Macroize @font-face descriptor definitions

This commit is contained in:
Simon Sapin 2017-01-31 18:07:06 +01:00
parent 2b83d844da
commit 4bcae573b3
3 changed files with 89 additions and 57 deletions

View file

@ -13,7 +13,7 @@ use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser};
use parser::{ParserContext, log_css_error, Parse}; use parser::{ParserContext, log_css_error, Parse};
use std::fmt; use std::fmt;
use std::iter; use std::iter;
use style_traits::ToCss; use style_traits::{ToCss, CommaSeparated};
use values::specified::url::SpecifiedUrl; use values::specified::url::SpecifiedUrl;
/// A source for a font-face rule. /// 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 /// A `UrlSource` represents a font-face source that has been specified with a
/// `url()` function. /// `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. /// Parse the block inside a `@font-face` rule.
/// ///
/// Note that the prelude parsing code lives in the `stylesheets` module. /// Note that the prelude parsing code lives in the `stylesheets` module.
pub fn parse_font_face_block(context: &ParserContext, input: &mut Parser) pub fn parse_font_face_block(context: &ParserContext, input: &mut Parser)
-> Result<FontFaceRule, ()> { -> Result<FontFaceRule, ()> {
let mut rule = FontFaceRule { let mut rule = FontFaceRule::initial();
family: FontFamily::Generic(atom!("")),
sources: Vec::new(),
};
{ {
let parser = FontFaceRuleParser { context: context, rule: &mut rule }; let parser = FontFaceRuleParser { context: context, rule: &mut rule };
let mut iter = DeclarationListParser::new(input, parser); let mut iter = DeclarationListParser::new(input, parser);
@ -174,20 +136,6 @@ impl<'a, 'b> AtRuleParser for FontFaceRuleParser<'a, 'b> {
type AtRule = (); 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> { impl Parse for Vec<Source> {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
input.parse_comma_separated(|input| Source::parse(context, input)) 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(),
}

View file

@ -59,4 +59,4 @@ pub mod cursor;
pub mod values; pub mod values;
pub mod viewport; pub mod viewport;
pub use values::ToCss; pub use values::{ToCss, CommaSeparated};

View file

@ -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 { impl ToCss for Au {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
write!(dest, "{}px", self.to_f64_px()) write!(dest, "{}px", self.to_f64_px())