Use the Parse trait for @font-face parsing.

This commit is contained in:
Simon Sapin 2017-01-27 17:54:15 +01:00
parent 7724bb01a3
commit 2b83d844da
3 changed files with 88 additions and 73 deletions

View file

@ -11,7 +11,6 @@
use computed_values::font_family::FontFamily;
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser};
use parser::{ParserContext, log_css_error, Parse};
use properties::longhands::font_family::parse_one_family;
use std::fmt;
use std::iter;
use style_traits::ToCss;
@ -181,40 +180,44 @@ impl<'a, 'b> DeclarationParser for FontFaceRuleParser<'a, 'b> {
fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<(), ()> {
match_ignore_ascii_case! { name,
"font-family" => {
self.rule.family = parse_one_family(input)?;
},
"src" => {
self.rule.sources = input.parse_comma_separated(|input| {
parse_one_src(self.context, input)
})?;
},
"font-family" => self.rule.family = Parse::parse(self.context, input)?,
"src" => self.rule.sources = Parse::parse(self.context, input)?,
_ => return Err(())
}
Ok(())
}
}
fn parse_one_src(context: &ParserContext, input: &mut Parser) -> Result<Source, ()> {
if input.try(|input| input.expect_function_matching("local")).is_ok() {
return Ok(Source::Local(try!(input.parse_nested_block(parse_one_family))))
impl Parse for Vec<Source> {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
input.parse_comma_separated(|input| Source::parse(context, input))
}
}
impl Parse for Source {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Source, ()> {
if input.try(|input| input.expect_function_matching("local")).is_ok() {
return input.parse_nested_block(|input| {
FontFamily::parse(context, input)
}).map(Source::Local)
}
let url = SpecifiedUrl::parse(context, input)?;
// Parsing optional format()
let format_hints = if input.try(|input| input.expect_function_matching("format")).is_ok() {
input.parse_nested_block(|input| {
input.parse_comma_separated(|input| {
Ok(input.expect_string()?.into_owned())
})
})?
} else {
vec![]
};
Ok(Source::Url(UrlSource {
url: url,
format_hints: format_hints,
}))
}
let url = try!(SpecifiedUrl::parse(context, input));
// Parsing optional format()
let format_hints = if input.try(|input| input.expect_function_matching("format")).is_ok() {
try!(input.parse_nested_block(|input| {
input.parse_comma_separated(|input| {
Ok((try!(input.expect_string())).into_owned())
})
}))
} else {
vec![]
};
Ok(Source::Url(UrlSource {
url: url,
format_hints: format_hints,
}))
}

View file

@ -107,56 +107,66 @@
pub fn get_initial_value() -> computed_value::T {
computed_value::T(vec![FontFamily::Generic(atom!("serif"))])
}
/// <family-name>#
/// <family-name> = <string> | [ <ident>+ ]
/// TODO: <generic-family>
pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
input.parse_comma_separated(parse_one_family).map(SpecifiedValue)
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
Vec::<FontFamily>::parse(context, input).map(SpecifiedValue)
}
pub fn parse_one_family(input: &mut Parser) -> Result<FontFamily, ()> {
if let Ok(value) = input.try(|input| input.expect_string()) {
return Ok(FontFamily::FamilyName(Atom::from(&*value)))
}
let first_ident = try!(input.expect_ident());
// FIXME(bholley): The fast thing to do here would be to look up the
// string (as lowercase) in the static atoms table. We don't have an
// API to do that yet though, so we do the simple thing for now.
let mut css_wide_keyword = false;
match_ignore_ascii_case! { first_ident,
"serif" => return Ok(FontFamily::Generic(atom!("serif"))),
"sans-serif" => return Ok(FontFamily::Generic(atom!("sans-serif"))),
"cursive" => return Ok(FontFamily::Generic(atom!("cursive"))),
"fantasy" => return Ok(FontFamily::Generic(atom!("fantasy"))),
"monospace" => return Ok(FontFamily::Generic(atom!("monospace"))),
impl Parse for Vec<FontFamily> {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
input.parse_comma_separated(|input| FontFamily::parse(context, input))
}
}
// https://drafts.csswg.org/css-fonts/#propdef-font-family
// "Font family names that happen to be the same as a keyword value
// (inherit, serif, sans-serif, monospace, fantasy, and cursive)
// must be quoted to prevent confusion with the keywords with the same names.
// The keywords initial and default are reserved for future use
// and must also be quoted when used as font names.
// UAs must not consider these keywords as matching the <family-name> type."
"inherit" => css_wide_keyword = true,
"initial" => css_wide_keyword = true,
"unset" => css_wide_keyword = true,
"default" => css_wide_keyword = true,
_ => {}
}
impl Parse for FontFamily {
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
if let Ok(value) = input.try(|input| input.expect_string()) {
return Ok(FontFamily::FamilyName(Atom::from(&*value)))
}
let first_ident = try!(input.expect_ident());
let mut value = first_ident.into_owned();
// These keywords are not allowed by themselves.
// The only way this value can be valid with with another keyword.
if css_wide_keyword {
let ident = input.expect_ident()?;
value.push_str(" ");
value.push_str(&ident);
// FIXME(bholley): The fast thing to do here would be to look up the
// string (as lowercase) in the static atoms table. We don't have an
// API to do that yet though, so we do the simple thing for now.
let mut css_wide_keyword = false;
match_ignore_ascii_case! { first_ident,
"serif" => return Ok(FontFamily::Generic(atom!("serif"))),
"sans-serif" => return Ok(FontFamily::Generic(atom!("sans-serif"))),
"cursive" => return Ok(FontFamily::Generic(atom!("cursive"))),
"fantasy" => return Ok(FontFamily::Generic(atom!("fantasy"))),
"monospace" => return Ok(FontFamily::Generic(atom!("monospace"))),
// https://drafts.csswg.org/css-fonts/#propdef-font-family
// "Font family names that happen to be the same as a keyword value
// (inherit, serif, sans-serif, monospace, fantasy, and cursive)
// must be quoted to prevent confusion with the keywords with the same names.
// The keywords initial and default are reserved for future use
// and must also be quoted when used as font names.
// UAs must not consider these keywords as matching the <family-name> type."
"inherit" => css_wide_keyword = true,
"initial" => css_wide_keyword = true,
"unset" => css_wide_keyword = true,
"default" => css_wide_keyword = true,
_ => {}
}
let mut value = first_ident.into_owned();
// These keywords are not allowed by themselves.
// The only way this value can be valid with with another keyword.
if css_wide_keyword {
let ident = input.expect_ident()?;
value.push_str(" ");
value.push_str(&ident);
}
while let Ok(ident) = input.try(|input| input.expect_ident()) {
value.push_str(" ");
value.push_str(&ident);
}
Ok(FontFamily::FamilyName(Atom::from(value)))
}
while let Ok(ident) = input.try(|input| input.expect_ident()) {
value.push_str(" ");
value.push_str(&ident);
}
Ok(FontFamily::FamilyName(Atom::from(value)))
}
</%helpers:longhand>

View file

@ -7,8 +7,10 @@
<%helpers:shorthand name="font" sub_properties="font-style font-variant font-weight font-stretch
font-size line-height font-family"
spec="https://drafts.csswg.org/css-fonts-3/#propdef-font">
use parser::Parse;
use properties::longhands::{font_style, font_variant, font_weight, font_stretch};
use properties::longhands::{font_size, line_height, font_family};
use properties::longhands::font_family::computed_value::FontFamily;
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
let mut nb_normals = 0;
@ -64,7 +66,7 @@
} else {
None
};
let family = try!(input.parse_comma_separated(font_family::parse_one_family));
let family = Vec::<FontFamily>::parse(context, input)?;
Ok(Longhands {
font_style: style,
font_variant: variant,