mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Format gfx platform #21373
This commit is contained in:
parent
5063ac465b
commit
c57c99d9f7
13 changed files with 496 additions and 372 deletions
|
@ -116,21 +116,18 @@ struct FontFamily {
|
|||
struct FontAlias {
|
||||
from: String,
|
||||
to: String,
|
||||
weight: Option<i32>
|
||||
weight: Option<i32>,
|
||||
}
|
||||
|
||||
struct FontList {
|
||||
families: Vec<FontFamily>,
|
||||
aliases: Vec<FontAlias>
|
||||
aliases: Vec<FontAlias>,
|
||||
}
|
||||
|
||||
impl FontList {
|
||||
fn new() -> FontList {
|
||||
// Possible paths containing the font mapping xml file.
|
||||
let paths = [
|
||||
"/etc/fonts.xml",
|
||||
"/system/etc/system_fonts.xml"
|
||||
];
|
||||
let paths = ["/etc/fonts.xml", "/system/etc/system_fonts.xml"];
|
||||
|
||||
// Try to load and parse paths until one of them success.
|
||||
let mut result = None;
|
||||
|
@ -146,7 +143,7 @@ impl FontList {
|
|||
None => FontList {
|
||||
families: Self::fallback_font_families(),
|
||||
aliases: Vec::new(),
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,25 +151,26 @@ impl FontList {
|
|||
fn from_path(path: &str) -> Option<FontList> {
|
||||
let xml = match Self::load_file(path) {
|
||||
Ok(xml) => xml,
|
||||
_=> { return None; },
|
||||
_ => {
|
||||
return None;
|
||||
},
|
||||
};
|
||||
|
||||
let dom: RcDom = parse_document(RcDom::default(), Default::default())
|
||||
.one(xml);
|
||||
let dom: RcDom = parse_document(RcDom::default(), Default::default()).one(xml);
|
||||
let doc = &dom.document;
|
||||
|
||||
// find familyset root node
|
||||
let children = doc.children.borrow();
|
||||
let familyset = children.iter().find(|child| {
|
||||
match child.data {
|
||||
NodeData::Element { ref name, .. } => &*name.local == "familyset",
|
||||
_ => false,
|
||||
}
|
||||
let familyset = children.iter().find(|child| match child.data {
|
||||
NodeData::Element { ref name, .. } => &*name.local == "familyset",
|
||||
_ => false,
|
||||
});
|
||||
|
||||
let familyset = match familyset {
|
||||
Some(node) => node,
|
||||
_ => { return None; }
|
||||
_ => {
|
||||
return None;
|
||||
},
|
||||
};
|
||||
|
||||
// Parse familyset node
|
||||
|
@ -181,7 +179,11 @@ impl FontList {
|
|||
|
||||
for node in familyset.children.borrow().iter() {
|
||||
match node.data {
|
||||
NodeData::Element { ref name, ref attrs, .. } => {
|
||||
NodeData::Element {
|
||||
ref name,
|
||||
ref attrs,
|
||||
..
|
||||
} => {
|
||||
if &*name.local == "family" {
|
||||
Self::parse_family(&node, attrs, &mut families);
|
||||
} else if &*name.local == "alias" {
|
||||
|
@ -191,13 +193,13 @@ impl FontList {
|
|||
}
|
||||
}
|
||||
},
|
||||
_=> {}
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
Some(FontList {
|
||||
families: families,
|
||||
aliases: aliases
|
||||
aliases: aliases,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -209,17 +211,16 @@ impl FontList {
|
|||
("Droid Sans", "DroidSans.ttf"),
|
||||
];
|
||||
|
||||
alternatives.iter().filter(|item| {
|
||||
Path::new(&Self::font_absolute_path(item.1)).exists()
|
||||
}).map(|item| {
|
||||
FontFamily {
|
||||
alternatives
|
||||
.iter()
|
||||
.filter(|item| Path::new(&Self::font_absolute_path(item.1)).exists())
|
||||
.map(|item| FontFamily {
|
||||
name: item.0.into(),
|
||||
fonts: vec![Font {
|
||||
filename: item.1.into(),
|
||||
weight: None,
|
||||
}]
|
||||
}
|
||||
}). collect()
|
||||
}],
|
||||
}).collect()
|
||||
}
|
||||
|
||||
// All Android fonts are located in /system/fonts
|
||||
|
@ -227,15 +228,14 @@ impl FontList {
|
|||
format!("/system/fonts/{}", filename)
|
||||
}
|
||||
|
||||
fn find_family(&self, name: &str) -> Option<&FontFamily>{
|
||||
fn find_family(&self, name: &str) -> Option<&FontFamily> {
|
||||
self.families.iter().find(|f| f.name == name)
|
||||
}
|
||||
|
||||
fn find_alias(&self, name: &str) -> Option<&FontAlias>{
|
||||
fn find_alias(&self, name: &str) -> Option<&FontAlias> {
|
||||
self.aliases.iter().find(|f| f.from == name)
|
||||
}
|
||||
|
||||
|
||||
fn load_file(path: &str) -> Result<String, io::Error> {
|
||||
let mut file = File::open(path)?;
|
||||
let mut content = String::new();
|
||||
|
@ -253,14 +253,16 @@ impl FontList {
|
|||
// <font weight="300" style="italic">Roboto-LightItalic.ttf</font>
|
||||
// <font weight="400" style="normal">Roboto-Regular.ttf</font>
|
||||
// </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
|
||||
let using_api_17 = familyset.children.borrow().iter().any(|node| {
|
||||
match node.data {
|
||||
let using_api_17 = familyset
|
||||
.children
|
||||
.borrow()
|
||||
.iter()
|
||||
.any(|node| match node.data {
|
||||
NodeData::Element { ref name, .. } => &*name.local == "nameset",
|
||||
_=> false,
|
||||
}
|
||||
});
|
||||
_ => false,
|
||||
});
|
||||
if using_api_17 {
|
||||
Self::parse_family_v17(familyset, out);
|
||||
return;
|
||||
|
@ -269,25 +271,31 @@ impl FontList {
|
|||
// Parse family name
|
||||
let name = match Self::find_attrib("name", attrs) {
|
||||
Some(name) => name,
|
||||
_ => { return; },
|
||||
_ => {
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
let mut fonts = Vec::new();
|
||||
// Parse font variants
|
||||
for node in familyset.children.borrow().iter() {
|
||||
match node.data {
|
||||
NodeData::Element { ref name, ref attrs, .. } => {
|
||||
NodeData::Element {
|
||||
ref name,
|
||||
ref attrs,
|
||||
..
|
||||
} => {
|
||||
if &*name.local == "font" {
|
||||
FontList::parse_font(&node, attrs, &mut fonts);
|
||||
}
|
||||
},
|
||||
_=> {}
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
out.push(FontFamily {
|
||||
name: name,
|
||||
fonts: fonts
|
||||
fonts: fonts,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -308,7 +316,7 @@ impl FontList {
|
|||
// <file>Roboto-BoldItalic.ttf</file>
|
||||
// </fileset>
|
||||
// </family>
|
||||
fn parse_family_v17(familyset: &Node, out:&mut Vec<FontFamily>) {
|
||||
fn parse_family_v17(familyset: &Node, out: &mut Vec<FontFamily>) {
|
||||
let mut nameset = Vec::new();
|
||||
let mut fileset = Vec::new();
|
||||
for node in familyset.children.borrow().iter() {
|
||||
|
@ -320,21 +328,23 @@ impl FontList {
|
|||
Self::collect_contents_with_tag(node, "file", &mut fileset);
|
||||
}
|
||||
},
|
||||
_=> {}
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
// Create a families for each variation
|
||||
for name in nameset {
|
||||
let fonts: Vec<Font> = fileset.iter().map(|f| Font {
|
||||
filename: f.clone(),
|
||||
weight: None,
|
||||
}).collect();
|
||||
let fonts: Vec<Font> = fileset
|
||||
.iter()
|
||||
.map(|f| Font {
|
||||
filename: f.clone(),
|
||||
weight: None,
|
||||
}).collect();
|
||||
|
||||
if !fonts.is_empty() {
|
||||
out.push(FontFamily {
|
||||
name: name,
|
||||
fonts: fonts
|
||||
fonts: fonts,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -342,11 +352,13 @@ impl FontList {
|
|||
|
||||
// Example:
|
||||
// <font weight="100" style="normal">Roboto-Thin.ttf</font>
|
||||
fn parse_font(node: &Node, attrs: &RefCell<Vec<Attribute>>, out:&mut Vec<Font>) {
|
||||
fn parse_font(node: &Node, attrs: &RefCell<Vec<Attribute>>, out: &mut Vec<Font>) {
|
||||
// Parse font filename
|
||||
let filename = match Self::text_content(node) {
|
||||
Some(filename) => filename,
|
||||
_ => { return; }
|
||||
_ => {
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
// Parse font weight
|
||||
|
@ -367,17 +379,21 @@ impl FontList {
|
|||
// <alias name="helvetica" to="sans-serif" />
|
||||
// <alias name="tahoma" to="sans-serif" />
|
||||
// <alias name="verdana" to="sans-serif" />
|
||||
fn parse_alias(attrs: &RefCell<Vec<Attribute>>, out:&mut Vec<FontAlias>) {
|
||||
fn parse_alias(attrs: &RefCell<Vec<Attribute>>, out: &mut Vec<FontAlias>) {
|
||||
// Parse alias name and referenced font
|
||||
let from = match Self::find_attrib("name", attrs) {
|
||||
Some(from) => from,
|
||||
_ => { return; },
|
||||
_ => {
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
// Parse referenced font
|
||||
let to = match Self::find_attrib("to", attrs) {
|
||||
Some(to) => to,
|
||||
_ => { return; },
|
||||
_ => {
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
// Parse optional weight filter
|
||||
|
@ -391,23 +407,28 @@ impl FontList {
|
|||
}
|
||||
|
||||
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> {
|
||||
node.children.borrow().get(0).and_then(|child| {
|
||||
match child.data {
|
||||
node.children
|
||||
.borrow()
|
||||
.get(0)
|
||||
.and_then(|child| match child.data {
|
||||
NodeData::Text { ref contents } => {
|
||||
let mut result = String::new();
|
||||
result.push_str(&contents.borrow());
|
||||
Some(result)
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
})
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
fn collect_contents_with_tag(node: &Node, tag: &str, out:&mut Vec<String>) {
|
||||
fn collect_contents_with_tag(node: &Node, tag: &str, out: &mut Vec<String>) {
|
||||
for child in node.children.borrow().iter() {
|
||||
match child.data {
|
||||
NodeData::Element { ref name, .. } => {
|
||||
|
@ -417,14 +438,17 @@ impl FontList {
|
|||
}
|
||||
}
|
||||
},
|
||||
_=> {}
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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)
|
||||
where F: FnMut(String)
|
||||
where
|
||||
F: FnMut(String),
|
||||
{
|
||||
if let Some(family) = FONT_LIST.find_family(family_name) {
|
||||
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))
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -473,46 +498,44 @@ pub fn system_default_family(generic_name: &str) -> Option<String> {
|
|||
|
||||
// Based on gfxAndroidPlatform::GetCommonFallbackFonts() in Gecko
|
||||
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()) {
|
||||
match block {
|
||||
UnicodeBlock::Armenian => {
|
||||
families.push("Droid Sans Armenian");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Hebrew => {
|
||||
families.push("Droid Sans Hebrew");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Arabic => {
|
||||
families.push("Droid Sans Arabic");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Devanagari => {
|
||||
families.push("Noto Sans Devanagari");
|
||||
families.push("Droid Sans Devanagari");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Tamil => {
|
||||
families.push("Noto Sans Tamil");
|
||||
families.push("Droid Sans Tamil");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Thai => {
|
||||
families.push("Noto Sans Thai");
|
||||
families.push("Droid Sans Thai");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Georgian |
|
||||
UnicodeBlock::GeorgianSupplement => {
|
||||
UnicodeBlock::Georgian | UnicodeBlock::GeorgianSupplement => {
|
||||
families.push("Droid Sans Georgian");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Ethiopic |
|
||||
UnicodeBlock::EthiopicSupplement => {
|
||||
UnicodeBlock::Ethiopic | UnicodeBlock::EthiopicSupplement => {
|
||||
families.push("Droid Sans Ethiopic");
|
||||
}
|
||||
},
|
||||
|
||||
_ => {
|
||||
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("Droid Sans Japanese");
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -98,14 +98,21 @@ fn create_face(
|
|||
let face_index = 0 as FT_Long;
|
||||
|
||||
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 {
|
||||
// This will trigger a synchronous file read in the layout thread, which we may want to
|
||||
// revisit at some point. See discussion here:
|
||||
//
|
||||
// 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)
|
||||
};
|
||||
|
||||
|
@ -122,25 +129,27 @@ fn create_face(
|
|||
}
|
||||
|
||||
impl FontHandleMethods for FontHandle {
|
||||
fn new_from_template(fctx: &FontContextHandle,
|
||||
template: Arc<FontTemplateData>,
|
||||
pt_size: Option<Au>)
|
||||
-> Result<FontHandle, ()> {
|
||||
fn new_from_template(
|
||||
fctx: &FontContextHandle,
|
||||
template: Arc<FontTemplateData>,
|
||||
pt_size: Option<Au>,
|
||||
) -> Result<FontHandle, ()> {
|
||||
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 mut handle = FontHandle {
|
||||
face: face,
|
||||
font_data: template.clone(),
|
||||
handle: fctx.clone(),
|
||||
can_do_fast_shaping: false,
|
||||
face: face,
|
||||
font_data: template.clone(),
|
||||
handle: fctx.clone(),
|
||||
can_do_fast_shaping: false,
|
||||
};
|
||||
// TODO (#11310): Implement basic support for GPOS and GSUB.
|
||||
handle.can_do_fast_shaping = handle.has_table(KERN) &&
|
||||
!handle.has_table(GPOS) &&
|
||||
!handle.has_table(GSUB);
|
||||
handle.can_do_fast_shaping =
|
||||
handle.has_table(KERN) && !handle.has_table(GPOS) && !handle.has_table(GSUB);
|
||||
Ok(handle)
|
||||
}
|
||||
|
||||
|
@ -203,7 +212,7 @@ impl FontHandleMethods for FontHandle {
|
|||
7 => FontStretchKeyword::Expanded,
|
||||
8 => FontStretchKeyword::ExtraExpanded,
|
||||
9 => FontStretchKeyword::UltraExpanded,
|
||||
_ => FontStretchKeyword::Normal
|
||||
_ => FontStretchKeyword::Normal,
|
||||
}
|
||||
} else {
|
||||
FontStretchKeyword::Normal
|
||||
|
@ -218,20 +227,26 @@ impl FontHandleMethods for FontHandle {
|
|||
if idx != 0 as FT_UInt {
|
||||
Some(idx as GlyphId)
|
||||
} else {
|
||||
debug!("Invalid codepoint: U+{:04X} ('{}')", codepoint as u32, codepoint);
|
||||
debug!(
|
||||
"Invalid codepoint: U+{:04X} ('{}')",
|
||||
codepoint as u32, codepoint
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn glyph_h_kerning(&self, first_glyph: GlyphId, second_glyph: GlyphId)
|
||||
-> FractionalPixel {
|
||||
fn glyph_h_kerning(&self, first_glyph: GlyphId, second_glyph: GlyphId) -> FractionalPixel {
|
||||
assert!(!self.face.is_null());
|
||||
let mut delta = FT_Vector { x: 0, y: 0 };
|
||||
unsafe {
|
||||
FT_Get_Kerning(self.face, first_glyph, second_glyph,
|
||||
FT_Kerning_Mode::FT_KERNING_DEFAULT as FT_UInt,
|
||||
&mut delta);
|
||||
FT_Get_Kerning(
|
||||
self.face,
|
||||
first_glyph,
|
||||
second_glyph,
|
||||
FT_Kerning_Mode::FT_KERNING_DEFAULT as FT_UInt,
|
||||
&mut delta,
|
||||
);
|
||||
}
|
||||
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> {
|
||||
assert!(!self.face.is_null());
|
||||
unsafe {
|
||||
let res = FT_Load_Glyph(self.face,
|
||||
glyph as FT_UInt,
|
||||
GLYPH_LOAD_FLAGS);
|
||||
let res = FT_Load_Glyph(self.face, glyph as FT_UInt, GLYPH_LOAD_FLAGS);
|
||||
if succeeded(res) {
|
||||
let void_glyph = (*self.face).glyph;
|
||||
let slot: FT_GlyphSlot = mem::transmute(void_glyph);
|
||||
|
@ -291,23 +304,24 @@ impl FontHandleMethods for FontHandle {
|
|||
x_height = self.font_units_to_au(os2.sx_height as f64);
|
||||
}
|
||||
|
||||
let average_advance = self.glyph_index('0')
|
||||
.and_then(|idx| self.glyph_h_advance(idx))
|
||||
.map_or(max_advance, |advance| self.font_units_to_au(advance));
|
||||
let average_advance = self
|
||||
.glyph_index('0')
|
||||
.and_then(|idx| self.glyph_h_advance(idx))
|
||||
.map_or(max_advance, |advance| self.font_units_to_au(advance));
|
||||
|
||||
let metrics = FontMetrics {
|
||||
underline_size: underline_size,
|
||||
underline_size: underline_size,
|
||||
underline_offset: underline_offset,
|
||||
strikeout_size: strikeout_size,
|
||||
strikeout_size: strikeout_size,
|
||||
strikeout_offset: strikeout_offset,
|
||||
leading: leading,
|
||||
x_height: x_height,
|
||||
em_size: em_size,
|
||||
ascent: ascent,
|
||||
descent: -descent, // linux font's seem to use the opposite sign from mac
|
||||
max_advance: max_advance,
|
||||
average_advance: average_advance,
|
||||
line_gap: height,
|
||||
leading: leading,
|
||||
x_height: x_height,
|
||||
em_size: em_size,
|
||||
ascent: ascent,
|
||||
descent: -descent, // linux font's seem to use the opposite sign from mac
|
||||
max_advance: max_advance,
|
||||
average_advance: average_advance,
|
||||
line_gap: height,
|
||||
};
|
||||
|
||||
debug!("Font metrics (@{}px): {:?}", em_size.to_f32_px(), metrics);
|
||||
|
@ -320,13 +334,25 @@ impl FontHandleMethods for FontHandle {
|
|||
unsafe {
|
||||
// Get the length
|
||||
let mut len = 0;
|
||||
if !succeeded(FT_Load_Sfnt_Table(self.face, tag, 0, ptr::null_mut(), &mut len)) {
|
||||
return None
|
||||
if !succeeded(FT_Load_Sfnt_Table(
|
||||
self.face,
|
||||
tag,
|
||||
0,
|
||||
ptr::null_mut(),
|
||||
&mut len,
|
||||
)) {
|
||||
return None;
|
||||
}
|
||||
// Get the bytes
|
||||
let mut buf = vec![0u8; len as usize];
|
||||
if !succeeded(FT_Load_Sfnt_Table(self.face, tag, 0, buf.as_mut_ptr(), &mut len)) {
|
||||
return None
|
||||
if !succeeded(FT_Load_Sfnt_Table(
|
||||
self.face,
|
||||
tag,
|
||||
0,
|
||||
buf.as_mut_ptr(),
|
||||
&mut len,
|
||||
)) {
|
||||
return None;
|
||||
}
|
||||
Some(FontTable { buffer: buf })
|
||||
}
|
||||
|
@ -338,25 +364,33 @@ impl FontHandleMethods for FontHandle {
|
|||
}
|
||||
|
||||
impl<'a> FontHandle {
|
||||
fn set_char_size(face: FT_Face, pt_size: Au) -> Result<(), ()>{
|
||||
fn set_char_size(face: FT_Face, pt_size: Au) -> Result<(), ()> {
|
||||
let char_size = pt_size.to_f64_px() * 64.0 + 0.5;
|
||||
|
||||
unsafe {
|
||||
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 {
|
||||
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 {
|
||||
unsafe {
|
||||
&mut (*self.face)
|
||||
}
|
||||
unsafe { &mut (*self.face) }
|
||||
}
|
||||
|
||||
fn font_units_to_au(&self, value: f64) -> Au {
|
||||
|
@ -378,11 +412,12 @@ impl<'a> FontHandle {
|
|||
|
||||
fn os2_table(&self) -> Option<OS2Table> {
|
||||
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;
|
||||
|
||||
if !valid {
|
||||
return None
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(OS2Table {
|
||||
|
|
|
@ -23,10 +23,10 @@ pub struct User {
|
|||
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 {
|
||||
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
|
||||
let actual_size = usable_size(ptr);
|
||||
let user = (*mem).user as *mut User;
|
||||
(*user).size += actual_size;
|
||||
|
@ -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 {
|
||||
let actual_size = usable_size(ptr);
|
||||
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,
|
||||
old_ptr: *mut c_void) -> *mut c_void {
|
||||
extern "C" fn ft_realloc(
|
||||
mem: FT_Memory,
|
||||
_old_size: c_long,
|
||||
new_req_size: c_long,
|
||||
old_ptr: *mut c_void,
|
||||
) -> *mut c_void {
|
||||
unsafe {
|
||||
let old_actual_size = usable_size(old_ptr);
|
||||
let new_ptr = realloc(old_ptr as *mut _, new_req_size as usize);
|
||||
|
@ -108,9 +112,7 @@ impl MallocSizeOf for FontContextHandle {
|
|||
|
||||
impl FontContextHandle {
|
||||
pub fn new() -> FontContextHandle {
|
||||
let user = Box::into_raw(Box::new(User {
|
||||
size: 0,
|
||||
}));
|
||||
let user = Box::into_raw(Box::new(User { size: 0 }));
|
||||
let mem = Box::into_raw(Box::new(FT_MemoryRec_ {
|
||||
user: user as *mut c_void,
|
||||
alloc: Some(ft_alloc),
|
||||
|
@ -121,12 +123,18 @@ impl FontContextHandle {
|
|||
let mut ctx: FT_Library = ptr::null_mut();
|
||||
|
||||
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);
|
||||
|
||||
FontContextHandle {
|
||||
ctx: Rc::new(FreeTypeLibraryHandle { ctx: ctx, mem: mem, user: user }),
|
||||
ctx: Rc::new(FreeTypeLibraryHandle {
|
||||
ctx: ctx,
|
||||
mem: mem,
|
||||
user: user,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,10 @@ static FC_FILE: &'static [u8] = b"file\0";
|
|||
static FC_INDEX: &'static [u8] = b"index\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 {
|
||||
let config = FcConfigGetCurrent();
|
||||
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 format: *mut FcChar8 = ptr::null_mut();
|
||||
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;
|
||||
}
|
||||
|
||||
// Skip bitmap fonts. They aren't supported by FreeType.
|
||||
let fontformat = c_str_to_string(format as *const c_char);
|
||||
if fontformat != "TrueType" &&
|
||||
fontformat != "CFF" &&
|
||||
fontformat != "Type 1" {
|
||||
if fontformat != "TrueType" && fontformat != "CFF" && fontformat != "Type 1" {
|
||||
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);
|
||||
callback(family_name);
|
||||
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)
|
||||
where F: FnMut(String)
|
||||
where
|
||||
F: FnMut(String),
|
||||
{
|
||||
debug!("getting variations for {}", family_name);
|
||||
unsafe {
|
||||
|
@ -62,7 +68,11 @@ pub fn for_each_variation<F>(family_name: &str, mut callback: F)
|
|||
assert!(!pattern.is_null());
|
||||
let family_name_c = CString::new(family_name).unwrap();
|
||||
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);
|
||||
|
||||
let object_set = FcObjectSetCreate();
|
||||
|
@ -85,7 +95,8 @@ pub fn for_each_variation<F>(family_name: &str, mut callback: F)
|
|||
panic!();
|
||||
};
|
||||
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 {
|
||||
index
|
||||
} else {
|
||||
|
@ -119,7 +130,12 @@ pub fn system_default_family(generic_name: &str) -> Option<String> {
|
|||
|
||||
let family_name = if result == FcResultMatch {
|
||||
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);
|
||||
FcPatternDestroy(family_match);
|
||||
Some(result)
|
||||
|
@ -136,12 +152,7 @@ pub static SANS_SERIF_FONT_FAMILY: &'static str = "DejaVu Sans";
|
|||
|
||||
// Based on gfxPlatformGtk::GetCommonFallbackFonts() in Gecko
|
||||
pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
|
||||
let mut families = vec!(
|
||||
"DejaVu Serif",
|
||||
"FreeSerif",
|
||||
"DejaVu Sans",
|
||||
"FreeSans",
|
||||
);
|
||||
let mut families = vec!["DejaVu Serif", "FreeSerif", "DejaVu Sans", "FreeSans"];
|
||||
|
||||
if let Some(codepoint) = codepoint {
|
||||
if is_cjk(codepoint) {
|
||||
|
|
|
@ -15,7 +15,6 @@ use webrender_api::NativeFontHandle;
|
|||
#[derive(Deserialize, Serialize)]
|
||||
pub struct FontTemplateData {
|
||||
// If you add members here, review the Debug impl below
|
||||
|
||||
pub bytes: Option<Vec<u8>>,
|
||||
pub identifier: Atom,
|
||||
}
|
||||
|
@ -23,9 +22,11 @@ pub struct FontTemplateData {
|
|||
impl fmt::Debug for FontTemplateData {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.debug_struct("FontTemplateData")
|
||||
.field("bytes", &self.bytes.as_ref().map(|b| format!("[{} bytes]", b.len())))
|
||||
.field("identifier", &self.identifier)
|
||||
.finish()
|
||||
.field(
|
||||
"bytes",
|
||||
&self.bytes.as_ref().map(|b| format!("[{} bytes]", b.len())),
|
||||
).field("identifier", &self.identifier)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/// Implementation of Quartz (CoreGraphics) fonts.
|
||||
|
||||
use app_units::Au;
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
use core_foundation::base::CFIndex;
|
||||
|
@ -111,8 +110,8 @@ impl FontHandle {
|
|||
return None;
|
||||
}
|
||||
|
||||
let pt_per_font_unit = self.ctfont.pt_size() as f64 /
|
||||
self.ctfont.units_per_em() as f64;
|
||||
let pt_per_font_unit =
|
||||
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);
|
||||
}
|
||||
start = end;
|
||||
|
@ -160,15 +159,15 @@ impl fmt::Debug for CachedKernTable {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl FontHandleMethods for FontHandle {
|
||||
fn new_from_template(_fctx: &FontContextHandle,
|
||||
template: Arc<FontTemplateData>,
|
||||
pt_size: Option<Au>)
|
||||
-> Result<FontHandle, ()> {
|
||||
fn new_from_template(
|
||||
_fctx: &FontContextHandle,
|
||||
template: Arc<FontTemplateData>,
|
||||
pt_size: Option<Au>,
|
||||
) -> Result<FontHandle, ()> {
|
||||
let size = match pt_size {
|
||||
Some(s) => s.to_f64_px(),
|
||||
None => 0.0
|
||||
None => 0.0,
|
||||
};
|
||||
match template.ctfont(size) {
|
||||
Some(ref ctfont) => {
|
||||
|
@ -181,13 +180,11 @@ impl FontHandleMethods for FontHandle {
|
|||
handle.h_kern_subtable = handle.find_h_kern_subtable();
|
||||
// TODO (#11310): Implement basic support for GPOS and GSUB.
|
||||
handle.can_do_fast_shaping = handle.h_kern_subtable.is_some() &&
|
||||
handle.table_for_tag(GPOS).is_none() &&
|
||||
handle.table_for_tag(GSUB).is_none();
|
||||
handle.table_for_tag(GPOS).is_none() &&
|
||||
handle.table_for_tag(GSUB).is_none();
|
||||
Ok(handle)
|
||||
}
|
||||
None => {
|
||||
Err(())
|
||||
}
|
||||
},
|
||||
None => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -213,13 +210,13 @@ impl FontHandleMethods for FontHandle {
|
|||
}
|
||||
|
||||
fn boldness(&self) -> FontWeight {
|
||||
let normalized = self.ctfont.all_traits().normalized_weight(); // [-1.0, 1.0]
|
||||
// TODO(emilio): It may make sense to make this range [.01, 10.0], to
|
||||
// align with css-fonts-4's range of [1, 1000].
|
||||
let normalized = self.ctfont.all_traits().normalized_weight(); // [-1.0, 1.0]
|
||||
// TODO(emilio): It may make sense to make this range [.01, 10.0], to
|
||||
// align with css-fonts-4's range of [1, 1000].
|
||||
let normalized = if normalized <= 0.0 {
|
||||
4.0 + normalized * 3.0 // [1.0, 4.0]
|
||||
4.0 + normalized * 3.0 // [1.0, 4.0]
|
||||
} else {
|
||||
4.0 + normalized * 5.0 // [4.0, 9.0]
|
||||
4.0 + normalized * 5.0 // [4.0, 9.0]
|
||||
}; // [1.0, 9.0], centered on 4.0
|
||||
FontWeight(normalized as f32 * 100.)
|
||||
}
|
||||
|
@ -228,7 +225,7 @@ impl FontHandleMethods for FontHandle {
|
|||
use style::values::computed::Percentage;
|
||||
use style::values::generics::NonNegative;
|
||||
|
||||
let normalized = self.ctfont.all_traits().normalized_width(); // [-1.0, 1.0]
|
||||
let normalized = self.ctfont.all_traits().normalized_width(); // [-1.0, 1.0]
|
||||
FontStretch(NonNegative(Percentage(normalized as f32 + 1.0)))
|
||||
}
|
||||
|
||||
|
@ -237,9 +234,9 @@ impl FontHandleMethods for FontHandle {
|
|||
let mut glyphs: [CGGlyph; 1] = [0 as CGGlyph];
|
||||
let count: CFIndex = 1;
|
||||
|
||||
let result = self.ctfont.get_glyphs_for_characters(&characters[0],
|
||||
&mut glyphs[0],
|
||||
count);
|
||||
let result = self
|
||||
.ctfont
|
||||
.get_glyphs_for_characters(&characters[0], &mut glyphs[0], count);
|
||||
|
||||
if !result {
|
||||
// No glyph for this character
|
||||
|
@ -265,10 +262,12 @@ impl FontHandleMethods for FontHandle {
|
|||
|
||||
fn glyph_h_advance(&self, glyph: GlyphId) -> Option<FractionalPixel> {
|
||||
let glyphs = [glyph as CGGlyph];
|
||||
let advance = self.ctfont.get_advances_for_glyphs(kCTFontDefaultOrientation,
|
||||
&glyphs[0],
|
||||
ptr::null_mut(),
|
||||
1);
|
||||
let advance = self.ctfont.get_advances_for_glyphs(
|
||||
kCTFontDefaultOrientation,
|
||||
&glyphs[0],
|
||||
ptr::null_mut(),
|
||||
1,
|
||||
);
|
||||
Some(advance as FractionalPixel)
|
||||
}
|
||||
|
||||
|
@ -283,39 +282,42 @@ impl FontHandleMethods for FontHandle {
|
|||
let line_gap = (ascent + descent + leading + 0.5).floor();
|
||||
|
||||
let max_advance_width = au_from_pt(bounding_rect.size.width as f64);
|
||||
let average_advance = self.glyph_index('0')
|
||||
.and_then(|idx| self.glyph_h_advance(idx))
|
||||
.map(Au::from_f64_px)
|
||||
.unwrap_or(max_advance_width);
|
||||
let average_advance = self
|
||||
.glyph_index('0')
|
||||
.and_then(|idx| self.glyph_h_advance(idx))
|
||||
.map(Au::from_f64_px)
|
||||
.unwrap_or(max_advance_width);
|
||||
|
||||
let metrics = FontMetrics {
|
||||
underline_size: au_from_pt(self.ctfont.underline_thickness() as f64),
|
||||
underline_size: au_from_pt(self.ctfont.underline_thickness() as f64),
|
||||
// TODO(Issue #201): underline metrics are not reliable. Have to pull out of font table
|
||||
// directly.
|
||||
//
|
||||
// see also: https://bugs.webkit.org/show_bug.cgi?id=16768
|
||||
// see also: https://bugreports.qt-project.org/browse/QTBUG-13364
|
||||
underline_offset: au_from_pt(self.ctfont.underline_position() as f64),
|
||||
strikeout_size: Au(0), // FIXME(Issue #942)
|
||||
strikeout_size: Au(0), // FIXME(Issue #942)
|
||||
strikeout_offset: Au(0), // FIXME(Issue #942)
|
||||
leading: au_from_pt(leading),
|
||||
x_height: au_from_pt((self.ctfont.x_height() as f64) * scale),
|
||||
em_size: em_size,
|
||||
ascent: au_from_pt(ascent * scale),
|
||||
descent: au_from_pt(descent * scale),
|
||||
max_advance: max_advance_width,
|
||||
average_advance: average_advance,
|
||||
line_gap: Au::from_f64_px(line_gap),
|
||||
leading: au_from_pt(leading),
|
||||
x_height: au_from_pt((self.ctfont.x_height() as f64) * scale),
|
||||
em_size: em_size,
|
||||
ascent: au_from_pt(ascent * scale),
|
||||
descent: au_from_pt(descent * scale),
|
||||
max_advance: max_advance_width,
|
||||
average_advance: average_advance,
|
||||
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
|
||||
}
|
||||
|
||||
fn table_for_tag(&self, tag: FontTableTag) -> Option<FontTable> {
|
||||
let result: Option<CFData> = self.ctfont.get_font_table(tag);
|
||||
result.and_then(|data| {
|
||||
Some(FontTable::wrap(data))
|
||||
})
|
||||
result.and_then(|data| Some(FontTable::wrap(data)))
|
||||
}
|
||||
|
||||
fn identifier(&self) -> Atom {
|
||||
|
|
|
@ -6,7 +6,7 @@ use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FontContextHandle {
|
||||
ctx: ()
|
||||
ctx: (),
|
||||
}
|
||||
|
||||
impl FontContextHandle {
|
||||
|
|
|
@ -6,14 +6,20 @@ use core_text;
|
|||
use text::util::unicode_plane;
|
||||
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();
|
||||
for family_name in family_names.iter() {
|
||||
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);
|
||||
|
||||
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
|
||||
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 {
|
||||
match unicode_plane(codepoint) {
|
||||
|
@ -45,66 +51,65 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
|
|||
UnicodeBlock::Thaana |
|
||||
UnicodeBlock::NKo => {
|
||||
families.push("Geeza Pro");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Devanagari => {
|
||||
families.push("Devanagari Sangam MN");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Gurmukhi => {
|
||||
families.push("Gurmukhi MN");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Gujarati => {
|
||||
families.push("Gujarati Sangam MN");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Tamil => {
|
||||
families.push("Tamil MN");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Lao => {
|
||||
families.push("Lao MN");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Tibetan => {
|
||||
families.push("Songti SC");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Myanmar => {
|
||||
families.push("Myanmar MN");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Ethiopic |
|
||||
UnicodeBlock::EthiopicSupplement |
|
||||
UnicodeBlock::EthiopicExtended |
|
||||
UnicodeBlock::EthiopicExtendedA => {
|
||||
families.push("Kefa");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Cherokee => {
|
||||
families.push("Plantagenet Cherokee");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::UnifiedCanadianAboriginalSyllabics |
|
||||
UnicodeBlock::UnifiedCanadianAboriginalSyllabicsExtended => {
|
||||
families.push("Euphemia UCAS");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Mongolian |
|
||||
UnicodeBlock::YiSyllables |
|
||||
UnicodeBlock::YiRadicals => {
|
||||
families.push("STHeiti");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Khmer |
|
||||
UnicodeBlock::KhmerSymbols => {
|
||||
UnicodeBlock::Khmer | UnicodeBlock::KhmerSymbols => {
|
||||
families.push("Khmer MN");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::TaiLe => {
|
||||
families.push("Microsoft Tai Le");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::GeneralPunctuation |
|
||||
UnicodeBlock::SuperscriptsandSubscripts |
|
||||
|
@ -134,11 +139,11 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
|
|||
families.push("Apple Symbols");
|
||||
families.push("Menlo");
|
||||
families.push("STIXGeneral");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::BraillePatterns => {
|
||||
families.push("Apple Braille");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Bopomofo |
|
||||
UnicodeBlock::HangulCompatibilityJamo |
|
||||
|
@ -147,7 +152,7 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
|
|||
UnicodeBlock::CJKStrokes |
|
||||
UnicodeBlock::KatakanaPhoneticExtensions => {
|
||||
families.push("Hiragino Sans GB");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::YijingHexagramSymbols |
|
||||
UnicodeBlock::CyrillicExtendedB |
|
||||
|
@ -158,27 +163,27 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
|
|||
UnicodeBlock::HalfwidthandFullwidthForms |
|
||||
UnicodeBlock::Specials => {
|
||||
families.push("Apple Symbols");
|
||||
}
|
||||
},
|
||||
|
||||
_ => {}
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// https://en.wikipedia.org/wiki/Plane_(Unicode)#Supplementary_Multilingual_Plane
|
||||
1 => {
|
||||
families.push("Apple Symbols");
|
||||
families.push("STIXGeneral");
|
||||
}
|
||||
},
|
||||
|
||||
// https://en.wikipedia.org/wiki/Plane_(Unicode)#Supplementary_Ideographic_Plane
|
||||
2 => {
|
||||
// Systems with MS Office may have these fonts
|
||||
families.push("MingLiU-ExtB");
|
||||
families.push("SimSun-ExtB");
|
||||
}
|
||||
},
|
||||
|
||||
_ => {}
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@ use webrender_api::NativeFontHandle;
|
|||
#[derive(Deserialize, Serialize)]
|
||||
pub struct FontTemplateData {
|
||||
// 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
|
||||
/// `CTFont` instances over and over. It can always be recreated from the `identifier` and/or
|
||||
/// `font_data` fields.
|
||||
|
@ -38,21 +37,21 @@ pub struct FontTemplateData {
|
|||
ctfont: CachedCTFont,
|
||||
|
||||
pub identifier: Atom,
|
||||
pub font_data: Option<Arc<Vec<u8>>>
|
||||
pub font_data: Option<Arc<Vec<u8>>>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for FontTemplateData {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.debug_struct("FontTemplateData")
|
||||
.field("ctfont", &self.ctfont)
|
||||
.field("identifier", &self.identifier)
|
||||
.field(
|
||||
"font_data",
|
||||
&self.font_data
|
||||
.field("ctfont", &self.ctfont)
|
||||
.field("identifier", &self.identifier)
|
||||
.field(
|
||||
"font_data",
|
||||
&self
|
||||
.font_data
|
||||
.as_ref()
|
||||
.map(|bytes| format!("[{} bytes]", bytes.len()))
|
||||
)
|
||||
.finish()
|
||||
.map(|bytes| format!("[{} bytes]", bytes.len())),
|
||||
).finish()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,7 +63,7 @@ impl FontTemplateData {
|
|||
Ok(FontTemplateData {
|
||||
ctfont: CachedCTFont(Mutex::new(HashMap::new())),
|
||||
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 {
|
||||
Ok(cgfont) => {
|
||||
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(),
|
||||
};
|
||||
if let Some(ctfont) = ctfont {
|
||||
|
@ -104,16 +103,23 @@ impl FontTemplateData {
|
|||
return font_data;
|
||||
}
|
||||
|
||||
let path = ServoUrl::parse(&*self.ctfont(0.0)
|
||||
.expect("No Core Text font available!")
|
||||
.url()
|
||||
.expect("No URL for Core Text font!")
|
||||
.get_string()
|
||||
.to_string()).expect("Couldn't parse Core Text font URL!")
|
||||
.as_url().to_file_path()
|
||||
.expect("Core Text font didn't name a path!");
|
||||
let path = ServoUrl::parse(
|
||||
&*self
|
||||
.ctfont(0.0)
|
||||
.expect("No Core Text font available!")
|
||||
.url()
|
||||
.expect("No URL for Core Text font!")
|
||||
.get_string()
|
||||
.to_string(),
|
||||
).expect("Couldn't parse Core Text font URL!")
|
||||
.as_url()
|
||||
.to_file_path()
|
||||
.expect("Core Text font didn't name a path!");
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -125,7 +131,8 @@ impl FontTemplateData {
|
|||
|
||||
/// Returns the native font that underlies this font template, if applicable.
|
||||
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 {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for CachedCTFont {
|
||||
fn deserialize<D>(deserializer: D) -> Result<CachedCTFont, D::Error>
|
||||
where D: Deserializer<'de> {
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct NoneOptionVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for NoneOptionVisitor {
|
||||
|
@ -158,7 +170,10 @@ impl<'de> Deserialize<'de> for CachedCTFont {
|
|||
}
|
||||
|
||||
#[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())))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,9 @@ mod freetype {
|
|||
/// Creates a String from the given null-terminated buffer.
|
||||
/// Panics if the buffer does not contain UTF-8.
|
||||
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;
|
||||
|
|
|
@ -27,10 +27,18 @@ use text::glyph::GlyphId;
|
|||
use truetype;
|
||||
|
||||
// 1em = 12pt = 16px, assuming 72 points per inch and 96 px per inch
|
||||
fn pt_to_px(pt: f64) -> f64 { pt / 72. * 96. }
|
||||
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)) }
|
||||
fn pt_to_px(pt: f64) -> f64 {
|
||||
pt / 72. * 96.
|
||||
}
|
||||
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 {
|
||||
data: Vec<u8>,
|
||||
|
@ -38,7 +46,9 @@ pub struct FontTable {
|
|||
|
||||
impl FontTable {
|
||||
pub fn wrap(data: &[u8]) -> FontTable {
|
||||
FontTable { data: data.to_vec() }
|
||||
FontTable {
|
||||
data: data.to_vec(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,7 +149,7 @@ impl FontInfo {
|
|||
} else {
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let mut os2_table_cursor = Cursor::new(os2_table_bytes.as_ref().unwrap());
|
||||
|
@ -163,18 +173,20 @@ impl FontInfo {
|
|||
|
||||
let weight = StyleFontWeight(weight_val as f32);
|
||||
|
||||
let stretch = StyleFontStretch(NonNegative(match min(9, max(1, width_val)) {
|
||||
1 => FontStretchKeyword::UltraCondensed,
|
||||
2 => FontStretchKeyword::ExtraCondensed,
|
||||
3 => FontStretchKeyword::Condensed,
|
||||
4 => FontStretchKeyword::SemiCondensed,
|
||||
5 => FontStretchKeyword::Normal,
|
||||
6 => FontStretchKeyword::SemiExpanded,
|
||||
7 => FontStretchKeyword::Expanded,
|
||||
8 => FontStretchKeyword::ExtraExpanded,
|
||||
9 => FontStretchKeyword::UltraExpanded,
|
||||
_ => return Err(()),
|
||||
}.compute()));
|
||||
let stretch = StyleFontStretch(NonNegative(
|
||||
match min(9, max(1, width_val)) {
|
||||
1 => FontStretchKeyword::UltraCondensed,
|
||||
2 => FontStretchKeyword::ExtraCondensed,
|
||||
3 => FontStretchKeyword::Condensed,
|
||||
4 => FontStretchKeyword::SemiCondensed,
|
||||
5 => FontStretchKeyword::Normal,
|
||||
6 => FontStretchKeyword::SemiExpanded,
|
||||
7 => FontStretchKeyword::Expanded,
|
||||
8 => FontStretchKeyword::ExtraExpanded,
|
||||
9 => FontStretchKeyword::UltraExpanded,
|
||||
_ => return Err(()),
|
||||
}.compute(),
|
||||
));
|
||||
|
||||
let style = if italic_bool {
|
||||
GenericFontStyle::Italic
|
||||
|
@ -212,18 +224,20 @@ impl FontInfo {
|
|||
// slightly blacker black
|
||||
FontWeight::ExtraBlack => 1000.,
|
||||
});
|
||||
let stretch = StyleFontStretch(NonNegative(match font.stretch() {
|
||||
FontStretch::Undefined => FontStretchKeyword::Normal,
|
||||
FontStretch::UltraCondensed => FontStretchKeyword::UltraCondensed,
|
||||
FontStretch::ExtraCondensed => FontStretchKeyword::ExtraCondensed,
|
||||
FontStretch::Condensed => FontStretchKeyword::Condensed,
|
||||
FontStretch::SemiCondensed => FontStretchKeyword::SemiCondensed,
|
||||
FontStretch::Normal => FontStretchKeyword::Normal,
|
||||
FontStretch::SemiExpanded => FontStretchKeyword::SemiExpanded,
|
||||
FontStretch::Expanded => FontStretchKeyword::Expanded,
|
||||
FontStretch::ExtraExpanded => FontStretchKeyword::ExtraExpanded,
|
||||
FontStretch::UltraExpanded => FontStretchKeyword::UltraExpanded,
|
||||
}.compute()));
|
||||
let stretch = StyleFontStretch(NonNegative(
|
||||
match font.stretch() {
|
||||
FontStretch::Undefined => FontStretchKeyword::Normal,
|
||||
FontStretch::UltraCondensed => FontStretchKeyword::UltraCondensed,
|
||||
FontStretch::ExtraCondensed => FontStretchKeyword::ExtraCondensed,
|
||||
FontStretch::Condensed => FontStretchKeyword::Condensed,
|
||||
FontStretch::SemiCondensed => FontStretchKeyword::SemiCondensed,
|
||||
FontStretch::Normal => FontStretchKeyword::Normal,
|
||||
FontStretch::SemiExpanded => FontStretchKeyword::SemiExpanded,
|
||||
FontStretch::Expanded => FontStretchKeyword::Expanded,
|
||||
FontStretch::ExtraExpanded => FontStretchKeyword::ExtraExpanded,
|
||||
FontStretch::UltraExpanded => FontStretchKeyword::UltraExpanded,
|
||||
}.compute(),
|
||||
));
|
||||
|
||||
Ok(FontInfo {
|
||||
family_name: font.family_name(),
|
||||
|
@ -246,13 +260,14 @@ pub struct FontHandle {
|
|||
scaled_du_to_px: f32,
|
||||
}
|
||||
|
||||
impl FontHandle {
|
||||
}
|
||||
impl FontHandle {}
|
||||
|
||||
impl FontHandleMethods for FontHandle {
|
||||
fn new_from_template(_: &FontContextHandle, template: Arc<FontTemplateData>, pt_size: Option<Au>)
|
||||
-> Result<Self, ()>
|
||||
{
|
||||
fn new_from_template(
|
||||
_: &FontContextHandle,
|
||||
template: Arc<FontTemplateData>,
|
||||
pt_size: Option<Au>,
|
||||
) -> Result<Self, ()> {
|
||||
let (info, face) = if let Some(ref raw_font) = template.bytes {
|
||||
let font_file = FontFile::new_from_data(&raw_font);
|
||||
if font_file.is_none() {
|
||||
|
@ -260,7 +275,9 @@ impl FontHandleMethods for FontHandle {
|
|||
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)?;
|
||||
(info, face)
|
||||
} else {
|
||||
|
@ -350,32 +367,34 @@ impl FontHandleMethods for FontHandle {
|
|||
let dm = self.face.metrics();
|
||||
|
||||
let au_from_du = |du| -> Au { Au::from_f32_px(du as f32 * self.du_to_px) };
|
||||
let au_from_du_s = |du| -> Au { Au:: from_f32_px(du as f32 * self.scaled_du_to_px) };
|
||||
let au_from_du_s = |du| -> Au { Au::from_f32_px(du as f32 * self.scaled_du_to_px) };
|
||||
|
||||
// anything that we calculate and don't just pull out of self.face.metrics
|
||||
// is pulled out here for clarity
|
||||
let leading = dm.ascent - dm.capHeight;
|
||||
|
||||
let metrics = FontMetrics {
|
||||
underline_size: au_from_du(dm.underlineThickness as i32),
|
||||
underline_size: au_from_du(dm.underlineThickness as i32),
|
||||
underline_offset: au_from_du_s(dm.underlinePosition as i32),
|
||||
strikeout_size: au_from_du(dm.strikethroughThickness as i32),
|
||||
strikeout_size: au_from_du(dm.strikethroughThickness as i32),
|
||||
strikeout_offset: au_from_du_s(dm.strikethroughPosition as i32),
|
||||
leading: au_from_du_s(leading as i32),
|
||||
x_height: au_from_du_s(dm.xHeight as i32),
|
||||
em_size: au_from_em(self.em_size as f64),
|
||||
ascent: au_from_du_s(dm.ascent as i32),
|
||||
descent: au_from_du_s(dm.descent as i32),
|
||||
max_advance: au_from_pt(0.0), // FIXME
|
||||
average_advance: au_from_pt(0.0), // FIXME
|
||||
line_gap: au_from_du_s((dm.ascent + dm.descent + dm.lineGap as u16) as i32),
|
||||
leading: au_from_du_s(leading as i32),
|
||||
x_height: au_from_du_s(dm.xHeight as i32),
|
||||
em_size: au_from_em(self.em_size as f64),
|
||||
ascent: au_from_du_s(dm.ascent as i32),
|
||||
descent: au_from_du_s(dm.descent as i32),
|
||||
max_advance: au_from_pt(0.0), // FIXME
|
||||
average_advance: au_from_pt(0.0), // FIXME
|
||||
line_gap: au_from_du_s((dm.ascent + dm.descent + dm.lineGap as u16) as i32),
|
||||
};
|
||||
debug!("Font metrics (@{} pt): {:?}", self.em_size * 12., metrics);
|
||||
metrics
|
||||
}
|
||||
|
||||
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 {
|
||||
|
|
|
@ -21,7 +21,10 @@ pub fn system_default_family(_: &str) -> Option<String> {
|
|||
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();
|
||||
for family in system_fc.families_iter() {
|
||||
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
|
||||
// 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();
|
||||
if let Some(family) = system_fc.get_font_family_by_name(family_name) {
|
||||
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 {
|
||||
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
|
||||
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 {
|
||||
match unicode_plane(codepoint) {
|
||||
|
@ -83,31 +91,29 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
|
|||
UnicodeBlock::Hebrew => {
|
||||
families.push("Estrangelo Edessa");
|
||||
families.push("Cambria");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Arabic |
|
||||
UnicodeBlock::ArabicSupplement => {
|
||||
UnicodeBlock::Arabic | UnicodeBlock::ArabicSupplement => {
|
||||
families.push("Microsoft Uighur");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Syriac => {
|
||||
families.push("Estrangelo Edessa");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Thaana => {
|
||||
families.push("MV Boli");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::NKo => {
|
||||
families.push("Ebrima");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Devanagari |
|
||||
UnicodeBlock::Bengali => {
|
||||
UnicodeBlock::Devanagari | UnicodeBlock::Bengali => {
|
||||
families.push("Nirmala UI");
|
||||
families.push("Utsaah");
|
||||
families.push("Aparajita");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Gurmukhi |
|
||||
UnicodeBlock::Gujarati |
|
||||
|
@ -123,21 +129,21 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
|
|||
UnicodeBlock::SundaneseSupplement |
|
||||
UnicodeBlock::VedicExtensions => {
|
||||
families.push("Nirmala UI");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Thai => {
|
||||
families.push("Leelawadee UI");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Lao => {
|
||||
families.push("Lao UI");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Myanmar |
|
||||
UnicodeBlock::MyanmarExtendedA |
|
||||
UnicodeBlock::MyanmarExtendedB => {
|
||||
families.push("Myanmar Text");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::HangulJamo |
|
||||
UnicodeBlock::HangulJamoExtendedA |
|
||||
|
@ -145,48 +151,47 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
|
|||
UnicodeBlock::HangulJamoExtendedB |
|
||||
UnicodeBlock::HangulCompatibilityJamo => {
|
||||
families.push("Malgun Gothic");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Ethiopic |
|
||||
UnicodeBlock::EthiopicSupplement |
|
||||
UnicodeBlock::EthiopicExtended |
|
||||
UnicodeBlock::EthiopicExtendedA => {
|
||||
families.push("Nyala");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Cherokee => {
|
||||
families.push("Plantagenet Cherokee");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::UnifiedCanadianAboriginalSyllabics |
|
||||
UnicodeBlock::UnifiedCanadianAboriginalSyllabicsExtended => {
|
||||
families.push("Euphemia");
|
||||
families.push("Segoe UI");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Khmer |
|
||||
UnicodeBlock::KhmerSymbols => {
|
||||
UnicodeBlock::Khmer | UnicodeBlock::KhmerSymbols => {
|
||||
families.push("Khmer UI");
|
||||
families.push("Leelawadee UI");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Mongolian => {
|
||||
families.push("Mongolian Baiti");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::TaiLe => {
|
||||
families.push("Microsoft Tai Le");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::NewTaiLue => {
|
||||
families.push("Microsoft New Tai Lue");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Buginese |
|
||||
UnicodeBlock::TaiTham |
|
||||
UnicodeBlock::CombiningDiacriticalMarksExtended => {
|
||||
families.push("Leelawadee UI");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::GeneralPunctuation |
|
||||
UnicodeBlock::SuperscriptsandSubscripts |
|
||||
|
@ -220,7 +225,7 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
|
|||
families.push("Meiryo");
|
||||
families.push("Lucida Sans Unicode");
|
||||
families.push("Ebrima");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::GeorgianSupplement |
|
||||
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 Symbol");
|
||||
families.push("Meiryo");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::BraillePatterns => {
|
||||
families.push("Segoe UI Symbol");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::CJKSymbolsandPunctuation |
|
||||
UnicodeBlock::Hiragana |
|
||||
|
@ -249,21 +254,20 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
|
|||
UnicodeBlock::CJKUnifiedIdeographs => {
|
||||
families.push("Microsoft YaHei");
|
||||
families.push("Yu Gothic");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::EnclosedCJKLettersandMonths => {
|
||||
families.push("Malgun Gothic");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::YijingHexagramSymbols => {
|
||||
families.push("Segoe UI Symbol");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::YiSyllables |
|
||||
UnicodeBlock::YiRadicals => {
|
||||
UnicodeBlock::YiSyllables | UnicodeBlock::YiRadicals => {
|
||||
families.push("Microsoft Yi Baiti");
|
||||
families.push("Segoe UI");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::Vai |
|
||||
UnicodeBlock::CyrillicExtendedB |
|
||||
|
@ -273,36 +277,34 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
|
|||
families.push("Ebrima");
|
||||
families.push("Segoe UI");
|
||||
families.push("Cambria Math");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::SylotiNagri |
|
||||
UnicodeBlock::CommonIndicNumberForms |
|
||||
UnicodeBlock::Phagspa |
|
||||
UnicodeBlock::Saurashtra |
|
||||
UnicodeBlock::DevanagariExtended => {
|
||||
families.push("Microsoft PhagsPa");
|
||||
families.push("Nirmala UI");
|
||||
}
|
||||
families.push("Microsoft PhagsPa");
|
||||
families.push("Nirmala UI");
|
||||
},
|
||||
|
||||
UnicodeBlock::KayahLi |
|
||||
UnicodeBlock::Rejang |
|
||||
UnicodeBlock::Javanese => {
|
||||
families.push("Malgun Gothic");
|
||||
families.push("Javanese Text");
|
||||
families.push("Leelawadee UI");
|
||||
}
|
||||
UnicodeBlock::KayahLi | UnicodeBlock::Rejang | UnicodeBlock::Javanese => {
|
||||
families.push("Malgun Gothic");
|
||||
families.push("Javanese Text");
|
||||
families.push("Leelawadee UI");
|
||||
},
|
||||
|
||||
UnicodeBlock::AlphabeticPresentationForms => {
|
||||
families.push("Microsoft Uighur");
|
||||
families.push("Gabriola");
|
||||
families.push("Sylfaen");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::ArabicPresentationFormsA |
|
||||
UnicodeBlock::ArabicPresentationFormsB => {
|
||||
families.push("Traditional Arabic");
|
||||
families.push("Arabic Typesetting");
|
||||
}
|
||||
},
|
||||
|
||||
UnicodeBlock::VariationSelectors |
|
||||
UnicodeBlock::VerticalForms |
|
||||
|
@ -312,12 +314,12 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
|
|||
UnicodeBlock::HalfwidthandFullwidthForms |
|
||||
UnicodeBlock::Specials => {
|
||||
families.push("Microsoft JhengHei");
|
||||
}
|
||||
},
|
||||
|
||||
_ => {}
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// https://en.wikipedia.org/wiki/Plane_(Unicode)#Supplementary_Multilingual_Plane
|
||||
1 => {
|
||||
|
@ -325,9 +327,9 @@ pub fn fallback_font_families(codepoint: Option<char>) -> Vec<&'static str> {
|
|||
families.push("Ebrima");
|
||||
families.push("Nirmala UI");
|
||||
families.push("Cambria Math");
|
||||
}
|
||||
},
|
||||
|
||||
_ => {}
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ use webrender_api::NativeFontHandle;
|
|||
#[derive(Deserialize, Serialize)]
|
||||
pub struct FontTemplateData {
|
||||
// If you add members here, review the Debug impl below
|
||||
|
||||
pub bytes: Option<Vec<u8>>,
|
||||
pub identifier: Atom,
|
||||
}
|
||||
|
@ -19,20 +18,22 @@ pub struct FontTemplateData {
|
|||
impl fmt::Debug for FontTemplateData {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.debug_struct("FontTemplateData")
|
||||
.field(
|
||||
"bytes",
|
||||
&self.bytes
|
||||
.field(
|
||||
"bytes",
|
||||
&self
|
||||
.bytes
|
||||
.as_ref()
|
||||
.map(|bytes| format!("[{} bytes]", bytes.len()))
|
||||
)
|
||||
.field("identifier", &self.identifier)
|
||||
.finish()
|
||||
.map(|bytes| format!("[{} bytes]", bytes.len())),
|
||||
).field("identifier", &self.identifier)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl FontTemplateData {
|
||||
pub fn new(identifier: Atom,
|
||||
font_data: Option<Vec<u8>>) -> Result<FontTemplateData, io::Error> {
|
||||
pub fn new(
|
||||
identifier: Atom,
|
||||
font_data: Option<Vec<u8>>,
|
||||
) -> Result<FontTemplateData, io::Error> {
|
||||
Ok(FontTemplateData {
|
||||
bytes: font_data,
|
||||
identifier: identifier,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue