diff options
author | Simon Sapin <simon.sapin@exyr.org> | 2017-01-31 18:07:06 +0100 |
---|---|---|
committer | Simon Sapin <simon.sapin@exyr.org> | 2017-02-02 18:32:02 +0100 |
commit | 4bcae573b3a93332802b95bebcf470caa98aa209 (patch) | |
tree | fbdbe95c0acfd110a3af7608bd476ed0e3c619b1 | |
parent | 2b83d844da5c07bc5068309bc5dcacbfc96c50d0 (diff) | |
download | servo-4bcae573b3a93332802b95bebcf470caa98aa209.tar.gz servo-4bcae573b3a93332802b95bebcf470caa98aa209.zip |
Macroize @font-face descriptor definitions
-rw-r--r-- | components/style/font_face.rs | 129 | ||||
-rw-r--r-- | components/style_traits/lib.rs | 2 | ||||
-rw-r--r-- | components/style_traits/values.rs | 15 |
3 files changed, 89 insertions, 57 deletions
diff --git a/components/style/font_face.rs b/components/style/font_face.rs index 0386ec16abf..649593c4cc9 100644 --- a/components/style/font_face.rs +++ b/components/style/font_face.rs @@ -13,7 +13,7 @@ use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser}; use parser::{ParserContext, log_css_error, Parse}; use std::fmt; use std::iter; -use style_traits::ToCss; +use style_traits::{ToCss, CommaSeparated}; use values::specified::url::SpecifiedUrl; /// A source for a font-face rule. @@ -44,6 +44,8 @@ impl ToCss for Source { } } +impl CommaSeparated for Source {} + /// A `UrlSource` represents a font-face source that has been specified with a /// `url()` function. /// @@ -65,52 +67,12 @@ impl ToCss for UrlSource { } } -/// A `@font-face` rule. -/// -/// https://drafts.csswg.org/css-fonts/#font-face-rule -#[derive(Debug, PartialEq, Eq)] -#[cfg_attr(feature = "servo", derive(HeapSizeOf))] -pub struct FontFaceRule { - /// The font family specified with the `font-family` property declaration. - pub family: FontFamily, - /// The list of sources specified with the different `src` property - /// declarations. - pub sources: Vec<Source>, -} - -impl ToCss for FontFaceRule { - // Serialization of FontFaceRule is not specced. - fn to_css<W>(&self, dest: &mut W) -> fmt::Result - where W: fmt::Write, - { - try!(dest.write_str("@font-face { font-family: ")); - try!(self.family.to_css(dest)); - try!(dest.write_str(";")); - - if self.sources.len() > 0 { - try!(dest.write_str(" src: ")); - let mut iter = self.sources.iter(); - try!(iter.next().unwrap().to_css(dest)); - for source in iter { - try!(dest.write_str(", ")); - try!(source.to_css(dest)); - } - try!(dest.write_str(";")); - } - - dest.write_str(" }") - } -} - /// Parse the block inside a `@font-face` rule. /// /// Note that the prelude parsing code lives in the `stylesheets` module. pub fn parse_font_face_block(context: &ParserContext, input: &mut Parser) -> Result<FontFaceRule, ()> { - let mut rule = FontFaceRule { - family: FontFamily::Generic(atom!("")), - sources: Vec::new(), - }; + let mut rule = FontFaceRule::initial(); { let parser = FontFaceRuleParser { context: context, rule: &mut rule }; let mut iter = DeclarationListParser::new(input, parser); @@ -174,20 +136,6 @@ impl<'a, 'b> AtRuleParser for FontFaceRuleParser<'a, 'b> { type AtRule = (); } - -impl<'a, 'b> DeclarationParser for FontFaceRuleParser<'a, 'b> { - type Declaration = (); - - fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<(), ()> { - match_ignore_ascii_case! { name, - "font-family" => self.rule.family = Parse::parse(self.context, input)?, - "src" => self.rule.sources = Parse::parse(self.context, input)?, - _ => return Err(()) - } - Ok(()) - } -} - impl Parse for Vec<Source> { fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { input.parse_comma_separated(|input| Source::parse(context, input)) @@ -221,3 +169,72 @@ impl Parse for Source { })) } } + +macro_rules! font_face_descriptors { + ( $( #[$doc: meta] $name: tt $ident: ident : $ty: ty = $initial: expr, )+ ) => { + /// A `@font-face` rule. + /// + /// https://drafts.csswg.org/css-fonts/#font-face-rule + #[derive(Debug, PartialEq, Eq)] + #[cfg_attr(feature = "servo", derive(HeapSizeOf))] + pub struct FontFaceRule { + $( + #[$doc] + pub $ident: $ty, + )+ + } + + impl FontFaceRule { + fn initial() -> Self { + FontFaceRule { + $( + $ident: $initial, + )+ + } + } + } + + impl ToCss for FontFaceRule { + // Serialization of FontFaceRule is not specced. + fn to_css<W>(&self, dest: &mut W) -> fmt::Result + where W: fmt::Write, + { + dest.write_str("@font-face {\n")?; + $( + // Because of parse_font_face_block, + // this condition is always true for "src" and "font-family". + // But it can be false for other descriptors. + if self.$ident != $initial { + dest.write_str(concat!(" ", $name, ": "))?; + self.$ident.to_css(dest)?; + dest.write_str(";\n")?; + } + )+ + dest.write_str("}") + } + } + + impl<'a, 'b> DeclarationParser for FontFaceRuleParser<'a, 'b> { + type Declaration = (); + + fn parse_value(&mut self, name: &str, input: &mut Parser) -> Result<(), ()> { + match_ignore_ascii_case! { name, + $( + $name => self.rule.$ident = Parse::parse(self.context, input)?, + )+ + _ => return Err(()) + } + Ok(()) + } + } + } +} + +/// css-name rust_identifier: Type = initial_value, +font_face_descriptors! { + /// The specified url. + "font-family" family: FontFamily = FontFamily::Generic(atom!("")), + + /// The format hints specified with the `format()` function. + "src" sources: Vec<Source> = Vec::new(), +} diff --git a/components/style_traits/lib.rs b/components/style_traits/lib.rs index 857624a5f9c..bc66db33d9d 100644 --- a/components/style_traits/lib.rs +++ b/components/style_traits/lib.rs @@ -59,4 +59,4 @@ pub mod cursor; pub mod values; pub mod viewport; -pub use values::ToCss; +pub use values::{ToCss, CommaSeparated}; diff --git a/components/style_traits/values.rs b/components/style_traits/values.rs index 59be4900523..5c23d74fbfa 100644 --- a/components/style_traits/values.rs +++ b/components/style_traits/values.rs @@ -24,6 +24,21 @@ pub trait ToCss { } } +/// Marker trait to automatically implement ToCss for Vec<T>. +pub trait CommaSeparated {} + +impl<T> ToCss for Vec<T> where T: ToCss + CommaSeparated { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + let mut iter = self.iter(); + iter.next().unwrap().to_css(dest)?; + for item in iter { + dest.write_str(", ")?; + item.to_css(dest)?; + } + Ok(()) + } +} + impl ToCss for Au { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { write!(dest, "{}px", self.to_f64_px()) |