Bug 1345206 - Servo parsing / serialization for @page. r=xidorn draft
authorJ. Ryan Stinnett <jryans@gmail.com>
Thu, 30 Mar 2017 20:05:55 -0500
changeset 558637 b8bd09a9df6cdc72a1e5a9f133e4421c29b2911b
parent 558636 e42258641c845ceb8354add4217c4360464a5911
child 558638 e53b122fdd0f57698247ec56677d9d7396bb6eff
push id52927
push userbmo:jryans@gmail.com
push dateFri, 07 Apr 2017 20:53:03 +0000
reviewersxidorn
bugs1345206
milestone55.0a1
Bug 1345206 - Servo parsing / serialization for @page. r=xidorn Adds basic parsing and serialization for @page rules in Servo. It is handled in the same manner as a regular style rule. MozReview-Commit-ID: JRr3DDGcUIl
servo/components/style/stylesheets.rs
--- a/servo/components/style/stylesheets.rs
+++ b/servo/components/style/stylesheets.rs
@@ -252,16 +252,17 @@ pub enum CssRule {
     Namespace(Arc<Locked<NamespaceRule>>),
     Import(Arc<Locked<ImportRule>>),
     Style(Arc<Locked<StyleRule>>),
     Media(Arc<Locked<MediaRule>>),
     FontFace(Arc<Locked<FontFaceRule>>),
     Viewport(Arc<Locked<ViewportRule>>),
     Keyframes(Arc<Locked<KeyframesRule>>),
     Supports(Arc<Locked<SupportsRule>>),
+    Page(Arc<Locked<PageRule>>),
 }
 
 #[allow(missing_docs)]
 pub enum CssRuleType {
     // https://drafts.csswg.org/cssom/#the-cssrule-interface
     Style               = 1,
     Charset             = 2,
     Import              = 3,
@@ -310,16 +311,17 @@ impl CssRule {
             CssRule::Style(_)     => CssRuleType::Style,
             CssRule::Import(_)    => CssRuleType::Import,
             CssRule::Media(_)     => CssRuleType::Media,
             CssRule::FontFace(_)  => CssRuleType::FontFace,
             CssRule::Keyframes(_) => CssRuleType::Keyframes,
             CssRule::Namespace(_) => CssRuleType::Namespace,
             CssRule::Viewport(_)  => CssRuleType::Viewport,
             CssRule::Supports(_)  => CssRuleType::Supports,
+            CssRule::Page(_)      => CssRuleType::Page,
         }
     }
 
     fn rule_state(&self) -> State {
         match *self {
             // CssRule::Charset(..) => State::Start,
             CssRule::Import(..) => State::Imports,
             CssRule::Namespace(..) => State::Namespaces,
@@ -343,17 +345,18 @@ impl CssRule {
                 // FIXME(emilio): Include the nested rules if the stylesheet is
                 // loaded.
                 f(&rules.0, Some(&media))
             }
             CssRule::Namespace(_) |
             CssRule::Style(_) |
             CssRule::FontFace(_) |
             CssRule::Viewport(_) |
-            CssRule::Keyframes(_) => {
+            CssRule::Keyframes(_) |
+            CssRule::Page(_) => {
                 f(&[], None)
             }
             CssRule::Media(ref lock) => {
                 let media_rule = lock.read_with(guard);
                 let mq = media_rule.media_queries.read_with(guard);
                 let rules = &media_rule.rules.read_with(guard).0;
                 f(rules, Some(&mq))
             }
@@ -416,16 +419,17 @@ impl ToCssWithGuard for CssRule {
             CssRule::Namespace(ref lock) => lock.read_with(guard).to_css(guard, dest),
             CssRule::Import(ref lock) => lock.read_with(guard).to_css(guard, dest),
             CssRule::Style(ref lock) => lock.read_with(guard).to_css(guard, dest),
             CssRule::FontFace(ref lock) => lock.read_with(guard).to_css(guard, dest),
             CssRule::Viewport(ref lock) => lock.read_with(guard).to_css(guard, dest),
             CssRule::Keyframes(ref lock) => lock.read_with(guard).to_css(guard, dest),
             CssRule::Media(ref lock) => lock.read_with(guard).to_css(guard, dest),
             CssRule::Supports(ref lock) => lock.read_with(guard).to_css(guard, dest),
+            CssRule::Page(ref lock) => lock.read_with(guard).to_css(guard, dest),
         }
     }
 }
 
 #[derive(Debug, PartialEq)]
 #[allow(missing_docs)]
 pub struct NamespaceRule {
     /// `None` for the default Namespace
@@ -554,16 +558,38 @@ impl ToCssWithGuard for SupportsRule {
         for rule in self.rules.read_with(guard).0.iter() {
             try!(dest.write_str(" "));
             try!(rule.to_css(guard, dest));
         }
         dest.write_str(" }")
     }
 }
 
+/// A [`@page`][page] rule.  This implements only a limited subset of the CSS 2.2 syntax.  In this
+/// subset, [page selectors][page-selectors] are not implemented.
+///
+/// [page]: https://drafts.csswg.org/css2/page.html#page-box
+/// [page-selectors]: https://drafts.csswg.org/css2/page.html#page-selectors
+#[derive(Debug)]
+pub struct PageRule(pub Arc<Locked<PropertyDeclarationBlock>>);
+
+impl ToCssWithGuard for PageRule {
+    // Serialization of PageRule is not specced, adapted from steps for StyleRule.
+    fn to_css<W>(&self, guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
+    where W: fmt::Write {
+        dest.write_str("@page { ")?;
+        let declaration_block = self.0.read_with(guard);
+        declaration_block.to_css(dest)?;
+        if declaration_block.declarations().len() > 0 {
+            write!(dest, " ")?;
+        }
+        dest.write_str("}")
+    }
+}
+
 #[allow(missing_docs)]
 #[derive(Debug)]
 pub struct StyleRule {
     pub selectors: SelectorList<SelectorImpl>,
     pub block: Arc<Locked<PropertyDeclarationBlock>>,
 }
 
 impl ToCssWithGuard for StyleRule {
@@ -776,16 +802,17 @@ macro_rules! rule_filter {
 
 rule_filter! {
     effective_style_rules(Style => StyleRule),
     effective_media_rules(Media => MediaRule),
     effective_font_face_rules(FontFace => FontFaceRule),
     effective_viewport_rules(Viewport => ViewportRule),
     effective_keyframes_rules(Keyframes => KeyframesRule),
     effective_supports_rules(Supports => SupportsRule),
+    effective_page_rules(Page => PageRule),
 }
 
 /// The stylesheet loader is the abstraction used to trigger network requests
 /// for `@import` rules.
 pub trait StylesheetLoader {
     /// Request a stylesheet after parsing a given `@import` rule.
     ///
     /// The called code is responsible to update the `stylesheet` rules field
@@ -852,16 +879,18 @@ enum AtRulePrelude {
     /// A @media rule prelude, with its media queries.
     Media(Arc<Locked<MediaList>>),
     /// An @supports rule, with its conditional
     Supports(SupportsCondition),
     /// A @viewport rule prelude.
     Viewport,
     /// A @keyframes rule, with its animation name.
     Keyframes(Atom),
+    /// A @page rule prelude.
+    Page,
 }
 
 
 impl<'a> AtRuleParser for TopLevelRuleParser<'a> {
     type Prelude = AtRulePrelude;
     type AtRule = CssRule;
 
     fn parse_prelude(&mut self, name: &str, input: &mut Parser)
@@ -1028,16 +1057,19 @@ impl<'a, 'b> AtRuleParser for NestedRule
                 let name = match input.next() {
                     Ok(Token::Ident(ref value)) if value != "none" => Atom::from(&**value),
                     Ok(Token::QuotedString(value)) => Atom::from(&*value),
                     _ => return Err(())
                 };
 
                 Ok(AtRuleType::WithBlock(AtRulePrelude::Keyframes(Atom::from(name))))
             },
+            "page" => {
+                Ok(AtRuleType::WithBlock(AtRulePrelude::Page))
+            },
             _ => Err(())
         }
     }
 
     fn parse_block(&mut self, prelude: AtRulePrelude, input: &mut Parser) -> Result<CssRule, ()> {
         match prelude {
             AtRulePrelude::FontFace => {
                 Ok(CssRule::FontFace(Arc::new(self.shared_lock.wrap(
@@ -1062,16 +1094,22 @@ impl<'a, 'b> AtRuleParser for NestedRule
                     try!(ViewportRule::parse(self.context, input))))))
             }
             AtRulePrelude::Keyframes(name) => {
                 Ok(CssRule::Keyframes(Arc::new(self.shared_lock.wrap(KeyframesRule {
                     name: name,
                     keyframes: parse_keyframe_list(&self.context, input, self.shared_lock),
                 }))))
             }
+            AtRulePrelude::Page => {
+                let declarations = parse_property_declaration_list(self.context, input);
+                Ok(CssRule::Page(Arc::new(self.shared_lock.wrap(PageRule(
+                    Arc::new(self.shared_lock.wrap(declarations))
+                )))))
+            }
         }
     }
 }
 
 impl<'a, 'b> QualifiedRuleParser for NestedRuleParser<'a, 'b> {
     type Prelude = SelectorList<SelectorImpl>;
     type QualifiedRule = CssRule;