mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +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 {
|
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,17 +211,16 @@ 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()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// All Android fonts are located in /system/fonts
|
// All Android fonts are located in /system/fonts
|
||||||
|
@ -227,15 +228,14 @@ impl FontList {
|
||||||
format!("/system/fonts/{}", filename)
|
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)
|
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)
|
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();
|
||||||
|
@ -253,13 +253,15 @@ impl FontList {
|
||||||
// <font weight="300" style="italic">Roboto-LightItalic.ttf</font>
|
// <font weight="300" style="italic">Roboto-LightItalic.ttf</font>
|
||||||
// <font weight="400" style="normal">Roboto-Regular.ttf</font>
|
// <font weight="400" style="normal">Roboto-Regular.ttf</font>
|
||||||
// </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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,7 +316,7 @@ impl FontList {
|
||||||
// <file>Roboto-BoldItalic.ttf</file>
|
// <file>Roboto-BoldItalic.ttf</file>
|
||||||
// </fileset>
|
// </fileset>
|
||||||
// </family>
|
// </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 nameset = Vec::new();
|
||||||
let mut fileset = Vec::new();
|
let mut fileset = Vec::new();
|
||||||
for node in familyset.children.borrow().iter() {
|
for node in familyset.children.borrow().iter() {
|
||||||
|
@ -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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -342,11 +352,13 @@ impl FontList {
|
||||||
|
|
||||||
// Example:
|
// Example:
|
||||||
// <font weight="100" style="normal">Roboto-Thin.ttf</font>
|
// <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
|
// 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
|
||||||
|
@ -367,17 +379,21 @@ impl FontList {
|
||||||
// <alias name="helvetica" to="sans-serif" />
|
// <alias name="helvetica" to="sans-serif" />
|
||||||
// <alias name="tahoma" to="sans-serif" />
|
// <alias name="tahoma" to="sans-serif" />
|
||||||
// <alias name="verdana" 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
|
// 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,23 +407,28 @@ 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,
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
for child in node.children.borrow().iter() {
|
||||||
match child.data {
|
match child.data {
|
||||||
NodeData::Element { ref name, .. } => {
|
NodeData::Element { ref name, .. } => {
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 })
|
||||||
}
|
}
|
||||||
|
@ -338,25 +364,33 @@ impl FontHandleMethods for FontHandle {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> 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;
|
let char_size = pt_size.to_f64_px() * 64.0 + 0.5;
|
||||||
|
|
||||||
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 {
|
||||||
|
|
|
@ -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,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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");
|
||||||
}
|
},
|
||||||
|
|
||||||
_ => {}
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 {
|
||||||
|
@ -350,7 +367,7 @@ impl FontHandleMethods for FontHandle {
|
||||||
let dm = self.face.metrics();
|
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 = |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
|
// anything that we calculate and don't just pull out of self.face.metrics
|
||||||
// is pulled out here for clarity
|
// is pulled out here for clarity
|
||||||
|
@ -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 {
|
||||||
|
|
|
@ -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");
|
||||||
}
|
},
|
||||||
|
|
||||||
_ => {}
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue