mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
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:
commit
b0ffeaf53c
10 changed files with 237 additions and 492 deletions
|
@ -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(
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) }
|
||||||
|
|
|
@ -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))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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())
|
||||||
|
}
|
||||||
|
|
|
@ -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) }
|
||||||
|
|
|
@ -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))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -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)
|
||||||
})
|
})
|
||||||
|
|
|
@ -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())
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue