Format gfx platform #21373

This commit is contained in:
kingdido999 2018-09-05 08:39:05 +08:00
parent 5063ac465b
commit c57c99d9f7
13 changed files with 496 additions and 372 deletions

View file

@ -116,21 +116,18 @@ struct FontFamily {
struct FontAlias { struct FontAlias {
from: String, from: String,
to: String, to: String,
weight: Option<i32> weight: Option<i32>,
} }
struct FontList { struct FontList {
families: Vec<FontFamily>, families: Vec<FontFamily>,
aliases: Vec<FontAlias> aliases: Vec<FontAlias>,
} }
impl FontList { impl FontList {
fn new() -> FontList { fn new() -> FontList {
// Possible paths containing the font mapping xml file. // Possible paths containing the font mapping xml file.
let paths = [ let paths = ["/etc/fonts.xml", "/system/etc/system_fonts.xml"];
"/etc/fonts.xml",
"/system/etc/system_fonts.xml"
];
// Try to load and parse paths until one of them success. // Try to load and parse paths until one of them success.
let mut result = None; let mut result = None;
@ -146,7 +143,7 @@ impl FontList {
None => FontList { None => FontList {
families: Self::fallback_font_families(), families: Self::fallback_font_families(),
aliases: Vec::new(), aliases: Vec::new(),
} },
} }
} }
@ -154,25 +151,26 @@ impl FontList {
fn from_path(path: &str) -> Option<FontList> { fn from_path(path: &str) -> Option<FontList> {
let xml = match Self::load_file(path) { let xml = match Self::load_file(path) {
Ok(xml) => xml, Ok(xml) => xml,
_=> { return None; }, _ => {
return None;
},
}; };
let dom: RcDom = parse_document(RcDom::default(), Default::default()) let dom: RcDom = parse_document(RcDom::default(), Default::default()).one(xml);
.one(xml);
let doc = &dom.document; let doc = &dom.document;
// find familyset root node // find familyset root node
let children = doc.children.borrow(); let children = doc.children.borrow();
let familyset = children.iter().find(|child| { let familyset = children.iter().find(|child| match child.data {
match child.data {
NodeData::Element { ref name, .. } => &*name.local == "familyset", NodeData::Element { ref name, .. } => &*name.local == "familyset",
_ => false, _ => false,
}
}); });
let familyset = match familyset { let familyset = match familyset {
Some(node) => node, Some(node) => node,
_ => { return None; } _ => {
return None;
},
}; };
// Parse familyset node // Parse familyset node
@ -181,7 +179,11 @@ impl FontList {
for node in familyset.children.borrow().iter() { for node in familyset.children.borrow().iter() {
match node.data { match node.data {
NodeData::Element { ref name, ref attrs, .. } => { NodeData::Element {
ref name,
ref attrs,
..
} => {
if &*name.local == "family" { if &*name.local == "family" {
Self::parse_family(&node, attrs, &mut families); Self::parse_family(&node, attrs, &mut families);
} else if &*name.local == "alias" { } else if &*name.local == "alias" {
@ -191,13 +193,13 @@ impl FontList {
} }
} }
}, },
_=> {} _ => {},
} }
} }
Some(FontList { Some(FontList {
families: families, families: families,
aliases: aliases aliases: aliases,
}) })
} }
@ -209,16 +211,15 @@ impl FontList {
("Droid Sans", "DroidSans.ttf"), ("Droid Sans", "DroidSans.ttf"),
]; ];
alternatives.iter().filter(|item| { alternatives
Path::new(&Self::font_absolute_path(item.1)).exists() .iter()
}).map(|item| { .filter(|item| Path::new(&Self::font_absolute_path(item.1)).exists())
FontFamily { .map(|item| FontFamily {
name: item.0.into(), name: item.0.into(),
fonts: vec![Font { fonts: vec![Font {
filename: item.1.into(), filename: item.1.into(),
weight: None, weight: None,
}] }],
}
}).collect() }).collect()
} }
@ -235,7 +236,6 @@ impl FontList {
self.aliases.iter().find(|f| f.from == name) self.aliases.iter().find(|f| f.from == name)
} }
fn load_file(path: &str) -> Result<String, io::Error> { fn load_file(path: &str) -> Result<String, io::Error> {
let mut file = File::open(path)?; let mut file = File::open(path)?;
let mut content = String::new(); let mut content = String::new();
@ -255,11 +255,13 @@ impl FontList {
// </family> // </family>
fn parse_family(familyset: &Node, attrs: &RefCell<Vec<Attribute>>, out: &mut Vec<FontFamily>) { fn parse_family(familyset: &Node, attrs: &RefCell<Vec<Attribute>>, out: &mut Vec<FontFamily>) {
// Fallback to old Android API v17 xml format if required // Fallback to old Android API v17 xml format if required
let using_api_17 = familyset.children.borrow().iter().any(|node| { let using_api_17 = familyset
match node.data { .children
.borrow()
.iter()
.any(|node| match node.data {
NodeData::Element { ref name, .. } => &*name.local == "nameset", NodeData::Element { ref name, .. } => &*name.local == "nameset",
_ => false, _ => false,
}
}); });
if using_api_17 { if using_api_17 {
Self::parse_family_v17(familyset, out); Self::parse_family_v17(familyset, out);
@ -269,25 +271,31 @@ impl FontList {
// Parse family name // Parse family name
let name = match Self::find_attrib("name", attrs) { let name = match Self::find_attrib("name", attrs) {
Some(name) => name, Some(name) => name,
_ => { return; }, _ => {
return;
},
}; };
let mut fonts = Vec::new(); let mut fonts = Vec::new();
// Parse font variants // Parse font variants
for node in familyset.children.borrow().iter() { for node in familyset.children.borrow().iter() {
match node.data { match node.data {
NodeData::Element { ref name, ref attrs, .. } => { NodeData::Element {
ref name,
ref attrs,
..
} => {
if &*name.local == "font" { if &*name.local == "font" {
FontList::parse_font(&node, attrs, &mut fonts); FontList::parse_font(&node, attrs, &mut fonts);
} }
}, },
_=> {} _ => {},
} }
} }
out.push(FontFamily { out.push(FontFamily {
name: name, name: name,
fonts: fonts fonts: fonts,
}); });
} }
@ -320,13 +328,15 @@ impl FontList {
Self::collect_contents_with_tag(node, "file", &mut fileset); Self::collect_contents_with_tag(node, "file", &mut fileset);
} }
}, },
_=> {} _ => {},
} }
} }
// Create a families for each variation // Create a families for each variation
for name in nameset { for name in nameset {
let fonts: Vec<Font> = fileset.iter().map(|f| Font { let fonts: Vec<Font> = fileset
.iter()
.map(|f| Font {
filename: f.clone(), filename: f.clone(),
weight: None, weight: None,
}).collect(); }).collect();
@ -334,7 +344,7 @@ impl FontList {
if !fonts.is_empty() { if !fonts.is_empty() {
out.push(FontFamily { out.push(FontFamily {
name: name, name: name,
fonts: fonts fonts: fonts,
}) })
} }
} }
@ -346,7 +356,9 @@ impl FontList {
// Parse font filename // Parse font filename
let filename = match Self::text_content(node) { let filename = match Self::text_content(node) {
Some(filename) => filename, Some(filename) => filename,
_ => { return; } _ => {
return;
},
}; };
// Parse font weight // Parse font weight
@ -371,13 +383,17 @@ impl FontList {
// Parse alias name and referenced font // Parse alias name and referenced font
let from = match Self::find_attrib("name", attrs) { let from = match Self::find_attrib("name", attrs) {
Some(from) => from, Some(from) => from,
_ => { return; }, _ => {
return;
},
}; };
// Parse referenced font // Parse referenced font
let to = match Self::find_attrib("to", attrs) { let to = match Self::find_attrib("to", attrs) {
Some(to) => to, Some(to) => to,
_ => { return; }, _ => {
return;
},
}; };
// Parse optional weight filter // Parse optional weight filter
@ -391,19 +407,24 @@ impl FontList {
} }
fn find_attrib(name: &str, attrs: &RefCell<Vec<Attribute>>) -> Option<String> { fn find_attrib(name: &str, attrs: &RefCell<Vec<Attribute>>) -> Option<String> {
attrs.borrow().iter().find(|attr| &*attr.name.local == name).map(|s| String::from(&s.value)) attrs
.borrow()
.iter()
.find(|attr| &*attr.name.local == name)
.map(|s| String::from(&s.value))
} }
fn text_content(node: &Node) -> Option<String> { fn text_content(node: &Node) -> Option<String> {
node.children.borrow().get(0).and_then(|child| { node.children
match child.data { .borrow()
.get(0)
.and_then(|child| match child.data {
NodeData::Text { ref contents } => { NodeData::Text { ref contents } => {
let mut result = String::new(); let mut result = String::new();
result.push_str(&contents.borrow()); result.push_str(&contents.borrow());
Some(result) Some(result)
}, },
_ => None _ => None,
}
}) })
} }
@ -417,14 +438,17 @@ impl FontList {
} }
} }
}, },
_=> {} _ => {},
} }
} }
} }
} }
// Functions used by FontCacheThread // Functions used by FontCacheThread
pub fn for_each_available_family<F>(mut callback: F) where F: FnMut(String) { pub fn for_each_available_family<F>(mut callback: F)
where
F: FnMut(String),
{
for family in &FONT_LIST.families { for family in &FONT_LIST.families {
callback(family.name.clone()); callback(family.name.clone());
} }
@ -434,7 +458,8 @@ pub fn for_each_available_family<F>(mut callback: F) where F: FnMut(String) {
} }
pub fn for_each_variation<F>(family_name: &str, mut callback: F) pub fn for_each_variation<F>(family_name: &str, mut callback: F)
where F: FnMut(String) where
F: FnMut(String),
{ {
if let Some(family) = FONT_LIST.find_family(family_name) { if let Some(family) = FONT_LIST.find_family(family_name) {
for font in &family.fonts { for font in &family.fonts {
@ -453,7 +478,7 @@ pub fn for_each_variation<F>(family_name: &str, mut callback: F)
callback(FontList::font_absolute_path(&font.filename)) callback(FontList::font_absolute_path(&font.filename))
} }
}, },
_ => {} _ => {},
} }
} }
} }
@ -473,46 +498,44 @@ pub fn system_default_family(generic_name: &str) -> Option<String> {
// Based on gfxAndroidPlatform::GetCommonFallbackFonts() in Gecko // Based on gfxAndroidPlatform::GetCommonFallbackFonts() in Gecko
pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> { pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
let mut families = vec!(); let mut families = vec![];
if let Some(block) = codepoint.and_then(|c| c.block()) { if let Some(block) = codepoint.and_then(|c| c.block()) {
match block { match block {
UnicodeBlock::Armenian => { UnicodeBlock::Armenian => {
families.push("Droid Sans Armenian"); families.push("Droid Sans Armenian");
} },
UnicodeBlock::Hebrew => { UnicodeBlock::Hebrew => {
families.push("Droid Sans Hebrew"); families.push("Droid Sans Hebrew");
} },
UnicodeBlock::Arabic => { UnicodeBlock::Arabic => {
families.push("Droid Sans Arabic"); families.push("Droid Sans Arabic");
} },
UnicodeBlock::Devanagari => { UnicodeBlock::Devanagari => {
families.push("Noto Sans Devanagari"); families.push("Noto Sans Devanagari");
families.push("Droid Sans Devanagari"); families.push("Droid Sans Devanagari");
} },
UnicodeBlock::Tamil => { UnicodeBlock::Tamil => {
families.push("Noto Sans Tamil"); families.push("Noto Sans Tamil");
families.push("Droid Sans Tamil"); families.push("Droid Sans Tamil");
} },
UnicodeBlock::Thai => { UnicodeBlock::Thai => {
families.push("Noto Sans Thai"); families.push("Noto Sans Thai");
families.push("Droid Sans Thai"); families.push("Droid Sans Thai");
} },
UnicodeBlock::Georgian | UnicodeBlock::Georgian | UnicodeBlock::GeorgianSupplement => {
UnicodeBlock::GeorgianSupplement => {
families.push("Droid Sans Georgian"); families.push("Droid Sans Georgian");
} },
UnicodeBlock::Ethiopic | UnicodeBlock::Ethiopic | UnicodeBlock::EthiopicSupplement => {
UnicodeBlock::EthiopicSupplement => {
families.push("Droid Sans Ethiopic"); families.push("Droid Sans Ethiopic");
} },
_ => { _ => {
if is_cjk(codepoint.unwrap()) { if is_cjk(codepoint.unwrap()) {
@ -520,7 +543,7 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
families.push("Noto Sans CJK JP"); families.push("Noto Sans CJK JP");
families.push("Droid Sans Japanese"); families.push("Droid Sans Japanese");
} }
} },
} }
} }

View file

@ -98,14 +98,21 @@ fn create_face(
let face_index = 0 as FT_Long; let face_index = 0 as FT_Long;
let result = if let Some(ref bytes) = template.bytes { let result = if let Some(ref bytes) = template.bytes {
FT_New_Memory_Face(lib, bytes.as_ptr(), bytes.len() as FT_Long, face_index, &mut face) FT_New_Memory_Face(
lib,
bytes.as_ptr(),
bytes.len() as FT_Long,
face_index,
&mut face,
)
} else { } else {
// This will trigger a synchronous file read in the layout thread, which we may want to // This will trigger a synchronous file read in the layout thread, which we may want to
// revisit at some point. See discussion here: // revisit at some point. See discussion here:
// //
// https://github.com/servo/servo/pull/20506#issuecomment-378838800 // https://github.com/servo/servo/pull/20506#issuecomment-378838800
let filename = CString::new(&*template.identifier).expect("filename contains NUL byte!"); let filename =
CString::new(&*template.identifier).expect("filename contains NUL byte!");
FT_New_Face(lib, filename.as_ptr(), face_index, &mut face) FT_New_Face(lib, filename.as_ptr(), face_index, &mut face)
}; };
@ -122,12 +129,15 @@ fn create_face(
} }
impl FontHandleMethods for FontHandle { impl FontHandleMethods for FontHandle {
fn new_from_template(fctx: &FontContextHandle, fn new_from_template(
fctx: &FontContextHandle,
template: Arc<FontTemplateData>, template: Arc<FontTemplateData>,
pt_size: Option<Au>) pt_size: Option<Au>,
-> Result<FontHandle, ()> { ) -> Result<FontHandle, ()> {
let ft_ctx: FT_Library = fctx.ctx.ctx; let ft_ctx: FT_Library = fctx.ctx.ctx;
if ft_ctx.is_null() { return Err(()); } if ft_ctx.is_null() {
return Err(());
}
let face = create_face(ft_ctx, &template, pt_size)?; let face = create_face(ft_ctx, &template, pt_size)?;
@ -138,9 +148,8 @@ impl FontHandleMethods for FontHandle {
can_do_fast_shaping: false, can_do_fast_shaping: false,
}; };
// TODO (#11310): Implement basic support for GPOS and GSUB. // TODO (#11310): Implement basic support for GPOS and GSUB.
handle.can_do_fast_shaping = handle.has_table(KERN) && handle.can_do_fast_shaping =
!handle.has_table(GPOS) && handle.has_table(KERN) && !handle.has_table(GPOS) && !handle.has_table(GSUB);
!handle.has_table(GSUB);
Ok(handle) Ok(handle)
} }
@ -203,7 +212,7 @@ impl FontHandleMethods for FontHandle {
7 => FontStretchKeyword::Expanded, 7 => FontStretchKeyword::Expanded,
8 => FontStretchKeyword::ExtraExpanded, 8 => FontStretchKeyword::ExtraExpanded,
9 => FontStretchKeyword::UltraExpanded, 9 => FontStretchKeyword::UltraExpanded,
_ => FontStretchKeyword::Normal _ => FontStretchKeyword::Normal,
} }
} else { } else {
FontStretchKeyword::Normal FontStretchKeyword::Normal
@ -218,20 +227,26 @@ impl FontHandleMethods for FontHandle {
if idx != 0 as FT_UInt { if idx != 0 as FT_UInt {
Some(idx as GlyphId) Some(idx as GlyphId)
} else { } else {
debug!("Invalid codepoint: U+{:04X} ('{}')", codepoint as u32, codepoint); debug!(
"Invalid codepoint: U+{:04X} ('{}')",
codepoint as u32, codepoint
);
None None
} }
} }
} }
fn glyph_h_kerning(&self, first_glyph: GlyphId, second_glyph: GlyphId) fn glyph_h_kerning(&self, first_glyph: GlyphId, second_glyph: GlyphId) -> FractionalPixel {
-> FractionalPixel {
assert!(!self.face.is_null()); assert!(!self.face.is_null());
let mut delta = FT_Vector { x: 0, y: 0 }; let mut delta = FT_Vector { x: 0, y: 0 };
unsafe { unsafe {
FT_Get_Kerning(self.face, first_glyph, second_glyph, FT_Get_Kerning(
self.face,
first_glyph,
second_glyph,
FT_Kerning_Mode::FT_KERNING_DEFAULT as FT_UInt, FT_Kerning_Mode::FT_KERNING_DEFAULT as FT_UInt,
&mut delta); &mut delta,
);
} }
fixed_to_float_ft(delta.x as i32) fixed_to_float_ft(delta.x as i32)
} }
@ -243,9 +258,7 @@ impl FontHandleMethods for FontHandle {
fn glyph_h_advance(&self, glyph: GlyphId) -> Option<FractionalPixel> { fn glyph_h_advance(&self, glyph: GlyphId) -> Option<FractionalPixel> {
assert!(!self.face.is_null()); assert!(!self.face.is_null());
unsafe { unsafe {
let res = FT_Load_Glyph(self.face, let res = FT_Load_Glyph(self.face, glyph as FT_UInt, GLYPH_LOAD_FLAGS);
glyph as FT_UInt,
GLYPH_LOAD_FLAGS);
if succeeded(res) { if succeeded(res) {
let void_glyph = (*self.face).glyph; let void_glyph = (*self.face).glyph;
let slot: FT_GlyphSlot = mem::transmute(void_glyph); let slot: FT_GlyphSlot = mem::transmute(void_glyph);
@ -291,7 +304,8 @@ impl FontHandleMethods for FontHandle {
x_height = self.font_units_to_au(os2.sx_height as f64); x_height = self.font_units_to_au(os2.sx_height as f64);
} }
let average_advance = self.glyph_index('0') let average_advance = self
.glyph_index('0')
.and_then(|idx| self.glyph_h_advance(idx)) .and_then(|idx| self.glyph_h_advance(idx))
.map_or(max_advance, |advance| self.font_units_to_au(advance)); .map_or(max_advance, |advance| self.font_units_to_au(advance));
@ -320,13 +334,25 @@ impl FontHandleMethods for FontHandle {
unsafe { unsafe {
// Get the length // Get the length
let mut len = 0; let mut len = 0;
if !succeeded(FT_Load_Sfnt_Table(self.face, tag, 0, ptr::null_mut(), &mut len)) { if !succeeded(FT_Load_Sfnt_Table(
return None self.face,
tag,
0,
ptr::null_mut(),
&mut len,
)) {
return None;
} }
// Get the bytes // Get the bytes
let mut buf = vec![0u8; len as usize]; let mut buf = vec![0u8; len as usize];
if !succeeded(FT_Load_Sfnt_Table(self.face, tag, 0, buf.as_mut_ptr(), &mut len)) { if !succeeded(FT_Load_Sfnt_Table(
return None self.face,
tag,
0,
buf.as_mut_ptr(),
&mut len,
)) {
return None;
} }
Some(FontTable { buffer: buf }) Some(FontTable { buffer: buf })
} }
@ -343,20 +369,28 @@ impl<'a> FontHandle {
unsafe { unsafe {
let result = FT_Set_Char_Size(face, char_size as FT_F26Dot6, 0, 0, 0); let result = FT_Set_Char_Size(face, char_size as FT_F26Dot6, 0, 0, 0);
if succeeded(result) { Ok(()) } else { Err(()) } if succeeded(result) {
Ok(())
} else {
Err(())
}
} }
} }
fn has_table(&self, tag: FontTableTag) -> bool { fn has_table(&self, tag: FontTableTag) -> bool {
unsafe { unsafe {
succeeded(FT_Load_Sfnt_Table(self.face, tag as FT_ULong, 0, ptr::null_mut(), &mut 0)) succeeded(FT_Load_Sfnt_Table(
self.face,
tag as FT_ULong,
0,
ptr::null_mut(),
&mut 0,
))
} }
} }
fn face_rec_mut(&'a self) -> &'a mut FT_FaceRec { fn face_rec_mut(&'a self) -> &'a mut FT_FaceRec {
unsafe { unsafe { &mut (*self.face) }
&mut (*self.face)
}
} }
fn font_units_to_au(&self, value: f64) -> Au { fn font_units_to_au(&self, value: f64) -> Au {
@ -378,11 +412,12 @@ impl<'a> FontHandle {
fn os2_table(&self) -> Option<OS2Table> { fn os2_table(&self) -> Option<OS2Table> {
unsafe { unsafe {
let os2 = FT_Get_Sfnt_Table(self.face_rec_mut(), FT_Sfnt_Tag::FT_SFNT_OS2) as *mut TT_OS2; let os2 =
FT_Get_Sfnt_Table(self.face_rec_mut(), FT_Sfnt_Tag::FT_SFNT_OS2) as *mut TT_OS2;
let valid = !os2.is_null() && (*os2).version != 0xffff; let valid = !os2.is_null() && (*os2).version != 0xffff;
if !valid { if !valid {
return None return None;
} }
Some(OS2Table { Some(OS2Table {

View file

@ -23,7 +23,7 @@ pub struct User {
size: usize, size: usize,
} }
extern fn ft_alloc(mem: FT_Memory, req_size: c_long) -> *mut c_void { extern "C" fn ft_alloc(mem: FT_Memory, req_size: c_long) -> *mut c_void {
unsafe { unsafe {
let ptr = malloc(req_size as usize); let ptr = malloc(req_size as usize);
let ptr = ptr as *mut c_void; // libc::c_void vs std::os::raw::c_void let ptr = ptr as *mut c_void; // libc::c_void vs std::os::raw::c_void
@ -34,7 +34,7 @@ extern fn ft_alloc(mem: FT_Memory, req_size: c_long) -> *mut c_void {
} }
} }
extern fn ft_free(mem: FT_Memory, ptr: *mut c_void) { extern "C" fn ft_free(mem: FT_Memory, ptr: *mut c_void) {
unsafe { unsafe {
let actual_size = usable_size(ptr); let actual_size = usable_size(ptr);
let user = (*mem).user as *mut User; let user = (*mem).user as *mut User;
@ -43,8 +43,12 @@ extern fn ft_free(mem: FT_Memory, ptr: *mut c_void) {
} }
} }
extern fn ft_realloc(mem: FT_Memory, _old_size: c_long, new_req_size: c_long, extern "C" fn ft_realloc(
old_ptr: *mut c_void) -> *mut c_void { mem: FT_Memory,
_old_size: c_long,
new_req_size: c_long,
old_ptr: *mut c_void,
) -> *mut c_void {
unsafe { unsafe {
let old_actual_size = usable_size(old_ptr); let old_actual_size = usable_size(old_ptr);
let new_ptr = realloc(old_ptr as *mut _, new_req_size as usize); let new_ptr = realloc(old_ptr as *mut _, new_req_size as usize);
@ -108,9 +112,7 @@ impl MallocSizeOf for FontContextHandle {
impl FontContextHandle { impl FontContextHandle {
pub fn new() -> FontContextHandle { pub fn new() -> FontContextHandle {
let user = Box::into_raw(Box::new(User { let user = Box::into_raw(Box::new(User { size: 0 }));
size: 0,
}));
let mem = Box::into_raw(Box::new(FT_MemoryRec_ { let mem = Box::into_raw(Box::new(FT_MemoryRec_ {
user: user as *mut c_void, user: user as *mut c_void,
alloc: Some(ft_alloc), alloc: Some(ft_alloc),
@ -121,12 +123,18 @@ impl FontContextHandle {
let mut ctx: FT_Library = ptr::null_mut(); let mut ctx: FT_Library = ptr::null_mut();
let result = FT_New_Library(mem, &mut ctx); let result = FT_New_Library(mem, &mut ctx);
if !succeeded(result) { panic!("Unable to initialize FreeType library"); } if !succeeded(result) {
panic!("Unable to initialize FreeType library");
}
FT_Add_Default_Modules(ctx); FT_Add_Default_Modules(ctx);
FontContextHandle { FontContextHandle {
ctx: Rc::new(FreeTypeLibraryHandle { ctx: ctx, mem: mem, user: user }), ctx: Rc::new(FreeTypeLibraryHandle {
ctx: ctx,
mem: mem,
user: user,
}),
} }
} }
} }

View file

@ -20,7 +20,10 @@ static FC_FILE: &'static [u8] = b"file\0";
static FC_INDEX: &'static [u8] = b"index\0"; static FC_INDEX: &'static [u8] = b"index\0";
static FC_FONTFORMAT: &'static [u8] = b"fontformat\0"; static FC_FONTFORMAT: &'static [u8] = b"fontformat\0";
pub fn for_each_available_family<F>(mut callback: F) where F: FnMut(String) { pub fn for_each_available_family<F>(mut callback: F)
where
F: FnMut(String),
{
unsafe { unsafe {
let config = FcConfigGetCurrent(); let config = FcConfigGetCurrent();
let font_set = FcConfigGetFonts(config, FcSetSystem); let font_set = FcConfigGetFonts(config, FcSetSystem);
@ -29,19 +32,21 @@ pub fn for_each_available_family<F>(mut callback: F) where F: FnMut(String) {
let mut family: *mut FcChar8 = ptr::null_mut(); let mut family: *mut FcChar8 = ptr::null_mut();
let mut format: *mut FcChar8 = ptr::null_mut(); let mut format: *mut FcChar8 = ptr::null_mut();
let mut v: c_int = 0; let mut v: c_int = 0;
if FcPatternGetString(*font, FC_FONTFORMAT.as_ptr() as *mut c_char, v, &mut format) != FcResultMatch { if FcPatternGetString(*font, FC_FONTFORMAT.as_ptr() as *mut c_char, v, &mut format) !=
FcResultMatch
{
continue; continue;
} }
// Skip bitmap fonts. They aren't supported by FreeType. // Skip bitmap fonts. They aren't supported by FreeType.
let fontformat = c_str_to_string(format as *const c_char); let fontformat = c_str_to_string(format as *const c_char);
if fontformat != "TrueType" && if fontformat != "TrueType" && fontformat != "CFF" && fontformat != "Type 1" {
fontformat != "CFF" &&
fontformat != "Type 1" {
continue; continue;
} }
while FcPatternGetString(*font, FC_FAMILY.as_ptr() as *mut c_char, v, &mut family) == FcResultMatch { while FcPatternGetString(*font, FC_FAMILY.as_ptr() as *mut c_char, v, &mut family) ==
FcResultMatch
{
let family_name = c_str_to_string(family as *const c_char); let family_name = c_str_to_string(family as *const c_char);
callback(family_name); callback(family_name);
v += 1; v += 1;
@ -51,7 +56,8 @@ pub fn for_each_available_family<F>(mut callback: F) where F: FnMut(String) {
} }
pub fn for_each_variation<F>(family_name: &str, mut callback: F) pub fn for_each_variation<F>(family_name: &str, mut callback: F)
where F: FnMut(String) where
F: FnMut(String),
{ {
debug!("getting variations for {}", family_name); debug!("getting variations for {}", family_name);
unsafe { unsafe {
@ -62,7 +68,11 @@ pub fn for_each_variation<F>(family_name: &str, mut callback: F)
assert!(!pattern.is_null()); assert!(!pattern.is_null());
let family_name_c = CString::new(family_name).unwrap(); let family_name_c = CString::new(family_name).unwrap();
let family_name = family_name_c.as_ptr(); let family_name = family_name_c.as_ptr();
let ok = FcPatternAddString(pattern, FC_FAMILY.as_ptr() as *mut c_char, family_name as *mut FcChar8); let ok = FcPatternAddString(
pattern,
FC_FAMILY.as_ptr() as *mut c_char,
family_name as *mut FcChar8,
);
assert_ne!(ok, 0); assert_ne!(ok, 0);
let object_set = FcObjectSetCreate(); let object_set = FcObjectSetCreate();
@ -85,7 +95,8 @@ pub fn for_each_variation<F>(family_name: &str, mut callback: F)
panic!(); panic!();
}; };
let mut index: libc::c_int = 0; let mut index: libc::c_int = 0;
let result = FcPatternGetInteger(*font, FC_INDEX.as_ptr() as *mut c_char, 0, &mut index); let result =
FcPatternGetInteger(*font, FC_INDEX.as_ptr() as *mut c_char, 0, &mut index);
let index = if result == FcResultMatch { let index = if result == FcResultMatch {
index index
} else { } else {
@ -119,7 +130,12 @@ pub fn system_default_family(generic_name: &str) -> Option<String> {
let family_name = if result == FcResultMatch { let family_name = if result == FcResultMatch {
let mut match_string: *mut FcChar8 = ptr::null_mut(); let mut match_string: *mut FcChar8 = ptr::null_mut();
FcPatternGetString(family_match, FC_FAMILY.as_ptr() as *mut c_char, 0, &mut match_string); FcPatternGetString(
family_match,
FC_FAMILY.as_ptr() as *mut c_char,
0,
&mut match_string,
);
let result = c_str_to_string(match_string as *const c_char); let result = c_str_to_string(match_string as *const c_char);
FcPatternDestroy(family_match); FcPatternDestroy(family_match);
Some(result) Some(result)
@ -136,12 +152,7 @@ pub static SANS_SERIF_FONT_FAMILY: &'static str = "DejaVu Sans";
// Based on gfxPlatformGtk::GetCommonFallbackFonts() in Gecko // Based on gfxPlatformGtk::GetCommonFallbackFonts() in Gecko
pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> { pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
let mut families = vec!( let mut families = vec!["DejaVu Serif", "FreeSerif", "DejaVu Sans", "FreeSans"];
"DejaVu Serif",
"FreeSerif",
"DejaVu Sans",
"FreeSans",
);
if let Some(codepoint) = codepoint { if let Some(codepoint) = codepoint {
if is_cjk(codepoint) { if is_cjk(codepoint) {

View file

@ -15,7 +15,6 @@ use webrender_api::NativeFontHandle;
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub struct FontTemplateData { pub struct FontTemplateData {
// If you add members here, review the Debug impl below // If you add members here, review the Debug impl below
pub bytes: Option<Vec<u8>>, pub bytes: Option<Vec<u8>>,
pub identifier: Atom, pub identifier: Atom,
} }
@ -23,8 +22,10 @@ pub struct FontTemplateData {
impl fmt::Debug for FontTemplateData { impl fmt::Debug for FontTemplateData {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("FontTemplateData") fmt.debug_struct("FontTemplateData")
.field("bytes", &self.bytes.as_ref().map(|b| format!("[{} bytes]", b.len()))) .field(
.field("identifier", &self.identifier) "bytes",
&self.bytes.as_ref().map(|b| format!("[{} bytes]", b.len())),
).field("identifier", &self.identifier)
.finish() .finish()
} }
} }

View file

@ -3,7 +3,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/// Implementation of Quartz (CoreGraphics) fonts. /// Implementation of Quartz (CoreGraphics) fonts.
use app_units::Au; use app_units::Au;
use byteorder::{BigEndian, ByteOrder}; use byteorder::{BigEndian, ByteOrder};
use core_foundation::base::CFIndex; use core_foundation::base::CFIndex;
@ -111,8 +110,8 @@ impl FontHandle {
return None; return None;
} }
let pt_per_font_unit = self.ctfont.pt_size() as f64 / let pt_per_font_unit =
self.ctfont.units_per_em() as f64; self.ctfont.pt_size() as f64 / self.ctfont.units_per_em() as f64;
result.px_per_font_unit = pt_to_px(pt_per_font_unit); result.px_per_font_unit = pt_to_px(pt_per_font_unit);
} }
start = end; start = end;
@ -160,15 +159,15 @@ impl fmt::Debug for CachedKernTable {
} }
} }
impl FontHandleMethods for FontHandle { impl FontHandleMethods for FontHandle {
fn new_from_template(_fctx: &FontContextHandle, fn new_from_template(
_fctx: &FontContextHandle,
template: Arc<FontTemplateData>, template: Arc<FontTemplateData>,
pt_size: Option<Au>) pt_size: Option<Au>,
-> Result<FontHandle, ()> { ) -> Result<FontHandle, ()> {
let size = match pt_size { let size = match pt_size {
Some(s) => s.to_f64_px(), Some(s) => s.to_f64_px(),
None => 0.0 None => 0.0,
}; };
match template.ctfont(size) { match template.ctfont(size) {
Some(ref ctfont) => { Some(ref ctfont) => {
@ -184,10 +183,8 @@ impl FontHandleMethods for FontHandle {
handle.table_for_tag(GPOS).is_none() && handle.table_for_tag(GPOS).is_none() &&
handle.table_for_tag(GSUB).is_none(); handle.table_for_tag(GSUB).is_none();
Ok(handle) Ok(handle)
} },
None => { None => Err(()),
Err(())
}
} }
} }
@ -237,9 +234,9 @@ impl FontHandleMethods for FontHandle {
let mut glyphs: [CGGlyph; 1] = [0 as CGGlyph]; let mut glyphs: [CGGlyph; 1] = [0 as CGGlyph];
let count: CFIndex = 1; let count: CFIndex = 1;
let result = self.ctfont.get_glyphs_for_characters(&characters[0], let result = self
&mut glyphs[0], .ctfont
count); .get_glyphs_for_characters(&characters[0], &mut glyphs[0], count);
if !result { if !result {
// No glyph for this character // No glyph for this character
@ -265,10 +262,12 @@ impl FontHandleMethods for FontHandle {
fn glyph_h_advance(&self, glyph: GlyphId) -> Option<FractionalPixel> { fn glyph_h_advance(&self, glyph: GlyphId) -> Option<FractionalPixel> {
let glyphs = [glyph as CGGlyph]; let glyphs = [glyph as CGGlyph];
let advance = self.ctfont.get_advances_for_glyphs(kCTFontDefaultOrientation, let advance = self.ctfont.get_advances_for_glyphs(
kCTFontDefaultOrientation,
&glyphs[0], &glyphs[0],
ptr::null_mut(), ptr::null_mut(),
1); 1,
);
Some(advance as FractionalPixel) Some(advance as FractionalPixel)
} }
@ -283,7 +282,8 @@ impl FontHandleMethods for FontHandle {
let line_gap = (ascent + descent + leading + 0.5).floor(); let line_gap = (ascent + descent + leading + 0.5).floor();
let max_advance_width = au_from_pt(bounding_rect.size.width as f64); let max_advance_width = au_from_pt(bounding_rect.size.width as f64);
let average_advance = self.glyph_index('0') let average_advance = self
.glyph_index('0')
.and_then(|idx| self.glyph_h_advance(idx)) .and_then(|idx| self.glyph_h_advance(idx))
.map(Au::from_f64_px) .map(Au::from_f64_px)
.unwrap_or(max_advance_width); .unwrap_or(max_advance_width);
@ -307,15 +307,17 @@ impl FontHandleMethods for FontHandle {
average_advance: average_advance, average_advance: average_advance,
line_gap: Au::from_f64_px(line_gap), line_gap: Au::from_f64_px(line_gap),
}; };
debug!("Font metrics (@{} pt): {:?}", self.ctfont.pt_size() as f64, metrics); debug!(
"Font metrics (@{} pt): {:?}",
self.ctfont.pt_size() as f64,
metrics
);
metrics metrics
} }
fn table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> { fn table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
let result: Option<CFData> = self.ctfont.get_font_table(tag); let result: Option<CFData> = self.ctfont.get_font_table(tag);
result.and_then(|data| { result.and_then(|data| Some(FontTable::wrap(data)))
Some(FontTable::wrap(data))
})
} }
fn identifier(&self) -> Atom { fn identifier(&self) -> Atom {

View file

@ -6,7 +6,7 @@ use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct FontContextHandle { pub struct FontContextHandle {
ctx: () ctx: (),
} }
impl FontContextHandle { impl FontContextHandle {

View file

@ -6,14 +6,20 @@ use core_text;
use text::util::unicode_plane; use text::util::unicode_plane;
use ucd::{Codepoint, UnicodeBlock}; use ucd::{Codepoint, UnicodeBlock};
pub fn for_each_available_family<F>(mut callback: F) where F: FnMut(String) { pub fn for_each_available_family<F>(mut callback: F)
where
F: FnMut(String),
{
let family_names = core_text::font_collection::get_family_names(); let family_names = core_text::font_collection::get_family_names();
for family_name in family_names.iter() { for family_name in family_names.iter() {
callback(family_name.to_string()); callback(family_name.to_string());
} }
} }
pub fn for_each_variation<F>(family_name: &str, mut callback: F) where F: FnMut(String) { pub fn for_each_variation<F>(family_name: &str, mut callback: F)
where
F: FnMut(String),
{
debug!("Looking for faces of family: {}", family_name); debug!("Looking for faces of family: {}", family_name);
let family_collection = core_text::font_collection::create_for_family(family_name); let family_collection = core_text::font_collection::create_for_family(family_name);
@ -31,7 +37,7 @@ pub fn system_default_family(_generic_name: &str) -> Option<String> {
// Based on gfxPlatformMac::GetCommonFallbackFonts() in Gecko // Based on gfxPlatformMac::GetCommonFallbackFonts() in Gecko
pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> { pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
let mut families = vec!("Lucida Grande"); let mut families = vec!["Lucida Grande"];
if let Some(codepoint) = codepoint { if let Some(codepoint) = codepoint {
match unicode_plane(codepoint) { match unicode_plane(codepoint) {
@ -45,66 +51,65 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
UnicodeBlock::Thaana | UnicodeBlock::Thaana |
UnicodeBlock::NKo => { UnicodeBlock::NKo => {
families.push("Geeza Pro"); families.push("Geeza Pro");
} },
UnicodeBlock::Devanagari => { UnicodeBlock::Devanagari => {
families.push("Devanagari Sangam MN"); families.push("Devanagari Sangam MN");
} },
UnicodeBlock::Gurmukhi => { UnicodeBlock::Gurmukhi => {
families.push("Gurmukhi MN"); families.push("Gurmukhi MN");
} },
UnicodeBlock::Gujarati => { UnicodeBlock::Gujarati => {
families.push("Gujarati Sangam MN"); families.push("Gujarati Sangam MN");
} },
UnicodeBlock::Tamil => { UnicodeBlock::Tamil => {
families.push("Tamil MN"); families.push("Tamil MN");
} },
UnicodeBlock::Lao => { UnicodeBlock::Lao => {
families.push("Lao MN"); families.push("Lao MN");
} },
UnicodeBlock::Tibetan => { UnicodeBlock::Tibetan => {
families.push("Songti SC"); families.push("Songti SC");
} },
UnicodeBlock::Myanmar => { UnicodeBlock::Myanmar => {
families.push("Myanmar MN"); families.push("Myanmar MN");
} },
UnicodeBlock::Ethiopic | UnicodeBlock::Ethiopic |
UnicodeBlock::EthiopicSupplement | UnicodeBlock::EthiopicSupplement |
UnicodeBlock::EthiopicExtended | UnicodeBlock::EthiopicExtended |
UnicodeBlock::EthiopicExtendedA => { UnicodeBlock::EthiopicExtendedA => {
families.push("Kefa"); families.push("Kefa");
} },
UnicodeBlock::Cherokee => { UnicodeBlock::Cherokee => {
families.push("Plantagenet Cherokee"); families.push("Plantagenet Cherokee");
} },
UnicodeBlock::UnifiedCanadianAboriginalSyllabics | UnicodeBlock::UnifiedCanadianAboriginalSyllabics |
UnicodeBlock::UnifiedCanadianAboriginalSyllabicsExtended => { UnicodeBlock::UnifiedCanadianAboriginalSyllabicsExtended => {
families.push("Euphemia UCAS"); families.push("Euphemia UCAS");
} },
UnicodeBlock::Mongolian | UnicodeBlock::Mongolian |
UnicodeBlock::YiSyllables | UnicodeBlock::YiSyllables |
UnicodeBlock::YiRadicals => { UnicodeBlock::YiRadicals => {
families.push("STHeiti"); families.push("STHeiti");
} },
UnicodeBlock::Khmer | UnicodeBlock::Khmer | UnicodeBlock::KhmerSymbols => {
UnicodeBlock::KhmerSymbols => {
families.push("Khmer MN"); families.push("Khmer MN");
} },
UnicodeBlock::TaiLe => { UnicodeBlock::TaiLe => {
families.push("Microsoft Tai Le"); families.push("Microsoft Tai Le");
} },
UnicodeBlock::GeneralPunctuation | UnicodeBlock::GeneralPunctuation |
UnicodeBlock::SuperscriptsandSubscripts | UnicodeBlock::SuperscriptsandSubscripts |
@ -134,11 +139,11 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
families.push("Apple Symbols"); families.push("Apple Symbols");
families.push("Menlo"); families.push("Menlo");
families.push("STIXGeneral"); families.push("STIXGeneral");
} },
UnicodeBlock::BraillePatterns => { UnicodeBlock::BraillePatterns => {
families.push("Apple Braille"); families.push("Apple Braille");
} },
UnicodeBlock::Bopomofo | UnicodeBlock::Bopomofo |
UnicodeBlock::HangulCompatibilityJamo | UnicodeBlock::HangulCompatibilityJamo |
@ -147,7 +152,7 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
UnicodeBlock::CJKStrokes | UnicodeBlock::CJKStrokes |
UnicodeBlock::KatakanaPhoneticExtensions => { UnicodeBlock::KatakanaPhoneticExtensions => {
families.push("Hiragino Sans GB"); families.push("Hiragino Sans GB");
} },
UnicodeBlock::YijingHexagramSymbols | UnicodeBlock::YijingHexagramSymbols |
UnicodeBlock::CyrillicExtendedB | UnicodeBlock::CyrillicExtendedB |
@ -158,27 +163,27 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
UnicodeBlock::HalfwidthandFullwidthForms | UnicodeBlock::HalfwidthandFullwidthForms |
UnicodeBlock::Specials => { UnicodeBlock::Specials => {
families.push("Apple Symbols"); families.push("Apple Symbols");
} },
_ => {} _ => {},
}
} }
} }
},
// https://en.wikipedia.org/wiki/Plane_(Unicode)#Supplementary_Multilingual_Plane // https://en.wikipedia.org/wiki/Plane_(Unicode)#Supplementary_Multilingual_Plane
1 => { 1 => {
families.push("Apple Symbols"); families.push("Apple Symbols");
families.push("STIXGeneral"); families.push("STIXGeneral");
} },
// https://en.wikipedia.org/wiki/Plane_(Unicode)#Supplementary_Ideographic_Plane // https://en.wikipedia.org/wiki/Plane_(Unicode)#Supplementary_Ideographic_Plane
2 => { 2 => {
// Systems with MS Office may have these fonts // Systems with MS Office may have these fonts
families.push("MingLiU-ExtB"); families.push("MingLiU-ExtB");
families.push("SimSun-ExtB"); families.push("SimSun-ExtB");
} },
_ => {} _ => {},
} }
} }

View file

@ -27,7 +27,6 @@ use webrender_api::NativeFontHandle;
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub struct FontTemplateData { pub struct FontTemplateData {
// If you add members here, review the Debug impl below // If you add members here, review the Debug impl below
/// The `CTFont` object, if present. This is cached here so that we don't have to keep creating /// The `CTFont` object, if present. This is cached here so that we don't have to keep creating
/// `CTFont` instances over and over. It can always be recreated from the `identifier` and/or /// `CTFont` instances over and over. It can always be recreated from the `identifier` and/or
/// `font_data` fields. /// `font_data` fields.
@ -38,7 +37,7 @@ pub struct FontTemplateData {
ctfont: CachedCTFont, ctfont: CachedCTFont,
pub identifier: Atom, pub identifier: Atom,
pub font_data: Option<Arc<Vec<u8>>> pub font_data: Option<Arc<Vec<u8>>>,
} }
impl fmt::Debug for FontTemplateData { impl fmt::Debug for FontTemplateData {
@ -48,11 +47,11 @@ impl fmt::Debug for FontTemplateData {
.field("identifier", &self.identifier) .field("identifier", &self.identifier)
.field( .field(
"font_data", "font_data",
&self.font_data &self
.font_data
.as_ref() .as_ref()
.map(|bytes| format!("[{} bytes]", bytes.len())) .map(|bytes| format!("[{} bytes]", bytes.len())),
) ).finish()
.finish()
} }
} }
@ -64,7 +63,7 @@ impl FontTemplateData {
Ok(FontTemplateData { Ok(FontTemplateData {
ctfont: CachedCTFont(Mutex::new(HashMap::new())), ctfont: CachedCTFont(Mutex::new(HashMap::new())),
identifier: identifier.to_owned(), identifier: identifier.to_owned(),
font_data: font_data.map(Arc::new) font_data: font_data.map(Arc::new),
}) })
} }
@ -83,10 +82,10 @@ impl FontTemplateData {
match cgfont_result { match cgfont_result {
Ok(cgfont) => { Ok(cgfont) => {
Some(core_text::font::new_from_CGFont(&cgfont, clamped_pt_size)) Some(core_text::font::new_from_CGFont(&cgfont, clamped_pt_size))
},
Err(_) => None,
} }
Err(_) => None },
}
}
None => core_text::font::new_from_name(&*self.identifier, clamped_pt_size).ok(), None => core_text::font::new_from_name(&*self.identifier, clamped_pt_size).ok(),
}; };
if let Some(ctfont) = ctfont { if let Some(ctfont) = ctfont {
@ -104,16 +103,23 @@ impl FontTemplateData {
return font_data; return font_data;
} }
let path = ServoUrl::parse(&*self.ctfont(0.0) let path = ServoUrl::parse(
&*self
.ctfont(0.0)
.expect("No Core Text font available!") .expect("No Core Text font available!")
.url() .url()
.expect("No URL for Core Text font!") .expect("No URL for Core Text font!")
.get_string() .get_string()
.to_string()).expect("Couldn't parse Core Text font URL!") .to_string(),
.as_url().to_file_path() ).expect("Couldn't parse Core Text font URL!")
.as_url()
.to_file_path()
.expect("Core Text font didn't name a path!"); .expect("Core Text font didn't name a path!");
let mut bytes = Vec::new(); let mut bytes = Vec::new();
File::open(path).expect("Couldn't open font file!").read_to_end(&mut bytes).unwrap(); File::open(path)
.expect("Couldn't open font file!")
.read_to_end(&mut bytes)
.unwrap();
bytes bytes
} }
@ -125,7 +131,8 @@ impl FontTemplateData {
/// Returns the native font that underlies this font template, if applicable. /// Returns the native font that underlies this font template, if applicable.
pub fn native_font(&self) -> Option<NativeFontHandle> { pub fn native_font(&self) -> Option<NativeFontHandle> {
self.ctfont(0.0).map(|ctfont| NativeFontHandle(ctfont.copy_to_CGFont())) self.ctfont(0.0)
.map(|ctfont| NativeFontHandle(ctfont.copy_to_CGFont()))
} }
} }
@ -140,14 +147,19 @@ impl Deref for CachedCTFont {
} }
impl Serialize for CachedCTFont { impl Serialize for CachedCTFont {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_none() serializer.serialize_none()
} }
} }
impl<'de> Deserialize<'de> for CachedCTFont { impl<'de> Deserialize<'de> for CachedCTFont {
fn deserialize<D>(deserializer: D) -> Result<CachedCTFont, D::Error> fn deserialize<D>(deserializer: D) -> Result<CachedCTFont, D::Error>
where D: Deserializer<'de> { where
D: Deserializer<'de>,
{
struct NoneOptionVisitor; struct NoneOptionVisitor;
impl<'de> Visitor<'de> for NoneOptionVisitor { impl<'de> Visitor<'de> for NoneOptionVisitor {
@ -158,7 +170,10 @@ impl<'de> Deserialize<'de> for CachedCTFont {
} }
#[inline] #[inline]
fn visit_none<E>(self) -> Result<CachedCTFont, E> where E: Error { fn visit_none<E>(self) -> Result<CachedCTFont, E>
where
E: Error,
{
Ok(CachedCTFont(Mutex::new(HashMap::new()))) Ok(CachedCTFont(Mutex::new(HashMap::new())))
} }
} }

View file

@ -23,7 +23,9 @@ mod freetype {
/// Creates a String from the given null-terminated buffer. /// Creates a String from the given null-terminated buffer.
/// Panics if the buffer does not contain UTF-8. /// Panics if the buffer does not contain UTF-8.
unsafe fn c_str_to_string(s: *const c_char) -> String { unsafe fn c_str_to_string(s: *const c_char) -> String {
str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap().to_owned() str::from_utf8(CStr::from_ptr(s).to_bytes())
.unwrap()
.to_owned()
} }
pub mod font; pub mod font;

View file

@ -27,10 +27,18 @@ use text::glyph::GlyphId;
use truetype; use truetype;
// 1em = 12pt = 16px, assuming 72 points per inch and 96 px per inch // 1em = 12pt = 16px, assuming 72 points per inch and 96 px per inch
fn pt_to_px(pt: f64) -> f64 { pt / 72. * 96. } fn pt_to_px(pt: f64) -> f64 {
fn em_to_px(em: f64) -> f64 { em * 16. } pt / 72. * 96.
fn au_from_em(em: f64) -> Au { Au::from_f64_px(em_to_px(em)) } }
fn au_from_pt(pt: f64) -> Au { Au::from_f64_px(pt_to_px(pt)) } fn em_to_px(em: f64) -> f64 {
em * 16.
}
fn au_from_em(em: f64) -> Au {
Au::from_f64_px(em_to_px(em))
}
fn au_from_pt(pt: f64) -> Au {
Au::from_f64_px(pt_to_px(pt))
}
pub struct FontTable { pub struct FontTable {
data: Vec<u8>, data: Vec<u8>,
@ -38,7 +46,9 @@ pub struct FontTable {
impl FontTable { impl FontTable {
pub fn wrap(data: &[u8]) -> FontTable { pub fn wrap(data: &[u8]) -> FontTable {
FontTable { data: data.to_vec() } FontTable {
data: data.to_vec(),
}
} }
} }
@ -139,7 +149,7 @@ impl FontInfo {
} else { } else {
return Err(()); return Err(());
} }
} },
}; };
let mut os2_table_cursor = Cursor::new(os2_table_bytes.as_ref().unwrap()); let mut os2_table_cursor = Cursor::new(os2_table_bytes.as_ref().unwrap());
@ -163,7 +173,8 @@ impl FontInfo {
let weight = StyleFontWeight(weight_val as f32); let weight = StyleFontWeight(weight_val as f32);
let stretch = StyleFontStretch(NonNegative(match min(9, max(1, width_val)) { let stretch = StyleFontStretch(NonNegative(
match min(9, max(1, width_val)) {
1 => FontStretchKeyword::UltraCondensed, 1 => FontStretchKeyword::UltraCondensed,
2 => FontStretchKeyword::ExtraCondensed, 2 => FontStretchKeyword::ExtraCondensed,
3 => FontStretchKeyword::Condensed, 3 => FontStretchKeyword::Condensed,
@ -174,7 +185,8 @@ impl FontInfo {
8 => FontStretchKeyword::ExtraExpanded, 8 => FontStretchKeyword::ExtraExpanded,
9 => FontStretchKeyword::UltraExpanded, 9 => FontStretchKeyword::UltraExpanded,
_ => return Err(()), _ => return Err(()),
}.compute())); }.compute(),
));
let style = if italic_bool { let style = if italic_bool {
GenericFontStyle::Italic GenericFontStyle::Italic
@ -212,7 +224,8 @@ impl FontInfo {
// slightly blacker black // slightly blacker black
FontWeight::ExtraBlack => 1000., FontWeight::ExtraBlack => 1000.,
}); });
let stretch = StyleFontStretch(NonNegative(match font.stretch() { let stretch = StyleFontStretch(NonNegative(
match font.stretch() {
FontStretch::Undefined => FontStretchKeyword::Normal, FontStretch::Undefined => FontStretchKeyword::Normal,
FontStretch::UltraCondensed => FontStretchKeyword::UltraCondensed, FontStretch::UltraCondensed => FontStretchKeyword::UltraCondensed,
FontStretch::ExtraCondensed => FontStretchKeyword::ExtraCondensed, FontStretch::ExtraCondensed => FontStretchKeyword::ExtraCondensed,
@ -223,7 +236,8 @@ impl FontInfo {
FontStretch::Expanded => FontStretchKeyword::Expanded, FontStretch::Expanded => FontStretchKeyword::Expanded,
FontStretch::ExtraExpanded => FontStretchKeyword::ExtraExpanded, FontStretch::ExtraExpanded => FontStretchKeyword::ExtraExpanded,
FontStretch::UltraExpanded => FontStretchKeyword::UltraExpanded, FontStretch::UltraExpanded => FontStretchKeyword::UltraExpanded,
}.compute())); }.compute(),
));
Ok(FontInfo { Ok(FontInfo {
family_name: font.family_name(), family_name: font.family_name(),
@ -246,13 +260,14 @@ pub struct FontHandle {
scaled_du_to_px: f32, scaled_du_to_px: f32,
} }
impl FontHandle { impl FontHandle {}
}
impl FontHandleMethods for FontHandle { impl FontHandleMethods for FontHandle {
fn new_from_template(_: &FontContextHandle, template: Arc<FontTemplateData>, pt_size: Option<Au>) fn new_from_template(
-> Result<Self, ()> _: &FontContextHandle,
{ template: Arc<FontTemplateData>,
pt_size: Option<Au>,
) -> Result<Self, ()> {
let (info, face) = if let Some(ref raw_font) = template.bytes { let (info, face) = if let Some(ref raw_font) = template.bytes {
let font_file = FontFile::new_from_data(&raw_font); let font_file = FontFile::new_from_data(&raw_font);
if font_file.is_none() { if font_file.is_none() {
@ -260,7 +275,9 @@ impl FontHandleMethods for FontHandle {
return Err(()); return Err(());
} }
let face = font_file.unwrap().create_face(0, dwrote::DWRITE_FONT_SIMULATIONS_NONE); let face = font_file
.unwrap()
.create_face(0, dwrote::DWRITE_FONT_SIMULATIONS_NONE);
let info = FontInfo::new_from_face(&face)?; let info = FontInfo::new_from_face(&face)?;
(info, face) (info, face)
} else { } else {
@ -375,7 +392,9 @@ impl FontHandleMethods for FontHandle {
} }
fn table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> { fn table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
self.face.get_font_table(tag).map(|bytes| FontTable { data: bytes }) self.face
.get_font_table(tag)
.map(|bytes| FontTable { data: bytes })
} }
fn identifier(&self) -> Atom { fn identifier(&self) -> Atom {

View file

@ -21,7 +21,10 @@ pub fn system_default_family(_: &str) -> Option<String> {
Some("Verdana".to_owned()) Some("Verdana".to_owned())
} }
pub fn for_each_available_family<F>(mut callback: F) where F: FnMut(String) { pub fn for_each_available_family<F>(mut callback: F)
where
F: FnMut(String),
{
let system_fc = FontCollection::system(); let system_fc = FontCollection::system();
for family in system_fc.families_iter() { for family in system_fc.families_iter() {
callback(family.name()); callback(family.name());
@ -37,7 +40,10 @@ pub fn for_each_available_family<F>(mut callback: F) where F: FnMut(String) {
// we'll stringify, and then put them all in a HashMap with // we'll stringify, and then put them all in a HashMap with
// the actual FontDescriptor there. // the actual FontDescriptor there.
pub fn for_each_variation<F>(family_name: &str, mut callback: F) where F: FnMut(String) { pub fn for_each_variation<F>(family_name: &str, mut callback: F)
where
F: FnMut(String),
{
let system_fc = FontCollection::system(); let system_fc = FontCollection::system();
if let Some(family) = system_fc.get_font_family_by_name(family_name) { if let Some(family) = system_fc.get_font_family_by_name(family_name) {
let count = family.get_font_count(); let count = family.get_font_count();
@ -65,12 +71,14 @@ pub fn descriptor_from_atom(ident: &Atom) -> FontDescriptor {
pub fn font_from_atom(ident: &Atom) -> Font { pub fn font_from_atom(ident: &Atom) -> Font {
let fonts = FONT_ATOM_MAP.lock().unwrap(); let fonts = FONT_ATOM_MAP.lock().unwrap();
FontCollection::system().get_font_from_descriptor(fonts.get(ident).unwrap()).unwrap() FontCollection::system()
.get_font_from_descriptor(fonts.get(ident).unwrap())
.unwrap()
} }
// Based on gfxWindowsPlatform::GetCommonFallbackFonts() in Gecko // Based on gfxWindowsPlatform::GetCommonFallbackFonts() in Gecko
pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> { pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
let mut families = vec!("Arial"); let mut families = vec!["Arial"];
if let Some(codepoint) = codepoint { if let Some(codepoint) = codepoint {
match unicode_plane(codepoint) { match unicode_plane(codepoint) {
@ -83,31 +91,29 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
UnicodeBlock::Hebrew => { UnicodeBlock::Hebrew => {
families.push("Estrangelo Edessa"); families.push("Estrangelo Edessa");
families.push("Cambria"); families.push("Cambria");
} },
UnicodeBlock::Arabic | UnicodeBlock::Arabic | UnicodeBlock::ArabicSupplement => {
UnicodeBlock::ArabicSupplement => {
families.push("Microsoft Uighur"); families.push("Microsoft Uighur");
} },
UnicodeBlock::Syriac => { UnicodeBlock::Syriac => {
families.push("Estrangelo Edessa"); families.push("Estrangelo Edessa");
} },
UnicodeBlock::Thaana => { UnicodeBlock::Thaana => {
families.push("MV Boli"); families.push("MV Boli");
} },
UnicodeBlock::NKo => { UnicodeBlock::NKo => {
families.push("Ebrima"); families.push("Ebrima");
} },
UnicodeBlock::Devanagari | UnicodeBlock::Devanagari | UnicodeBlock::Bengali => {
UnicodeBlock::Bengali => {
families.push("Nirmala UI"); families.push("Nirmala UI");
families.push("Utsaah"); families.push("Utsaah");
families.push("Aparajita"); families.push("Aparajita");
} },
UnicodeBlock::Gurmukhi | UnicodeBlock::Gurmukhi |
UnicodeBlock::Gujarati | UnicodeBlock::Gujarati |
@ -123,21 +129,21 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
UnicodeBlock::SundaneseSupplement | UnicodeBlock::SundaneseSupplement |
UnicodeBlock::VedicExtensions => { UnicodeBlock::VedicExtensions => {
families.push("Nirmala UI"); families.push("Nirmala UI");
} },
UnicodeBlock::Thai => { UnicodeBlock::Thai => {
families.push("Leelawadee UI"); families.push("Leelawadee UI");
} },
UnicodeBlock::Lao => { UnicodeBlock::Lao => {
families.push("Lao UI"); families.push("Lao UI");
} },
UnicodeBlock::Myanmar | UnicodeBlock::Myanmar |
UnicodeBlock::MyanmarExtendedA | UnicodeBlock::MyanmarExtendedA |
UnicodeBlock::MyanmarExtendedB => { UnicodeBlock::MyanmarExtendedB => {
families.push("Myanmar Text"); families.push("Myanmar Text");
} },
UnicodeBlock::HangulJamo | UnicodeBlock::HangulJamo |
UnicodeBlock::HangulJamoExtendedA | UnicodeBlock::HangulJamoExtendedA |
@ -145,48 +151,47 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
UnicodeBlock::HangulJamoExtendedB | UnicodeBlock::HangulJamoExtendedB |
UnicodeBlock::HangulCompatibilityJamo => { UnicodeBlock::HangulCompatibilityJamo => {
families.push("Malgun Gothic"); families.push("Malgun Gothic");
} },
UnicodeBlock::Ethiopic | UnicodeBlock::Ethiopic |
UnicodeBlock::EthiopicSupplement | UnicodeBlock::EthiopicSupplement |
UnicodeBlock::EthiopicExtended | UnicodeBlock::EthiopicExtended |
UnicodeBlock::EthiopicExtendedA => { UnicodeBlock::EthiopicExtendedA => {
families.push("Nyala"); families.push("Nyala");
} },
UnicodeBlock::Cherokee => { UnicodeBlock::Cherokee => {
families.push("Plantagenet Cherokee"); families.push("Plantagenet Cherokee");
} },
UnicodeBlock::UnifiedCanadianAboriginalSyllabics | UnicodeBlock::UnifiedCanadianAboriginalSyllabics |
UnicodeBlock::UnifiedCanadianAboriginalSyllabicsExtended => { UnicodeBlock::UnifiedCanadianAboriginalSyllabicsExtended => {
families.push("Euphemia"); families.push("Euphemia");
families.push("Segoe UI"); families.push("Segoe UI");
} },
UnicodeBlock::Khmer | UnicodeBlock::Khmer | UnicodeBlock::KhmerSymbols => {
UnicodeBlock::KhmerSymbols => {
families.push("Khmer UI"); families.push("Khmer UI");
families.push("Leelawadee UI"); families.push("Leelawadee UI");
} },
UnicodeBlock::Mongolian => { UnicodeBlock::Mongolian => {
families.push("Mongolian Baiti"); families.push("Mongolian Baiti");
} },
UnicodeBlock::TaiLe => { UnicodeBlock::TaiLe => {
families.push("Microsoft Tai Le"); families.push("Microsoft Tai Le");
} },
UnicodeBlock::NewTaiLue => { UnicodeBlock::NewTaiLue => {
families.push("Microsoft New Tai Lue"); families.push("Microsoft New Tai Lue");
} },
UnicodeBlock::Buginese | UnicodeBlock::Buginese |
UnicodeBlock::TaiTham | UnicodeBlock::TaiTham |
UnicodeBlock::CombiningDiacriticalMarksExtended => { UnicodeBlock::CombiningDiacriticalMarksExtended => {
families.push("Leelawadee UI"); families.push("Leelawadee UI");
} },
UnicodeBlock::GeneralPunctuation | UnicodeBlock::GeneralPunctuation |
UnicodeBlock::SuperscriptsandSubscripts | UnicodeBlock::SuperscriptsandSubscripts |
@ -220,7 +225,7 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
families.push("Meiryo"); families.push("Meiryo");
families.push("Lucida Sans Unicode"); families.push("Lucida Sans Unicode");
families.push("Ebrima"); families.push("Ebrima");
} },
UnicodeBlock::GeorgianSupplement | UnicodeBlock::GeorgianSupplement |
UnicodeBlock::Tifinagh | UnicodeBlock::Tifinagh |
@ -232,11 +237,11 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
families.push("Segoe UI"); families.push("Segoe UI");
families.push("Segoe UI Symbol"); families.push("Segoe UI Symbol");
families.push("Meiryo"); families.push("Meiryo");
} },
UnicodeBlock::BraillePatterns => { UnicodeBlock::BraillePatterns => {
families.push("Segoe UI Symbol"); families.push("Segoe UI Symbol");
} },
UnicodeBlock::CJKSymbolsandPunctuation | UnicodeBlock::CJKSymbolsandPunctuation |
UnicodeBlock::Hiragana | UnicodeBlock::Hiragana |
@ -249,21 +254,20 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
UnicodeBlock::CJKUnifiedIdeographs => { UnicodeBlock::CJKUnifiedIdeographs => {
families.push("Microsoft YaHei"); families.push("Microsoft YaHei");
families.push("Yu Gothic"); families.push("Yu Gothic");
} },
UnicodeBlock::EnclosedCJKLettersandMonths => { UnicodeBlock::EnclosedCJKLettersandMonths => {
families.push("Malgun Gothic"); families.push("Malgun Gothic");
} },
UnicodeBlock::YijingHexagramSymbols => { UnicodeBlock::YijingHexagramSymbols => {
families.push("Segoe UI Symbol"); families.push("Segoe UI Symbol");
} },
UnicodeBlock::YiSyllables | UnicodeBlock::YiSyllables | UnicodeBlock::YiRadicals => {
UnicodeBlock::YiRadicals => {
families.push("Microsoft Yi Baiti"); families.push("Microsoft Yi Baiti");
families.push("Segoe UI"); families.push("Segoe UI");
} },
UnicodeBlock::Vai | UnicodeBlock::Vai |
UnicodeBlock::CyrillicExtendedB | UnicodeBlock::CyrillicExtendedB |
@ -273,7 +277,7 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
families.push("Ebrima"); families.push("Ebrima");
families.push("Segoe UI"); families.push("Segoe UI");
families.push("Cambria Math"); families.push("Cambria Math");
} },
UnicodeBlock::SylotiNagri | UnicodeBlock::SylotiNagri |
UnicodeBlock::CommonIndicNumberForms | UnicodeBlock::CommonIndicNumberForms |
@ -282,27 +286,25 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
UnicodeBlock::DevanagariExtended => { UnicodeBlock::DevanagariExtended => {
families.push("Microsoft PhagsPa"); families.push("Microsoft PhagsPa");
families.push("Nirmala UI"); families.push("Nirmala UI");
} },
UnicodeBlock::KayahLi | UnicodeBlock::KayahLi | UnicodeBlock::Rejang | UnicodeBlock::Javanese => {
UnicodeBlock::Rejang |
UnicodeBlock::Javanese => {
families.push("Malgun Gothic"); families.push("Malgun Gothic");
families.push("Javanese Text"); families.push("Javanese Text");
families.push("Leelawadee UI"); families.push("Leelawadee UI");
} },
UnicodeBlock::AlphabeticPresentationForms => { UnicodeBlock::AlphabeticPresentationForms => {
families.push("Microsoft Uighur"); families.push("Microsoft Uighur");
families.push("Gabriola"); families.push("Gabriola");
families.push("Sylfaen"); families.push("Sylfaen");
} },
UnicodeBlock::ArabicPresentationFormsA | UnicodeBlock::ArabicPresentationFormsA |
UnicodeBlock::ArabicPresentationFormsB => { UnicodeBlock::ArabicPresentationFormsB => {
families.push("Traditional Arabic"); families.push("Traditional Arabic");
families.push("Arabic Typesetting"); families.push("Arabic Typesetting");
} },
UnicodeBlock::VariationSelectors | UnicodeBlock::VariationSelectors |
UnicodeBlock::VerticalForms | UnicodeBlock::VerticalForms |
@ -312,12 +314,12 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
UnicodeBlock::HalfwidthandFullwidthForms | UnicodeBlock::HalfwidthandFullwidthForms |
UnicodeBlock::Specials => { UnicodeBlock::Specials => {
families.push("Microsoft JhengHei"); families.push("Microsoft JhengHei");
} },
_ => {} _ => {},
}
} }
} }
},
// https://en.wikipedia.org/wiki/Plane_(Unicode)#Supplementary_Multilingual_Plane // https://en.wikipedia.org/wiki/Plane_(Unicode)#Supplementary_Multilingual_Plane
1 => { 1 => {
@ -325,9 +327,9 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
families.push("Ebrima"); families.push("Ebrima");
families.push("Nirmala UI"); families.push("Nirmala UI");
families.push("Cambria Math"); families.push("Cambria Math");
} },
_ => {} _ => {},
} }
} }

View file

@ -11,7 +11,6 @@ use webrender_api::NativeFontHandle;
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub struct FontTemplateData { pub struct FontTemplateData {
// If you add members here, review the Debug impl below // If you add members here, review the Debug impl below
pub bytes: Option<Vec<u8>>, pub bytes: Option<Vec<u8>>,
pub identifier: Atom, pub identifier: Atom,
} }
@ -21,18 +20,20 @@ impl fmt::Debug for FontTemplateData {
fmt.debug_struct("FontTemplateData") fmt.debug_struct("FontTemplateData")
.field( .field(
"bytes", "bytes",
&self.bytes &self
.bytes
.as_ref() .as_ref()
.map(|bytes| format!("[{} bytes]", bytes.len())) .map(|bytes| format!("[{} bytes]", bytes.len())),
) ).field("identifier", &self.identifier)
.field("identifier", &self.identifier)
.finish() .finish()
} }
} }
impl FontTemplateData { impl FontTemplateData {
pub fn new(identifier: Atom, pub fn new(
font_data: Option<Vec<u8>>) -> Result<FontTemplateData, io::Error> { identifier: Atom,
font_data: Option<Vec<u8>>,
) -> Result<FontTemplateData, io::Error> {
Ok(FontTemplateData { Ok(FontTemplateData {
bytes: font_data, bytes: font_data,
identifier: identifier, identifier: identifier,