Merge pull request #2751 from glennw/font-refactor-1

First part of font refactoring. These changes simplify a few things
This commit is contained in:
Lars Bergstrom 2014-07-03 11:53:00 -05:00
commit b0ffeaf53c
10 changed files with 237 additions and 492 deletions

View file

@ -30,7 +30,7 @@ pub struct FontContextInfo {
} }
pub trait FontContextHandleMethods { 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 { pub struct FontContext {
@ -128,7 +128,7 @@ impl FontContext {
let result = match self.font_list { let result = match self.font_list {
Some(ref mut fl) => { 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 { match font_in_family {
Some(font_entry) => { Some(font_entry) => {
let font_id = let font_id =
@ -164,7 +164,7 @@ impl FontContext {
let font_desc = match self.font_list { let font_desc = match self.font_list {
Some(ref mut font_list) => { Some(ref mut font_list) => {
let font_desc = { 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 { match font_entry {
Some(v) => { Some(v) => {
let font_id = let font_id =
@ -207,8 +207,8 @@ impl FontContext {
return match &desc.selector { return match &desc.selector {
// TODO(Issue #174): implement by-platform-name font selectors. // TODO(Issue #174): implement by-platform-name font selectors.
&SelectorPlatformIdentifier(ref identifier) => { &SelectorPlatformIdentifier(ref identifier) => {
let result_handle = self.handle.create_font_from_identifier((*identifier).clone(), let result_handle = self.handle.create_font_from_identifier(identifier.as_slice(),
desc.style.clone()); Some(&desc.style));
result_handle.and_then(|handle| { result_handle.and_then(|handle| {
Ok( Ok(
Rc::new( Rc::new(

View file

@ -4,10 +4,11 @@
use std::collections::hashmap::HashMap; use std::collections::hashmap::HashMap;
use font::SpecifiedFontStyle; use font::SpecifiedFontStyle;
use font_context::FontContextHandleMethods;
use gfx_font::FontHandleMethods; use gfx_font::FontHandleMethods;
use platform::font::FontHandle; use platform::font::FontHandle;
use platform::font_context::FontContextHandle; use platform::font_context::FontContextHandle;
use platform::font_list::FontListHandle; use platform::font_list;
use style::computed_values::{font_weight, font_style}; use style::computed_values::{font_weight, font_style};
use servo_util::time::{TimeProfilerChan, profile}; use servo_util::time::{TimeProfilerChan, profile};
@ -15,16 +16,9 @@ use servo_util::time;
pub type FontFamilyMap = HashMap<String, FontFamily>; 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. /// The platform-independent font list abstraction.
pub struct FontList { pub struct FontList {
family_map: FontFamilyMap, family_map: FontFamilyMap,
handle: FontListHandle,
time_profiler_chan: TimeProfilerChan, time_profiler_chan: TimeProfilerChan,
} }
@ -32,9 +26,7 @@ impl FontList {
pub fn new(fctx: &FontContextHandle, pub fn new(fctx: &FontContextHandle,
time_profiler_chan: TimeProfilerChan) time_profiler_chan: TimeProfilerChan)
-> FontList { -> FontList {
let handle = FontListHandle::new(fctx);
let mut list = FontList { let mut list = FontList {
handle: handle,
family_map: HashMap::new(), family_map: HashMap::new(),
time_profiler_chan: time_profiler_chan.clone(), time_profiler_chan: time_profiler_chan.clone(),
}; };
@ -48,11 +40,16 @@ impl FontList {
// //
// Should font families with entries be invalidated/refreshed too? // Should font families with entries be invalidated/refreshed too?
profile(time::GfxRegenAvailableFontsCategory, self.time_profiler_chan.clone(), || { 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, family_name: &String,
style: &SpecifiedFontStyle) -> Option<&'a FontEntry> { style: &SpecifiedFontStyle) -> Option<&'a FontEntry> {
// TODO(Issue #188): look up localized font family names if canonical name not found // 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); let s: &'a mut FontFamily = self.family_map.get_mut(family_name);
// TODO(Issue #192: handle generic font families, like 'serif' and 'sans-serif'. // TODO(Issue #192: handle generic font families, like 'serif' and 'sans-serif'.
// if such family exists, try to match style to a font // 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() { if result.is_some() {
return result; return result;
} }
@ -76,7 +73,7 @@ impl FontList {
} }
pub fn get_last_resort_font_families() -> Vec<String> { 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 { if self.entries.len() > 0 {
return 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) 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> { -> Option<&'a FontEntry> {
self.load_family_variations(list); self.load_family_variations(fctx);
// TODO(Issue #189): optimize lookup for // TODO(Issue #189): optimize lookup for
// regular/bold/italic/bolditalic with fixed offsets and a // regular/bold/italic/bolditalic with fixed offsets and a

View file

@ -118,9 +118,11 @@ impl FontHandleMethods for FontHandle {
// an identifier usable by FontContextHandle to recreate this FontHandle. // an identifier usable by FontContextHandle to recreate this FontHandle.
fn face_identifier(&self) -> String { fn face_identifier(&self) -> String {
/* FT_Get_Postscript_Name seems like a better choice here, but it match self.source {
doesn't give usable results for fontconfig when deserializing. */ FontSourceFile(ref path) => path.clone(),
unsafe { str::raw::from_c_str((*self.face).family_name) } _ => 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 { fn family_name(&self) -> String {
unsafe { str::raw::from_c_str((*self.face).family_name) } unsafe { str::raw::from_c_str((*self.face).family_name) }

View file

@ -5,7 +5,6 @@
use font::UsedFontStyle; use font::UsedFontStyle;
use platform::font::FontHandle; use platform::font::FontHandle;
use font_context::FontContextHandleMethods; use font_context::FontContextHandleMethods;
use platform::font_list::path_from_identifier;
use freetype::freetype::FTErrorMethods; use freetype::freetype::FTErrorMethods;
use freetype::freetype::FT_Add_Default_Modules; 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 ptr = libc::malloc(mem::size_of::<struct_FT_MemoryRec_>() as size_t);
let allocator: &mut struct_FT_MemoryRec_ = mem::transmute(ptr); let allocator: &mut struct_FT_MemoryRec_ = mem::transmute(ptr);
mem::overwrite(allocator, struct_FT_MemoryRec_ { ptr::write(allocator, struct_FT_MemoryRec_ {
user: ptr::null(), user: ptr::null(),
alloc: ft_alloc, alloc: ft_alloc,
free: ft_free, free: ft_free,
@ -87,13 +86,10 @@ impl FontContextHandle {
} }
impl FontContextHandleMethods for 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, ()> { -> Result<FontHandle, ()> {
debug!("Creating font handle for {:s}", name); debug!("Creating font handle for {:s}", name);
path_from_identifier(name, &style).and_then(|file_name| { FontHandle::new_from_file(self, name.as_slice(), style)
debug!("Opening font face {:s}", file_name);
FontHandle::new_from_file(self, file_name.as_slice(), Some(&style))
})
} }
} }

View file

@ -7,215 +7,99 @@
extern crate freetype; extern crate freetype;
extern crate fontconfig; extern crate fontconfig;
use fontconfig::fontconfig::{ use fontconfig::fontconfig::{FcChar8, FcResultMatch, FcSetSystem};
FcChar8, FcResultMatch, FcSetSystem, FcPattern,
FcResultNoMatch, FcMatchPattern, FC_SLANT_ITALIC, FC_WEIGHT_BOLD, FC_SLANT_OBLIQUE
};
use fontconfig::fontconfig::{ use fontconfig::fontconfig::{
FcConfigGetCurrent, FcConfigGetFonts, FcPatternGetString, FcConfigGetCurrent, FcConfigGetFonts, FcPatternGetString,
FcPatternDestroy, FcFontSetDestroy, FcConfigSubstitute, FcPatternDestroy, FcFontSetDestroy,
FcDefaultSubstitute, FcPatternCreate, FcPatternAddString, FcPatternAddInteger, FcPatternCreate, FcPatternAddString,
FcFontMatch, FcFontSetList, FcObjectSetCreate, FcObjectSetDestroy, FcFontSetList, FcObjectSetCreate, FcObjectSetDestroy,
FcObjectSetAdd, FcPatternGetInteger 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;
use libc::{c_int, c_char}; use libc::{c_int, c_char};
use std::ptr; use std::ptr;
use std::str; use std::str;
pub struct FontListHandle { pub fn get_available_families(callback: |String|) {
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();
unsafe {
let config = FcConfigGetCurrent();
let fontSet = FcConfigGetFonts(config, FcSetSystem);
for i in range(0, (*fontSet).nfont as int) {
let font = (*fontSet).fonts.offset(i);
let family: *FcChar8 = ptr::null();
let mut v: c_int = 0;
"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);
v += 1;
}
});
}
}
return family_map;
}
pub fn load_variations_for_family(&self, family: &mut FontFamily) {
debug!("getting variations for {:?}", family);
unsafe {
let config = FcConfigGetCurrent();
let font_set = FcConfigGetFonts(config, FcSetSystem);
let font_set_array_ptr = &font_set;
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| {
let ok = FcPatternAddString(pattern, FC_FAMILY, family_name as *FcChar8);
assert!(ok != 0);
});
});
let object_set = FcObjectSetCreate();
assert!(object_set.is_not_null());
"file".to_c_str().with_ref(|FC_FILE| {
FcObjectSetAdd(object_set, FC_FILE);
});
"index".to_c_str().with_ref(|FC_INDEX| {
FcObjectSetAdd(object_set, FC_INDEX);
});
let matches = FcFontSetList(config, font_set_array_ptr, 1, pattern, object_set);
debug!("found {} variations", (*matches).nfont);
for i in range(0, (*matches).nfont as int) {
let font = (*matches).fonts.offset(i);
let file = "file".to_c_str().with_ref(|FC_FILE| {
let file: *FcChar8 = ptr::null();
if FcPatternGetString(*font, FC_FILE, 0, &file) == FcResultMatch {
str::raw::from_c_str(file as *libc::c_char)
} else {
fail!();
}
});
let index = "index".to_c_str().with_ref(|FC_INDEX| {
let index: libc::c_int = 0;
if FcPatternGetInteger(*font, FC_INDEX, 0, &index) == FcResultMatch {
index
} else {
fail!();
}
});
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);
}
FcFontSetDestroy(matches);
FcPatternDestroy(pattern);
FcObjectSetDestroy(object_set);
}
}
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 { unsafe {
let config = FcConfigGetCurrent(); let config = FcConfigGetCurrent();
let wrapper = AutoPattern { pattern: FcPatternCreate() }; let fontSet = FcConfigGetFonts(config, FcSetSystem);
let pattern = wrapper.pattern; for i in range(0, (*fontSet).nfont as int) {
let res = "family".to_c_str().with_ref(|FC_FAMILY| { let font = (*fontSet).fonts.offset(i);
name.to_c_str().with_ref(|family| { let family: *FcChar8 = ptr::null();
FcPatternAddString(pattern, FC_FAMILY, family as *FcChar8) let mut v: c_int = 0;
}) "family".to_c_str().with_ref(|FC_FAMILY| {
}); while FcPatternGetString(*font, FC_FAMILY, v, &family) == FcResultMatch {
if res != 1 { let family_name = str::raw::from_c_str(family as *c_char);
debug!("adding family to pattern failed"); callback(family_name);
return Err(()); v += 1;
}
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))
} }
} }
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);
let font_set_array_ptr = &font_set;
let pattern = FcPatternCreate();
assert!(pattern.is_not_null());
"family".to_c_str().with_ref(|FC_FAMILY| {
family_name.to_c_str().with_ref(|family_name| {
let ok = FcPatternAddString(pattern, FC_FAMILY, family_name as *FcChar8);
assert!(ok != 0);
});
});
let object_set = FcObjectSetCreate();
assert!(object_set.is_not_null());
"file".to_c_str().with_ref(|FC_FILE| {
FcObjectSetAdd(object_set, FC_FILE);
});
"index".to_c_str().with_ref(|FC_INDEX| {
FcObjectSetAdd(object_set, FC_INDEX);
});
let matches = FcFontSetList(config, font_set_array_ptr, 1, pattern, object_set);
debug!("found {} variations", (*matches).nfont);
for i in range(0, (*matches).nfont as int) {
let font = (*matches).fonts.offset(i);
let file = "file".to_c_str().with_ref(|FC_FILE| {
let file: *FcChar8 = ptr::null();
if FcPatternGetString(*font, FC_FILE, 0, &file) == FcResultMatch {
str::raw::from_c_str(file as *libc::c_char)
} else {
fail!();
}
});
let index = "index".to_c_str().with_ref(|FC_INDEX| {
let index: libc::c_int = 0;
if FcPatternGetInteger(*font, FC_INDEX, 0, &index) == FcResultMatch {
index
} else {
fail!();
}
});
debug!("variation file: {}", file);
debug!("variation index: {}", index);
callback(file);
}
FcFontSetDestroy(matches);
FcPatternDestroy(pattern);
FcObjectSetDestroy(object_set);
}
}
pub fn get_last_resort_font_families() -> Vec<String> {
vec!("Roboto".to_string())
}

View file

@ -118,9 +118,11 @@ impl FontHandleMethods for FontHandle {
// an identifier usable by FontContextHandle to recreate this FontHandle. // an identifier usable by FontContextHandle to recreate this FontHandle.
fn face_identifier(&self) -> String { fn face_identifier(&self) -> String {
/* FT_Get_Postscript_Name seems like a better choice here, but it match self.source {
doesn't give usable results for fontconfig when deserializing. */ FontSourceFile(ref path) => path.clone(),
unsafe { str::raw::from_c_str((*self.face).family_name) } _ => 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 { fn family_name(&self) -> String {
unsafe { str::raw::from_c_str((*self.face).family_name) } unsafe { str::raw::from_c_str((*self.face).family_name) }

View file

@ -5,7 +5,6 @@
use font::UsedFontStyle; use font::UsedFontStyle;
use platform::font::FontHandle; use platform::font::FontHandle;
use font_context::FontContextHandleMethods; use font_context::FontContextHandleMethods;
use platform::font_list::path_from_identifier;
use freetype::freetype::FTErrorMethods; use freetype::freetype::FTErrorMethods;
use freetype::freetype::FT_Add_Default_Modules; 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 ptr = libc::malloc(mem::size_of::<struct_FT_MemoryRec_>() as size_t);
let allocator: &mut struct_FT_MemoryRec_ = mem::transmute(ptr); let allocator: &mut struct_FT_MemoryRec_ = mem::transmute(ptr);
mem::overwrite(allocator, struct_FT_MemoryRec_ { ptr::write(allocator, struct_FT_MemoryRec_ {
user: ptr::null(), user: ptr::null(),
alloc: ft_alloc, alloc: ft_alloc,
free: ft_free, free: ft_free,
@ -87,13 +86,10 @@ impl FontContextHandle {
} }
impl FontContextHandleMethods for 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, ()> { -> Result<FontHandle, ()> {
debug!("Creating font handle for {:s}", name); debug!("Creating font handle for {:s}", name);
path_from_identifier(name, &style).and_then(|file_name| { FontHandle::new_from_file(self, name.as_slice(), style)
debug!("Opening font face {:s}", file_name);
FontHandle::new_from_file(self, file_name.as_slice(), Some(&style))
})
} }
} }

View file

@ -7,219 +7,103 @@
extern crate freetype; extern crate freetype;
extern crate fontconfig; extern crate fontconfig;
use fontconfig::fontconfig::{ use fontconfig::fontconfig::{FcChar8, FcResultMatch, FcSetSystem};
FcChar8, FcResultMatch, FcSetSystem, FcPattern,
FcResultNoMatch, FcMatchPattern, FC_SLANT_ITALIC, FC_WEIGHT_BOLD, FC_SLANT_OBLIQUE
};
use fontconfig::fontconfig::{ use fontconfig::fontconfig::{
FcConfigGetCurrent, FcConfigGetFonts, FcPatternGetString, FcConfigGetCurrent, FcConfigGetFonts, FcPatternGetString,
FcPatternDestroy, FcFontSetDestroy, FcConfigSubstitute, FcPatternDestroy, FcFontSetDestroy,
FcDefaultSubstitute, FcPatternCreate, FcPatternAddString, FcPatternAddInteger, FcPatternCreate, FcPatternAddString,
FcFontMatch, FcFontSetList, FcObjectSetCreate, FcObjectSetDestroy, FcFontSetList, FcObjectSetCreate, FcObjectSetDestroy,
FcObjectSetAdd, FcPatternGetInteger 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;
use libc::{c_int, c_char}; use libc::{c_int, c_char};
use std::ptr; use std::ptr;
use std::str; use std::str;
pub struct FontListHandle { pub fn get_available_families(callback: |String|) {
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();
unsafe {
let config = FcConfigGetCurrent();
let fontSet = FcConfigGetFonts(config, FcSetSystem);
for i in range(0, (*fontSet).nfont as int) {
let font = (*fontSet).fonts.offset(i);
let family: *FcChar8 = ptr::null();
let mut v: c_int = 0;
"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);
v += 1;
}
});
}
}
return family_map;
}
pub fn load_variations_for_family(&self, family: &mut FontFamily) {
debug!("getting variations for {:?}", family);
unsafe {
let config = FcConfigGetCurrent();
let font_set = FcConfigGetFonts(config, FcSetSystem);
let font_set_array_ptr = &font_set;
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| {
let ok = FcPatternAddString(pattern, FC_FAMILY, family_name as *FcChar8);
assert!(ok != 0);
});
});
let object_set = FcObjectSetCreate();
assert!(object_set.is_not_null());
"file".to_c_str().with_ref(|FC_FILE| {
FcObjectSetAdd(object_set, FC_FILE);
});
"index".to_c_str().with_ref(|FC_INDEX| {
FcObjectSetAdd(object_set, FC_INDEX);
});
let matches = FcFontSetList(config, font_set_array_ptr, 1, pattern, object_set);
debug!("found {} variations", (*matches).nfont);
for i in range(0, (*matches).nfont as int) {
let font = (*matches).fonts.offset(i);
let file = "file".to_c_str().with_ref(|FC_FILE| {
let file: *FcChar8 = ptr::null();
if FcPatternGetString(*font, FC_FILE, 0, &file) == FcResultMatch {
str::raw::from_c_str(file as *libc::c_char)
} else {
fail!();
}
});
let index = "index".to_c_str().with_ref(|FC_INDEX| {
let index: libc::c_int = 0;
if FcPatternGetInteger(*font, FC_INDEX, 0, &index) == FcResultMatch {
index
} else {
fail!();
}
});
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);
}
FcFontSetDestroy(matches);
FcPatternDestroy(pattern);
FcObjectSetDestroy(object_set);
}
}
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 { unsafe {
let config = FcConfigGetCurrent(); let config = FcConfigGetCurrent();
let wrapper = AutoPattern { pattern: FcPatternCreate() }; let fontSet = FcConfigGetFonts(config, FcSetSystem);
let pattern = wrapper.pattern; for i in range(0, (*fontSet).nfont as int) {
let res = "family".to_c_str().with_ref(|FC_FAMILY| { let font = (*fontSet).fonts.offset(i);
name.to_c_str().with_ref(|family| { let family: *FcChar8 = ptr::null();
FcPatternAddString(pattern, FC_FAMILY, family as *FcChar8) let mut v: c_int = 0;
}) "family".to_c_str().with_ref(|FC_FAMILY| {
}); while FcPatternGetString(*font, FC_FAMILY, v, &family) == FcResultMatch {
if res != 1 { let family_name = str::raw::from_c_str(family as *c_char);
debug!("adding family to pattern failed"); callback(family_name);
return Err(()); v += 1;
}
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))
} }
} }
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);
let font_set_array_ptr = &font_set;
let pattern = FcPatternCreate();
assert!(pattern.is_not_null());
"family".to_c_str().with_ref(|FC_FAMILY| {
family_name.to_c_str().with_ref(|family_name| {
let ok = FcPatternAddString(pattern, FC_FAMILY, family_name as *FcChar8);
assert!(ok != 0);
});
});
let object_set = FcObjectSetCreate();
assert!(object_set.is_not_null());
"file".to_c_str().with_ref(|FC_FILE| {
FcObjectSetAdd(object_set, FC_FILE);
});
"index".to_c_str().with_ref(|FC_INDEX| {
FcObjectSetAdd(object_set, FC_INDEX);
});
let matches = FcFontSetList(config, font_set_array_ptr, 1, pattern, object_set);
debug!("found {} variations", (*matches).nfont);
for i in range(0, (*matches).nfont as int) {
let font = (*matches).fonts.offset(i);
let file = "file".to_c_str().with_ref(|FC_FILE| {
let file: *FcChar8 = ptr::null();
if FcPatternGetString(*font, FC_FILE, 0, &file) == FcResultMatch {
str::raw::from_c_str(file as *libc::c_char)
} else {
fail!();
}
});
let index = "index".to_c_str().with_ref(|FC_INDEX| {
let index: libc::c_int = 0;
if FcPatternGetInteger(*font, FC_INDEX, 0, &index) == FcResultMatch {
index
} else {
fail!();
}
});
debug!("variation file: {}", file);
debug!("variation index: {}", index);
callback(file);
}
FcFontSetDestroy(matches);
FcPatternDestroy(pattern);
FcObjectSetDestroy(object_set);
}
}
pub fn get_last_resort_font_families() -> Vec<String> {
vec!(
"Fira Sans".to_string(),
"DejaVu Sans".to_string(),
"Arial".to_string()
)
}

View file

@ -23,10 +23,14 @@ impl FontContextHandle {
impl FontContextHandleMethods for FontContextHandle { impl FontContextHandleMethods for FontContextHandle {
fn create_font_from_identifier(&self, fn create_font_from_identifier(&self,
name: String, name: &str,
style: UsedFontStyle) style: Option<&UsedFontStyle>)
-> Result<FontHandle, ()> { -> 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| { ctfont_result.and_then(|ctfont| {
FontHandle::new_from_CTFont(self, ctfont) FontHandle::new_from_CTFont(self, ctfont)
}) })

View file

@ -2,63 +2,36 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * 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::base::TCFType;
use core_foundation::string::{CFString, CFStringRef}; use core_foundation::string::{CFString, CFStringRef};
use core_text::font_descriptor::{CTFontDescriptor, CTFontDescriptorRef}; use core_text::font_descriptor::{CTFontDescriptor, CTFontDescriptorRef};
use core_text; use core_text;
use std::mem; use std::mem;
pub struct FontListHandle { pub fn get_available_families(callback: |String|) {
fctx: FontContextHandle, let family_names = core_text::font_collection::get_family_names();
} for strref in family_names.iter() {
let family_name_ref: CFStringRef = unsafe { mem::transmute(strref) };
impl FontListHandle { let family_name_cf: CFString = unsafe { TCFType::wrap_under_get_rule(family_name_ref) };
pub fn new(fctx: &FontContextHandle) -> FontListHandle { let family_name = family_name_cf.to_str();
FontListHandle { callback(family_name);
fctx: fctx.clone()
}
}
pub fn get_available_families(&self) -> FontFamilyMap {
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
}
pub fn load_variations_for_family(&self, family: &mut FontFamily) {
debug!("Looking for faces of family: {:s}", family.family_name);
let family_collection =
core_text::font_collection::create_for_family(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())
} }
} }
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_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 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())
}