mirror of
https://github.com/servo/servo.git
synced 2025-08-08 06:55:31 +01:00
First part of font refactoring. These changes simplify a few things
but don't do much on their own, they just make it easier to implement the work to come (web fonts, performance improvments in terms of font loading and memory usage). - Font identifier on Linux/Android is now the font file path. This is a temporary measure, but simplifies things a lot for now. - Remove FontListHandleMethods trait in favour of free functions. - FontList::refresh() has no knowledge of FontFamily etc. Instead it takes a closure that the caller provides. - FontList::load_variations_for_family no longer creates the font handle. Instead it takes a closure and provides the name of the font identifier for the variations it finds. - Remove path_from_identifier() - it's no longer required. - create_font_from_identifier() takes an Option<Style>, allowing it to be used to create fonts for family matching purposes where the font size is not important. Tested on Linux + Mac. Builds on Android but not able to confirm it's working correctly.
This commit is contained in:
parent
568e7ed0c6
commit
51bd334f3f
10 changed files with 237 additions and 492 deletions
|
@ -30,7 +30,7 @@ pub struct FontContextInfo {
|
|||
}
|
||||
|
||||
pub trait FontContextHandleMethods {
|
||||
fn create_font_from_identifier(&self, String, UsedFontStyle) -> Result<FontHandle, ()>;
|
||||
fn create_font_from_identifier(&self, &str, Option<&UsedFontStyle>) -> Result<FontHandle, ()>;
|
||||
}
|
||||
|
||||
pub struct FontContext {
|
||||
|
@ -128,7 +128,7 @@ impl FontContext {
|
|||
|
||||
let result = match self.font_list {
|
||||
Some(ref mut fl) => {
|
||||
let font_in_family = fl.find_font_in_family(&transformed_family_name, style);
|
||||
let font_in_family = fl.find_font_in_family(&self.handle, &transformed_family_name, style);
|
||||
match font_in_family {
|
||||
Some(font_entry) => {
|
||||
let font_id =
|
||||
|
@ -164,7 +164,7 @@ impl FontContext {
|
|||
let font_desc = match self.font_list {
|
||||
Some(ref mut font_list) => {
|
||||
let font_desc = {
|
||||
let font_entry = font_list.find_font_in_family(family, style);
|
||||
let font_entry = font_list.find_font_in_family(&self.handle, family, style);
|
||||
match font_entry {
|
||||
Some(v) => {
|
||||
let font_id =
|
||||
|
@ -207,8 +207,8 @@ impl FontContext {
|
|||
return match &desc.selector {
|
||||
// TODO(Issue #174): implement by-platform-name font selectors.
|
||||
&SelectorPlatformIdentifier(ref identifier) => {
|
||||
let result_handle = self.handle.create_font_from_identifier((*identifier).clone(),
|
||||
desc.style.clone());
|
||||
let result_handle = self.handle.create_font_from_identifier(identifier.as_slice(),
|
||||
Some(&desc.style));
|
||||
result_handle.and_then(|handle| {
|
||||
Ok(
|
||||
Rc::new(
|
||||
|
|
|
@ -4,10 +4,11 @@
|
|||
|
||||
use std::collections::hashmap::HashMap;
|
||||
use font::SpecifiedFontStyle;
|
||||
use font_context::FontContextHandleMethods;
|
||||
use gfx_font::FontHandleMethods;
|
||||
use platform::font::FontHandle;
|
||||
use platform::font_context::FontContextHandle;
|
||||
use platform::font_list::FontListHandle;
|
||||
use platform::font_list;
|
||||
use style::computed_values::{font_weight, font_style};
|
||||
|
||||
use servo_util::time::{TimeProfilerChan, profile};
|
||||
|
@ -15,16 +16,9 @@ use servo_util::time;
|
|||
|
||||
pub type FontFamilyMap = HashMap<String, FontFamily>;
|
||||
|
||||
trait FontListHandleMethods {
|
||||
fn get_available_families(&self, fctx: &FontContextHandle) -> FontFamilyMap;
|
||||
fn load_variations_for_family(&self, family: &mut FontFamily);
|
||||
fn get_last_resort_font_families() -> Vec<String>;
|
||||
}
|
||||
|
||||
/// The platform-independent font list abstraction.
|
||||
pub struct FontList {
|
||||
family_map: FontFamilyMap,
|
||||
handle: FontListHandle,
|
||||
time_profiler_chan: TimeProfilerChan,
|
||||
}
|
||||
|
||||
|
@ -32,9 +26,7 @@ impl FontList {
|
|||
pub fn new(fctx: &FontContextHandle,
|
||||
time_profiler_chan: TimeProfilerChan)
|
||||
-> FontList {
|
||||
let handle = FontListHandle::new(fctx);
|
||||
let mut list = FontList {
|
||||
handle: handle,
|
||||
family_map: HashMap::new(),
|
||||
time_profiler_chan: time_profiler_chan.clone(),
|
||||
};
|
||||
|
@ -48,11 +40,16 @@ impl FontList {
|
|||
//
|
||||
// Should font families with entries be invalidated/refreshed too?
|
||||
profile(time::GfxRegenAvailableFontsCategory, self.time_profiler_chan.clone(), || {
|
||||
self.family_map = self.handle.get_available_families();
|
||||
self.family_map.clear();
|
||||
font_list::get_available_families(|family_name| {
|
||||
debug!("Creating new FontFamily for family: {:s}", family_name);
|
||||
let new_family = FontFamily::new(family_name.as_slice());
|
||||
self.family_map.insert(family_name, new_family);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub fn find_font_in_family<'a>(&'a mut self,
|
||||
pub fn find_font_in_family<'a>(&'a mut self, fctx: &FontContextHandle,
|
||||
family_name: &String,
|
||||
style: &SpecifiedFontStyle) -> Option<&'a FontEntry> {
|
||||
// TODO(Issue #188): look up localized font family names if canonical name not found
|
||||
|
@ -63,7 +60,7 @@ impl FontList {
|
|||
let s: &'a mut FontFamily = self.family_map.get_mut(family_name);
|
||||
// TODO(Issue #192: handle generic font families, like 'serif' and 'sans-serif'.
|
||||
// if such family exists, try to match style to a font
|
||||
let result = s.find_font_for_style(&mut self.handle, style);
|
||||
let result = s.find_font_for_style(fctx, style);
|
||||
if result.is_some() {
|
||||
return result;
|
||||
}
|
||||
|
@ -76,7 +73,7 @@ impl FontList {
|
|||
}
|
||||
|
||||
pub fn get_last_resort_font_families() -> Vec<String> {
|
||||
FontListHandle::get_last_resort_font_families()
|
||||
font_list::get_last_resort_font_families()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,17 +91,24 @@ impl FontFamily {
|
|||
}
|
||||
}
|
||||
|
||||
fn load_family_variations(&mut self, list: &FontListHandle) {
|
||||
fn load_family_variations(&mut self, fctx: &FontContextHandle) {
|
||||
if self.entries.len() > 0 {
|
||||
return
|
||||
}
|
||||
list.load_variations_for_family(self);
|
||||
let mut entries = vec!();
|
||||
font_list::load_variations_for_family(self.family_name.as_slice(), |file_path| {
|
||||
let font_handle = fctx.create_font_from_identifier(file_path.as_slice(), None).unwrap();
|
||||
debug!("Creating new FontEntry for face: {:s}", font_handle.face_name());
|
||||
let entry = FontEntry::new(font_handle);
|
||||
entries.push(entry);
|
||||
});
|
||||
self.entries = entries;
|
||||
assert!(self.entries.len() > 0)
|
||||
}
|
||||
|
||||
pub fn find_font_for_style<'a>(&'a mut self, list: &FontListHandle, style: &SpecifiedFontStyle)
|
||||
pub fn find_font_for_style<'a>(&'a mut self, fctx: &FontContextHandle, style: &SpecifiedFontStyle)
|
||||
-> Option<&'a FontEntry> {
|
||||
self.load_family_variations(list);
|
||||
self.load_family_variations(fctx);
|
||||
|
||||
// TODO(Issue #189): optimize lookup for
|
||||
// regular/bold/italic/bolditalic with fixed offsets and a
|
||||
|
|
|
@ -118,9 +118,11 @@ impl FontHandleMethods for FontHandle {
|
|||
|
||||
// an identifier usable by FontContextHandle to recreate this FontHandle.
|
||||
fn face_identifier(&self) -> String {
|
||||
/* FT_Get_Postscript_Name seems like a better choice here, but it
|
||||
doesn't give usable results for fontconfig when deserializing. */
|
||||
unsafe { str::raw::from_c_str((*self.face).family_name) }
|
||||
match self.source {
|
||||
FontSourceFile(ref path) => path.clone(),
|
||||
_ => unreachable!(), // This will be handled when the rest of the font
|
||||
// refactor is complete. For now, it can never be hit.
|
||||
}
|
||||
}
|
||||
fn family_name(&self) -> String {
|
||||
unsafe { str::raw::from_c_str((*self.face).family_name) }
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
use font::UsedFontStyle;
|
||||
use platform::font::FontHandle;
|
||||
use font_context::FontContextHandleMethods;
|
||||
use platform::font_list::path_from_identifier;
|
||||
|
||||
use freetype::freetype::FTErrorMethods;
|
||||
use freetype::freetype::FT_Add_Default_Modules;
|
||||
|
@ -65,7 +64,7 @@ impl FontContextHandle {
|
|||
|
||||
let ptr = libc::malloc(mem::size_of::<struct_FT_MemoryRec_>() as size_t);
|
||||
let allocator: &mut struct_FT_MemoryRec_ = mem::transmute(ptr);
|
||||
mem::overwrite(allocator, struct_FT_MemoryRec_ {
|
||||
ptr::write(allocator, struct_FT_MemoryRec_ {
|
||||
user: ptr::null(),
|
||||
alloc: ft_alloc,
|
||||
free: ft_free,
|
||||
|
@ -87,13 +86,10 @@ impl FontContextHandle {
|
|||
}
|
||||
|
||||
impl FontContextHandleMethods for FontContextHandle {
|
||||
fn create_font_from_identifier(&self, name: String, style: UsedFontStyle)
|
||||
fn create_font_from_identifier(&self, name: &str, style: Option<&UsedFontStyle>)
|
||||
-> Result<FontHandle, ()> {
|
||||
debug!("Creating font handle for {:s}", name);
|
||||
path_from_identifier(name, &style).and_then(|file_name| {
|
||||
debug!("Opening font face {:s}", file_name);
|
||||
FontHandle::new_from_file(self, file_name.as_slice(), Some(&style))
|
||||
})
|
||||
FontHandle::new_from_file(self, name.as_slice(), style)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,43 +7,21 @@
|
|||
extern crate freetype;
|
||||
extern crate fontconfig;
|
||||
|
||||
use fontconfig::fontconfig::{
|
||||
FcChar8, FcResultMatch, FcSetSystem, FcPattern,
|
||||
FcResultNoMatch, FcMatchPattern, FC_SLANT_ITALIC, FC_WEIGHT_BOLD, FC_SLANT_OBLIQUE
|
||||
};
|
||||
use fontconfig::fontconfig::{FcChar8, FcResultMatch, FcSetSystem};
|
||||
use fontconfig::fontconfig::{
|
||||
FcConfigGetCurrent, FcConfigGetFonts, FcPatternGetString,
|
||||
FcPatternDestroy, FcFontSetDestroy, FcConfigSubstitute,
|
||||
FcDefaultSubstitute, FcPatternCreate, FcPatternAddString, FcPatternAddInteger,
|
||||
FcFontMatch, FcFontSetList, FcObjectSetCreate, FcObjectSetDestroy,
|
||||
FcPatternDestroy, FcFontSetDestroy,
|
||||
FcPatternCreate, FcPatternAddString,
|
||||
FcFontSetList, FcObjectSetCreate, FcObjectSetDestroy,
|
||||
FcObjectSetAdd, FcPatternGetInteger
|
||||
};
|
||||
|
||||
use style::computed_values::font_style;
|
||||
|
||||
|
||||
use font::{FontHandleMethods, UsedFontStyle};
|
||||
use font_list::{FontEntry, FontFamily, FontFamilyMap};
|
||||
use platform::font::FontHandle;
|
||||
use platform::font_context::FontContextHandle;
|
||||
|
||||
use std::collections::hashmap::HashMap;
|
||||
use libc;
|
||||
use libc::{c_int, c_char};
|
||||
use std::ptr;
|
||||
use std::str;
|
||||
|
||||
pub struct FontListHandle {
|
||||
pub fctx: FontContextHandle,
|
||||
}
|
||||
|
||||
impl FontListHandle {
|
||||
pub fn new(fctx: &FontContextHandle) -> FontListHandle {
|
||||
FontListHandle { fctx: fctx.clone() }
|
||||
}
|
||||
|
||||
pub fn get_available_families(&self) -> FontFamilyMap {
|
||||
let mut family_map : FontFamilyMap = HashMap::new();
|
||||
pub fn get_available_families(callback: |String|) {
|
||||
unsafe {
|
||||
let config = FcConfigGetCurrent();
|
||||
let fontSet = FcConfigGetFonts(config, FcSetSystem);
|
||||
|
@ -54,19 +32,16 @@ impl FontListHandle {
|
|||
"family".to_c_str().with_ref(|FC_FAMILY| {
|
||||
while FcPatternGetString(*font, FC_FAMILY, v, &family) == FcResultMatch {
|
||||
let family_name = str::raw::from_c_str(family as *c_char);
|
||||
debug!("Creating new FontFamily for family: {:s}", family_name);
|
||||
let new_family = FontFamily::new(family_name.as_slice());
|
||||
family_map.insert(family_name, new_family);
|
||||
callback(family_name);
|
||||
v += 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return family_map;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_variations_for_family(&self, family: &mut FontFamily) {
|
||||
debug!("getting variations for {:?}", family);
|
||||
pub fn load_variations_for_family(family_name: &str, callback: |String|) {
|
||||
debug!("getting variations for {}", family_name);
|
||||
unsafe {
|
||||
let config = FcConfigGetCurrent();
|
||||
let font_set = FcConfigGetFonts(config, FcSetSystem);
|
||||
|
@ -74,7 +49,7 @@ impl FontListHandle {
|
|||
let pattern = FcPatternCreate();
|
||||
assert!(pattern.is_not_null());
|
||||
"family".to_c_str().with_ref(|FC_FAMILY| {
|
||||
family.family_name.to_c_str().with_ref(|family_name| {
|
||||
family_name.to_c_str().with_ref(|family_name| {
|
||||
let ok = FcPatternAddString(pattern, FC_FAMILY, family_name as *FcChar8);
|
||||
assert!(ok != 0);
|
||||
});
|
||||
|
@ -116,106 +91,15 @@ impl FontListHandle {
|
|||
debug!("variation file: {}", file);
|
||||
debug!("variation index: {}", index);
|
||||
|
||||
let font_handle = FontHandle::new_from_file(&self.fctx,
|
||||
file.as_slice(), None);
|
||||
let font_handle = font_handle.unwrap();
|
||||
|
||||
debug!("Creating new FontEntry for face: {:s}", font_handle.face_name());
|
||||
let entry = FontEntry::new(font_handle);
|
||||
family.entries.push(entry);
|
||||
callback(file);
|
||||
}
|
||||
|
||||
FcFontSetDestroy(matches);
|
||||
FcPatternDestroy(pattern);
|
||||
FcObjectSetDestroy(object_set);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_last_resort_font_families() -> Vec<String> {
|
||||
pub fn get_last_resort_font_families() -> Vec<String> {
|
||||
vec!("Roboto".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
struct AutoPattern {
|
||||
pattern: *FcPattern
|
||||
}
|
||||
|
||||
impl Drop for AutoPattern {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
FcPatternDestroy(self.pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn path_from_identifier(name: String, style: &UsedFontStyle) -> Result<String, ()> {
|
||||
unsafe {
|
||||
let config = FcConfigGetCurrent();
|
||||
let wrapper = AutoPattern { pattern: FcPatternCreate() };
|
||||
let pattern = wrapper.pattern;
|
||||
let res = "family".to_c_str().with_ref(|FC_FAMILY| {
|
||||
name.to_c_str().with_ref(|family| {
|
||||
FcPatternAddString(pattern, FC_FAMILY, family as *FcChar8)
|
||||
})
|
||||
});
|
||||
if res != 1 {
|
||||
debug!("adding family to pattern failed");
|
||||
return Err(());
|
||||
}
|
||||
|
||||
match style.style {
|
||||
font_style::normal => (),
|
||||
font_style::italic => {
|
||||
let res = "slant".to_c_str().with_ref(|FC_SLANT| {
|
||||
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC)
|
||||
});
|
||||
if res != 1 {
|
||||
debug!("adding slant to pattern failed");
|
||||
return Err(());
|
||||
}
|
||||
},
|
||||
font_style::oblique => {
|
||||
let res = "slant".to_c_str().with_ref(|FC_SLANT| {
|
||||
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_OBLIQUE)
|
||||
});
|
||||
if res != 1 {
|
||||
debug!("adding slant(oblique) to pattern failed");
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if style.weight.is_bold() {
|
||||
let res = "weight".to_c_str().with_ref(|FC_WEIGHT| {
|
||||
FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD)
|
||||
});
|
||||
if res != 1 {
|
||||
debug!("adding weight to pattern failed");
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
|
||||
if FcConfigSubstitute(config, pattern, FcMatchPattern) != 1 {
|
||||
debug!("substitution failed");
|
||||
return Err(());
|
||||
}
|
||||
FcDefaultSubstitute(pattern);
|
||||
let result = FcResultNoMatch;
|
||||
let result_wrapper = AutoPattern { pattern: FcFontMatch(config, pattern, &result) };
|
||||
let result_pattern = result_wrapper.pattern;
|
||||
if result != FcResultMatch && result_pattern.is_null() {
|
||||
debug!("obtaining match to pattern failed");
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let file: *FcChar8 = ptr::null();
|
||||
let res = "file".to_c_str().with_ref(|FC_FILE| {
|
||||
FcPatternGetString(result_pattern, FC_FILE, 0, &file)
|
||||
});
|
||||
if res != FcResultMatch {
|
||||
debug!("getting filename for font failed");
|
||||
return Err(());
|
||||
}
|
||||
Ok(str::raw::from_c_str(file as *c_char))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,9 +118,11 @@ impl FontHandleMethods for FontHandle {
|
|||
|
||||
// an identifier usable by FontContextHandle to recreate this FontHandle.
|
||||
fn face_identifier(&self) -> String {
|
||||
/* FT_Get_Postscript_Name seems like a better choice here, but it
|
||||
doesn't give usable results for fontconfig when deserializing. */
|
||||
unsafe { str::raw::from_c_str((*self.face).family_name) }
|
||||
match self.source {
|
||||
FontSourceFile(ref path) => path.clone(),
|
||||
_ => unreachable!(), // This will be handled when the rest of the font
|
||||
// refactor is complete. For now, it can never be hit.
|
||||
}
|
||||
}
|
||||
fn family_name(&self) -> String {
|
||||
unsafe { str::raw::from_c_str((*self.face).family_name) }
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
use font::UsedFontStyle;
|
||||
use platform::font::FontHandle;
|
||||
use font_context::FontContextHandleMethods;
|
||||
use platform::font_list::path_from_identifier;
|
||||
|
||||
use freetype::freetype::FTErrorMethods;
|
||||
use freetype::freetype::FT_Add_Default_Modules;
|
||||
|
@ -65,7 +64,7 @@ impl FontContextHandle {
|
|||
|
||||
let ptr = libc::malloc(mem::size_of::<struct_FT_MemoryRec_>() as size_t);
|
||||
let allocator: &mut struct_FT_MemoryRec_ = mem::transmute(ptr);
|
||||
mem::overwrite(allocator, struct_FT_MemoryRec_ {
|
||||
ptr::write(allocator, struct_FT_MemoryRec_ {
|
||||
user: ptr::null(),
|
||||
alloc: ft_alloc,
|
||||
free: ft_free,
|
||||
|
@ -87,13 +86,10 @@ impl FontContextHandle {
|
|||
}
|
||||
|
||||
impl FontContextHandleMethods for FontContextHandle {
|
||||
fn create_font_from_identifier(&self, name: String, style: UsedFontStyle)
|
||||
fn create_font_from_identifier(&self, name: &str, style: Option<&UsedFontStyle>)
|
||||
-> Result<FontHandle, ()> {
|
||||
debug!("Creating font handle for {:s}", name);
|
||||
path_from_identifier(name, &style).and_then(|file_name| {
|
||||
debug!("Opening font face {:s}", file_name);
|
||||
FontHandle::new_from_file(self, file_name.as_slice(), Some(&style))
|
||||
})
|
||||
FontHandle::new_from_file(self, name.as_slice(), style)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,43 +7,21 @@
|
|||
extern crate freetype;
|
||||
extern crate fontconfig;
|
||||
|
||||
use fontconfig::fontconfig::{
|
||||
FcChar8, FcResultMatch, FcSetSystem, FcPattern,
|
||||
FcResultNoMatch, FcMatchPattern, FC_SLANT_ITALIC, FC_WEIGHT_BOLD, FC_SLANT_OBLIQUE
|
||||
};
|
||||
use fontconfig::fontconfig::{FcChar8, FcResultMatch, FcSetSystem};
|
||||
use fontconfig::fontconfig::{
|
||||
FcConfigGetCurrent, FcConfigGetFonts, FcPatternGetString,
|
||||
FcPatternDestroy, FcFontSetDestroy, FcConfigSubstitute,
|
||||
FcDefaultSubstitute, FcPatternCreate, FcPatternAddString, FcPatternAddInteger,
|
||||
FcFontMatch, FcFontSetList, FcObjectSetCreate, FcObjectSetDestroy,
|
||||
FcPatternDestroy, FcFontSetDestroy,
|
||||
FcPatternCreate, FcPatternAddString,
|
||||
FcFontSetList, FcObjectSetCreate, FcObjectSetDestroy,
|
||||
FcObjectSetAdd, FcPatternGetInteger
|
||||
};
|
||||
|
||||
use style::computed_values::font_style;
|
||||
|
||||
|
||||
use font::{FontHandleMethods, UsedFontStyle};
|
||||
use font_list::{FontEntry, FontFamily, FontFamilyMap};
|
||||
use platform::font::FontHandle;
|
||||
use platform::font_context::FontContextHandle;
|
||||
|
||||
use std::collections::hashmap::HashMap;
|
||||
use libc;
|
||||
use libc::{c_int, c_char};
|
||||
use std::ptr;
|
||||
use std::str;
|
||||
|
||||
pub struct FontListHandle {
|
||||
pub fctx: FontContextHandle,
|
||||
}
|
||||
|
||||
impl FontListHandle {
|
||||
pub fn new(fctx: &FontContextHandle) -> FontListHandle {
|
||||
FontListHandle { fctx: fctx.clone() }
|
||||
}
|
||||
|
||||
pub fn get_available_families(&self) -> FontFamilyMap {
|
||||
let mut family_map : FontFamilyMap = HashMap::new();
|
||||
pub fn get_available_families(callback: |String|) {
|
||||
unsafe {
|
||||
let config = FcConfigGetCurrent();
|
||||
let fontSet = FcConfigGetFonts(config, FcSetSystem);
|
||||
|
@ -54,19 +32,16 @@ impl FontListHandle {
|
|||
"family".to_c_str().with_ref(|FC_FAMILY| {
|
||||
while FcPatternGetString(*font, FC_FAMILY, v, &family) == FcResultMatch {
|
||||
let family_name = str::raw::from_c_str(family as *c_char);
|
||||
debug!("Creating new FontFamily for family: {:s}", family_name);
|
||||
let new_family = FontFamily::new(family_name.as_slice());
|
||||
family_map.insert(family_name, new_family);
|
||||
callback(family_name);
|
||||
v += 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return family_map;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_variations_for_family(&self, family: &mut FontFamily) {
|
||||
debug!("getting variations for {:?}", family);
|
||||
pub fn load_variations_for_family(family_name: &str, callback: |String|) {
|
||||
debug!("getting variations for {}", family_name);
|
||||
unsafe {
|
||||
let config = FcConfigGetCurrent();
|
||||
let font_set = FcConfigGetFonts(config, FcSetSystem);
|
||||
|
@ -74,7 +49,7 @@ impl FontListHandle {
|
|||
let pattern = FcPatternCreate();
|
||||
assert!(pattern.is_not_null());
|
||||
"family".to_c_str().with_ref(|FC_FAMILY| {
|
||||
family.family_name.to_c_str().with_ref(|family_name| {
|
||||
family_name.to_c_str().with_ref(|family_name| {
|
||||
let ok = FcPatternAddString(pattern, FC_FAMILY, family_name as *FcChar8);
|
||||
assert!(ok != 0);
|
||||
});
|
||||
|
@ -116,110 +91,19 @@ impl FontListHandle {
|
|||
debug!("variation file: {}", file);
|
||||
debug!("variation index: {}", index);
|
||||
|
||||
let font_handle = FontHandle::new_from_file(&self.fctx,
|
||||
file.as_slice(), None);
|
||||
let font_handle = font_handle.unwrap();
|
||||
|
||||
debug!("Creating new FontEntry for face: {:s}", font_handle.face_name());
|
||||
let entry = FontEntry::new(font_handle);
|
||||
family.entries.push(entry);
|
||||
callback(file);
|
||||
}
|
||||
|
||||
FcFontSetDestroy(matches);
|
||||
FcPatternDestroy(pattern);
|
||||
FcObjectSetDestroy(object_set);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_last_resort_font_families() -> Vec<String> {
|
||||
pub fn get_last_resort_font_families() -> Vec<String> {
|
||||
vec!(
|
||||
"Fira Sans".to_string(),
|
||||
"DejaVu Sans".to_string(),
|
||||
"Arial".to_string()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct AutoPattern {
|
||||
pattern: *FcPattern
|
||||
}
|
||||
|
||||
impl Drop for AutoPattern {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
FcPatternDestroy(self.pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn path_from_identifier(name: String, style: &UsedFontStyle) -> Result<String, ()> {
|
||||
unsafe {
|
||||
let config = FcConfigGetCurrent();
|
||||
let wrapper = AutoPattern { pattern: FcPatternCreate() };
|
||||
let pattern = wrapper.pattern;
|
||||
let res = "family".to_c_str().with_ref(|FC_FAMILY| {
|
||||
name.to_c_str().with_ref(|family| {
|
||||
FcPatternAddString(pattern, FC_FAMILY, family as *FcChar8)
|
||||
})
|
||||
});
|
||||
if res != 1 {
|
||||
debug!("adding family to pattern failed");
|
||||
return Err(());
|
||||
}
|
||||
|
||||
match style.style {
|
||||
font_style::normal => (),
|
||||
font_style::italic => {
|
||||
let res = "slant".to_c_str().with_ref(|FC_SLANT| {
|
||||
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC)
|
||||
});
|
||||
if res != 1 {
|
||||
debug!("adding slant to pattern failed");
|
||||
return Err(());
|
||||
}
|
||||
},
|
||||
font_style::oblique => {
|
||||
let res = "slant".to_c_str().with_ref(|FC_SLANT| {
|
||||
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_OBLIQUE)
|
||||
});
|
||||
if res != 1 {
|
||||
debug!("adding slant(oblique) to pattern failed");
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if style.weight.is_bold() {
|
||||
let res = "weight".to_c_str().with_ref(|FC_WEIGHT| {
|
||||
FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD)
|
||||
});
|
||||
if res != 1 {
|
||||
debug!("adding weight to pattern failed");
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
|
||||
if FcConfigSubstitute(config, pattern, FcMatchPattern) != 1 {
|
||||
debug!("substitution failed");
|
||||
return Err(());
|
||||
}
|
||||
FcDefaultSubstitute(pattern);
|
||||
let result = FcResultNoMatch;
|
||||
let result_wrapper = AutoPattern { pattern: FcFontMatch(config, pattern, &result) };
|
||||
let result_pattern = result_wrapper.pattern;
|
||||
if result != FcResultMatch && result_pattern.is_null() {
|
||||
debug!("obtaining match to pattern failed");
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let file: *FcChar8 = ptr::null();
|
||||
let res = "file".to_c_str().with_ref(|FC_FILE| {
|
||||
FcPatternGetString(result_pattern, FC_FILE, 0, &file)
|
||||
});
|
||||
if res != FcResultMatch {
|
||||
debug!("getting filename for font failed");
|
||||
return Err(());
|
||||
}
|
||||
Ok(str::raw::from_c_str(file as *c_char))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,10 +23,14 @@ impl FontContextHandle {
|
|||
|
||||
impl FontContextHandleMethods for FontContextHandle {
|
||||
fn create_font_from_identifier(&self,
|
||||
name: String,
|
||||
style: UsedFontStyle)
|
||||
name: &str,
|
||||
style: Option<&UsedFontStyle>)
|
||||
-> Result<FontHandle, ()> {
|
||||
let ctfont_result = core_text::font::new_from_name(name.as_slice(), style.pt_size);
|
||||
let pt_size = match style {
|
||||
Some(style) => style.pt_size,
|
||||
None => 0.0,
|
||||
};
|
||||
let ctfont_result = core_text::font::new_from_name(name.as_slice(), pt_size);
|
||||
ctfont_result.and_then(|ctfont| {
|
||||
FontHandle::new_from_CTFont(self, ctfont)
|
||||
})
|
||||
|
|
|
@ -2,63 +2,36 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use font::FontHandleMethods;
|
||||
use font_list::{FontEntry, FontFamily, FontFamilyMap};
|
||||
use platform::macos::font::FontHandle;
|
||||
use platform::macos::font_context::FontContextHandle;
|
||||
|
||||
use std::collections::hashmap::HashMap;
|
||||
use core_foundation::base::TCFType;
|
||||
use core_foundation::string::{CFString, CFStringRef};
|
||||
use core_text::font_descriptor::{CTFontDescriptor, CTFontDescriptorRef};
|
||||
use core_text;
|
||||
use std::mem;
|
||||
|
||||
pub struct FontListHandle {
|
||||
fctx: FontContextHandle,
|
||||
}
|
||||
|
||||
impl FontListHandle {
|
||||
pub fn new(fctx: &FontContextHandle) -> FontListHandle {
|
||||
FontListHandle {
|
||||
fctx: fctx.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_available_families(&self) -> FontFamilyMap {
|
||||
pub fn get_available_families(callback: |String|) {
|
||||
let family_names = core_text::font_collection::get_family_names();
|
||||
let mut family_map: FontFamilyMap = HashMap::new();
|
||||
for strref in family_names.iter() {
|
||||
let family_name_ref: CFStringRef = unsafe { mem::transmute(strref) };
|
||||
let family_name_cf: CFString = unsafe { TCFType::wrap_under_get_rule(family_name_ref) };
|
||||
let family_name = family_name_cf.to_str();
|
||||
debug!("Creating new FontFamily for family: {:s}", family_name);
|
||||
|
||||
let new_family = FontFamily::new(family_name.as_slice());
|
||||
family_map.insert(family_name, new_family);
|
||||
}
|
||||
family_map
|
||||
callback(family_name);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_variations_for_family(&self, family: &mut FontFamily) {
|
||||
debug!("Looking for faces of family: {:s}", family.family_name);
|
||||
pub fn load_variations_for_family(family_name: &str, callback: |String|) {
|
||||
debug!("Looking for faces of family: {:s}", family_name);
|
||||
|
||||
let family_collection =
|
||||
core_text::font_collection::create_for_family(family.family_name.as_slice());
|
||||
core_text::font_collection::create_for_family(family_name.as_slice());
|
||||
let family_descriptors = family_collection.get_descriptors();
|
||||
for descref in family_descriptors.iter() {
|
||||
let descref: CTFontDescriptorRef = unsafe { mem::transmute(descref) };
|
||||
let desc: CTFontDescriptor = unsafe { TCFType::wrap_under_get_rule(descref) };
|
||||
let font = core_text::font::new_from_descriptor(&desc, 0.0);
|
||||
let handle = FontHandle::new_from_CTFont(&self.fctx, font).unwrap();
|
||||
|
||||
debug!("Creating new FontEntry for face: {:s}", handle.face_name());
|
||||
let entry = FontEntry::new(handle);
|
||||
family.entries.push(entry)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_last_resort_font_families() -> Vec<String> {
|
||||
vec!("Arial Unicode MS".to_string(), "Arial".to_string())
|
||||
let postscript_name = desc.font_name();
|
||||
callback(postscript_name);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_last_resort_font_families() -> Vec<String> {
|
||||
vec!("Arial Unicode MS".to_string(), "Arial".to_string())
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue