Address review comments.

This commit is contained in:
Glenn Watson 2014-07-11 10:30:52 +10:00
parent 6465bf6a85
commit 40559d148a
4 changed files with 126 additions and 41 deletions

View file

@ -105,7 +105,7 @@ impl FontCache {
self.web_families.insert(family_name.clone(), family); self.web_families.insert(family_name.clone(), family);
} }
let family = self.web_families.get_mut(&family_name); let family = self.web_families.get_mut(&family_name);
family.add_template(format!("{}", url).as_slice(), Some(bytes)); family.add_template(format!("{}", url).as_slice(), Some(bytes));
}, },
Err(msg) => { Err(msg) => {
fail!(msg); fail!(msg);

View file

@ -455,20 +455,23 @@ impl LayoutTask {
// Find all font-face rules and notify the font cache of them. // Find all font-face rules and notify the font cache of them.
// GWTODO: Need to handle unloading web fonts (when we handle unloading stylesheets!) // GWTODO: Need to handle unloading web fonts (when we handle unloading stylesheets!)
// GWTODO: Need to handle font-face nested within media rules. // GWTODO: Need to handle font-face nested within media rules.
// GWTODO: Don't rely on format hint here. Should determine file format from data.
for rule in sheet.rules.iter() { for rule in sheet.rules.iter() {
match rule { match rule {
&CSSFontFaceRule(ref font_face_rule) => { &CSSFontFaceRule(ref font_face_rule) => {
for source in font_face_rule.sources.iter() { for source_line in font_face_rule.source_lines.iter() {
match source.format { for source in source_line.sources.iter() {
TtfFormat => { match source.format_hint {
self.font_cache_task.add_web_font(source.url.clone(), font_face_rule.family.as_slice()); TtfFormat => {
}, self.font_cache_task.add_web_font(source.url.clone(), font_face_rule.family.as_slice());
_ => {} },
_ => {}
}
} }
} }
}, },
_ => {} _ => {}
} }
} }
self.stylist.add_stylesheet(sheet, AuthorOrigin); self.stylist.add_stylesheet(sheet, AuthorOrigin);

View file

@ -22,19 +22,27 @@ pub enum FontFaceFormat {
pub struct FontFaceSource { pub struct FontFaceSource {
pub url: Url, pub url: Url,
pub format: FontFaceFormat, pub format_hint: FontFaceFormat,
}
pub struct FontFaceSourceLine {
pub sources: Vec<FontFaceSource>
} }
pub struct FontFaceRule { pub struct FontFaceRule {
pub family: String, pub family: String,
pub sources: Vec<FontFaceSource>, pub source_lines: Vec<FontFaceSourceLine>,
} }
pub fn parse_font_face_rule(rule: AtRule, parent_rules: &mut Vec<CSSRule>, base_url: &Url) { pub fn parse_font_face_rule(rule: AtRule, parent_rules: &mut Vec<CSSRule>, base_url: &Url) {
let mut font_face_rule = FontFaceRule {
family: "".to_string(), let mut maybe_family = None;
sources: vec!() let mut source_lines = vec!();
};
if rule.prelude.as_slice().skip_whitespace().next().is_some() {
log_css_error(rule.location, "@font-face prelude contains unexpected characters");
return;
}
let block = match rule.block { let block = match rule.block {
Some(block) => block, Some(block) => block,
@ -53,9 +61,10 @@ pub fn parse_font_face_rule(rule: AtRule, parent_rules: &mut Vec<CSSRule>, base_
let name_lower = name.as_slice().to_ascii_lower(); let name_lower = name.as_slice().to_ascii_lower();
match name_lower.as_slice() { match name_lower.as_slice() {
"font-family" => { "font-family" => {
// FIXME(#2802): Share code with the font-family parser.
match one_component_value(value.as_slice()) { match one_component_value(value.as_slice()) {
Some(&String(ref string_value)) => { Some(&String(ref string_value)) => {
font_face_rule.family = string_value.clone(); maybe_family = Some(string_value.clone());
}, },
_ => { _ => {
log_css_error(location, format!("Unsupported font-family string {:s}", name).as_slice()); log_css_error(location, format!("Unsupported font-family string {:s}", name).as_slice());
@ -63,45 +72,112 @@ pub fn parse_font_face_rule(rule: AtRule, parent_rules: &mut Vec<CSSRule>, base_
} }
}, },
"src" => { "src" => {
for component_value in value.as_slice().skip_whitespace() { let mut iter = value.as_slice().skip_whitespace();
match component_value { let mut sources = vec!();
&URL(ref string_value) => { let mut syntax_error = false;
let font_url = parse_url(string_value.as_slice(), Some(base_url.clone()));
let src = FontFaceSource { url: font_url, format: UnknownFormat }; 'outer: loop {
font_face_rule.sources.push(src);
// url() or local() should be next
let url = match iter.next() {
Some(&URL(ref string_value)) => {
parse_url(string_value.as_slice(), Some(base_url.clone()))
}, },
&Function(ref string_value, ref values) => { _ => {
log_css_error(location, "Unsupported declaration (local font face is not supported yet)");
syntax_error = true;
break;
}
};
// optional format, or comma to start loop again
let mut next_token = iter.next();
match next_token {
Some(&Function(ref string_value, ref values)) => {
match string_value.as_slice() { match string_value.as_slice() {
"format" => { "format" => {
let format = one_component_value(values.as_slice()).and_then(|c| { let maybe_format_hint_string = one_component_value(
values.as_slice()).and_then(|c| {
match c { match c {
&String(ref format_string) => Some(format_string.as_slice().to_ascii_lower()), &String(ref s) => Some(s.as_slice().to_ascii_lower()),
_ => None, _ => None,
} }
}); });
match font_face_rule.sources.mut_last() {
Some(source) => { match maybe_format_hint_string {
source.format = match format.unwrap_or("".to_string()).as_slice() { Some(ref format_hint_string) => {
"embedded-opentype" => EotFormat, let format_hints: Vec<&str> = format_hint_string.as_slice().split(',').collect();
"woff" => WoffFormat,
"truetype" | "opentype" => TtfFormat, for format_hint in format_hints.iter() {
"svg" => SvgFormat, let format_hint = format_hint.trim();
_ => UnknownFormat,
let hint = match format_hint.as_slice() {
"embedded-opentype" => EotFormat,
"woff" => WoffFormat,
"truetype" | "opentype" => TtfFormat,
"svg" => SvgFormat,
_ => UnknownFormat,
};
if hint == UnknownFormat {
log_css_error(location,
format!("Unknown font format {}", format_hint).as_slice());
syntax_error = true;
break 'outer;
}
let source = FontFaceSource {
url: url.clone(),
format_hint: hint,
};
sources.push(source);
} }
},
None => {
log_css_error(location,
format!("Unsupported token {}", string_value).as_slice());
syntax_error = true;
break;
} }
None => {} }
};
},
"local" => {
log_css_error(location, "local font face not supported yet!");
}, },
_ => { _ => {
log_css_error(location, format!("Unsupported declaration {}", string_value).as_slice()); log_css_error(location,
format!("Unsupported token {}", string_value).as_slice());
syntax_error = true;
break;
} }
} }
next_token = iter.next();
}, },
_ => {} _ => {
let source = FontFaceSource {
url: url,
format_hint: UnknownFormat,
};
sources.push(source);
}
} }
// after url or optional format, comes comma or end
match next_token {
Some(&Comma) => {},
None => break,
_ => {
log_css_error(location, "Unexpected token type");
syntax_error = true;
break;
}
}
}
if !syntax_error {
assert!(sources.len() > 0);
let source_line = FontFaceSourceLine {
sources: sources
};
source_lines.push(source_line);
} }
}, },
_ => { _ => {
@ -112,5 +188,11 @@ pub fn parse_font_face_rule(rule: AtRule, parent_rules: &mut Vec<CSSRule>, base_
} }
} }
parent_rules.push(CSSFontFaceRule(font_face_rule)); if maybe_family.is_some() && source_lines.len() > 0 {
let font_face_rule = FontFaceRule {
family: maybe_family.unwrap(),
source_lines: source_lines,
};
parent_rules.push(CSSFontFaceRule(font_face_rule));
}
} }

View file

@ -47,7 +47,7 @@ pub use selectors::{NamespaceConstraint, Selector, CompoundSelector, SimpleSelec
pub use selectors::{parse_selector_list}; pub use selectors::{parse_selector_list};
pub use namespaces::NamespaceMap; pub use namespaces::NamespaceMap;
pub use media_queries::{MediaRule, MediaQueryList, MediaQuery, Device, MediaType, MediaQueryType}; pub use media_queries::{MediaRule, MediaQueryList, MediaQuery, Device, MediaType, MediaQueryType};
pub use font_face::{FontFaceFormat, FontFaceRule, FontFaceSource, TtfFormat}; pub use font_face::{FontFaceFormat, FontFaceRule, FontFaceSource,FontFaceSourceLine, TtfFormat};
mod stylesheets; mod stylesheets;
mod errors; mod errors;