aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorSimon Sapin <simon.sapin@exyr.org>2019-10-23 14:55:23 +0200
committerAnthony Ramine <nox@nox.paris>2019-10-23 15:34:48 +0200
commit4f8cfd9b489f93ecf9cb1db8e9cdd330a98ffcbf (patch)
treed32466dc81a93ca4eab18ec7a0a8fcaf9bbb99f5 /components
parente26530341bdd3bfdaf40ba0e9f6cc1460732bc9e (diff)
downloadservo-4f8cfd9b489f93ecf9cb1db8e9cdd330a98ffcbf.tar.gz
servo-4f8cfd9b489f93ecf9cb1db8e9cdd330a98ffcbf.zip
Use xml-rs instead of rcdom for Android font list parsing
Diffstat (limited to 'components')
-rw-r--r--components/gfx/Cargo.toml2
-rw-r--r--components/gfx/platform/freetype/android/font_list.rs198
-rw-r--r--components/gfx/platform/freetype/android/xml.rs50
-rw-r--r--components/gfx/platform/mod.rs1
4 files changed, 124 insertions, 127 deletions
diff --git a/components/gfx/Cargo.toml b/components/gfx/Cargo.toml
index a27ffcdab15..d1519b91040 100644
--- a/components/gfx/Cargo.toml
+++ b/components/gfx/Cargo.toml
@@ -56,7 +56,7 @@ servo_allocator = {path = "../allocator"}
servo-fontconfig = "0.4"
[target.'cfg(target_os = "android")'.dependencies]
-xml5ever = {version = "0.15"}
+xml-rs = "0.8"
[target.'cfg(target_os = "windows")'.dependencies]
dwrote = "0.9"
diff --git a/components/gfx/platform/freetype/android/font_list.rs b/components/gfx/platform/freetype/android/font_list.rs
index 6d5156d9617..9c4570b6cca 100644
--- a/components/gfx/platform/freetype/android/font_list.rs
+++ b/components/gfx/platform/freetype/android/font_list.rs
@@ -2,17 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+use super::xml::{Attribute, Node};
use crate::text::util::is_cjk;
-use std::cell::RefCell;
-use std::fs::File;
-use std::io::{self, Read};
use std::path::Path;
use ucd::{Codepoint, UnicodeBlock};
-use xml5ever::driver::parse_document;
-use xml5ever::rcdom::*;
-use xml5ever::rcdom::{Node, RcDom};
-use xml5ever::tendril::TendrilSink;
-use xml5ever::Attribute;
lazy_static! {
static ref FONT_LIST: FontList = FontList::new();
@@ -157,51 +150,36 @@ impl FontList {
// Creates a new FontList from a path to the font mapping xml file.
fn from_path(path: &str) -> Option<FontList> {
- let xml = match Self::load_file(path) {
- Ok(xml) => xml,
- _ => {
- return None;
- },
- };
-
- let dom: RcDom = parse_document(RcDom::default(), Default::default()).one(xml);
- let doc = &dom.document;
+ let bytes = std::fs::read(path).ok()?;
+ let nodes = super::xml::parse(&bytes).ok()?;
// 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 = match familyset {
- Some(node) => node,
- _ => {
- return None;
+ let familyset = nodes.iter().find_map(|e| match e {
+ Node::Element { name, children, .. } if name.local_name == "familyset" => {
+ Some(children)
},
- };
+ _ => None,
+ })?;
// Parse familyset node
let mut families = Vec::new();
let mut aliases = Vec::new();
- for node in familyset.children.borrow().iter() {
- match node.data {
- NodeData::Element {
- ref name,
- ref attrs,
- ..
- } => {
- if &*name.local == "family" {
- Self::parse_family(&node, attrs, &mut families);
- } else if &*name.local == "alias" {
- // aliases come after the fonts they reference. -->
- if !families.is_empty() {
- Self::parse_alias(attrs, &mut aliases);
- }
+ for node in familyset {
+ if let Node::Element {
+ name,
+ attributes,
+ children,
+ } = node
+ {
+ if name.local_name == "family" {
+ Self::parse_family(children, attributes, &mut families);
+ } else if name.local_name == "alias" {
+ // aliases come after the fonts they reference. -->
+ if !families.is_empty() {
+ Self::parse_alias(attributes, &mut aliases);
}
- },
- _ => {},
+ }
}
}
@@ -253,14 +231,6 @@ impl FontList {
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();
- file.read_to_string(&mut content)?;
-
- Ok(content)
- }
-
// Parse family and font file names
// Example:
// <family name="sans-serif">
@@ -270,40 +240,35 @@ 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: &[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 {
- NodeData::Element { ref name, .. } => &*name.local == "nameset",
- _ => false,
- });
+ let using_api_17 = familyset.iter().any(|node| match node {
+ Node::Element { name, .. } => name.local_name == "nameset",
+ _ => false,
+ });
if using_api_17 {
Self::parse_family_v17(familyset, out);
return;
}
// Parse family name
- let name = match Self::find_attrib("name", attrs) {
- Some(name) => name,
- _ => {
- return;
- },
+ let name = if let Some(name) = Self::find_attrib("name", attrs) {
+ name
+ } else {
+ 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,
- ..
+ for node in familyset {
+ match node {
+ Node::Element {
+ name,
+ attributes,
+ children,
} => {
- if &*name.local == "font" {
- FontList::parse_font(&node, attrs, &mut fonts);
+ if name.local_name == "font" {
+ FontList::parse_font(&children, attributes, &mut fonts);
}
},
_ => {},
@@ -333,19 +298,16 @@ 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() {
- match node.data {
- NodeData::Element { ref name, .. } => {
- if &*name.local == "nameset" {
- Self::collect_contents_with_tag(node, "name", &mut nameset);
- } else if &*name.local == "fileset" {
- Self::collect_contents_with_tag(node, "file", &mut fileset);
- }
- },
- _ => {},
+ for node in familyset {
+ if let Node::Element { name, children, .. } = node {
+ if name.local_name == "nameset" {
+ Self::collect_contents_with_tag(children, "name", &mut nameset);
+ } else if name.local_name == "fileset" {
+ Self::collect_contents_with_tag(children, "file", &mut fileset);
+ }
}
}
@@ -370,22 +332,17 @@ 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(nodes: &[Node], attrs: &[Attribute], out: &mut Vec<Font>) {
// Parse font filename
- let filename = match Self::text_content(node) {
- Some(filename) => filename,
- _ => {
- return;
- },
- };
-
- // Parse font weight
- let weight = Self::find_attrib("weight", attrs).and_then(|w| w.parse().ok());
+ if let Some(filename) = Self::text_content(nodes) {
+ // Parse font weight
+ let weight = Self::find_attrib("weight", attrs).and_then(|w| w.parse().ok());
- out.push(Font {
- filename: filename,
- weight: weight,
- })
+ out.push(Font {
+ filename: filename,
+ weight: weight,
+ })
+ }
}
// Example:
@@ -397,7 +354,7 @@ 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: &[Attribute], out: &mut Vec<FontAlias>) {
// Parse alias name and referenced font
let from = match Self::find_attrib("name", attrs) {
Some(from) => from,
@@ -424,39 +381,28 @@ impl FontList {
})
}
- fn find_attrib(name: &str, attrs: &RefCell<Vec<Attribute>>) -> Option<String> {
+ fn find_attrib(name: &str, attrs: &[Attribute]) -> Option<String> {
attrs
- .borrow()
.iter()
- .find(|attr| &*attr.name.local == name)
- .map(|s| String::from(&s.value))
+ .find(|attr| attr.name.local_name == name)
+ .map(|attr| attr.value.clone())
}
- fn text_content(node: &Node) -> Option<String> {
- 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,
- })
+ fn text_content(nodes: &[Node]) -> Option<String> {
+ nodes.get(0).and_then(|child| match child {
+ Node::Text(contents) => Some(contents.clone()),
+ Node::Element { .. } => None,
+ })
}
- 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, .. } => {
- if &*name.local == tag {
- if let Some(content) = Self::text_content(child) {
- out.push(content);
- }
+ fn collect_contents_with_tag(nodes: &[Node], tag: &str, out: &mut Vec<String>) {
+ for node in nodes {
+ if let Node::Element { name, children, .. } = node {
+ if name.local_name == tag {
+ if let Some(content) = Self::text_content(children) {
+ out.push(content);
}
- },
- _ => {},
+ }
}
}
}
diff --git a/components/gfx/platform/freetype/android/xml.rs b/components/gfx/platform/freetype/android/xml.rs
new file mode 100644
index 00000000000..aa03123006f
--- /dev/null
+++ b/components/gfx/platform/freetype/android/xml.rs
@@ -0,0 +1,50 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use xml::reader::XmlEvent::*;
+
+pub(super) use xml::attribute::OwnedAttribute as Attribute;
+
+pub(super) enum Node {
+ Element {
+ name: xml::name::OwnedName,
+ attributes: Vec<xml::attribute::OwnedAttribute>,
+ children: Vec<Node>,
+ },
+ Text(String),
+}
+
+pub(super) fn parse(bytes: &[u8]) -> xml::reader::Result<Vec<Node>> {
+ let mut stack = Vec::new();
+ let mut nodes = Vec::new();
+ for result in xml::EventReader::new(&*bytes) {
+ match result? {
+ StartElement {
+ name, attributes, ..
+ } => {
+ stack.push((name, attributes, nodes));
+ nodes = Vec::new();
+ },
+ EndElement { .. } => {
+ let (name, attributes, mut parent_nodes) = stack.pop().unwrap();
+ parent_nodes.push(Node::Element {
+ name,
+ attributes,
+ children: nodes,
+ });
+ nodes = parent_nodes;
+ },
+ CData(s) | Characters(s) | Whitespace(s) => {
+ if let Some(Node::Text(text)) = nodes.last_mut() {
+ text.push_str(&s)
+ } else {
+ nodes.push(Node::Text(s))
+ }
+ },
+ StartDocument { .. } | EndDocument | ProcessingInstruction { .. } | Comment(..) => {},
+ }
+ }
+ assert!(stack.is_empty());
+ Ok(nodes)
+}
diff --git a/components/gfx/platform/mod.rs b/components/gfx/platform/mod.rs
index 87ace2230c2..5b41d70c9d6 100644
--- a/components/gfx/platform/mod.rs
+++ b/components/gfx/platform/mod.rs
@@ -36,6 +36,7 @@ mod freetype {
#[cfg(target_os = "android")]
mod android {
pub mod font_list;
+ mod xml;
}
#[cfg(target_os = "android")]
pub use self::android::font_list;