diff --git a/components/script/dom/cssrule.rs b/components/script/dom/cssrule.rs index 54bb8c175a5..1a24d5839bf 100644 --- a/components/script/dom/cssrule.rs +++ b/components/script/dom/cssrule.rs @@ -83,6 +83,7 @@ impl CSSRule { StyleCssRule::Namespace(s) => Root::upcast(CSSNamespaceRule::new(window, parent_stylesheet, s)), StyleCssRule::Viewport(s) => Root::upcast(CSSViewportRule::new(window, parent_stylesheet, s)), StyleCssRule::Supports(s) => Root::upcast(CSSSupportsRule::new(window, parent_stylesheet, s)), + StyleCssRule::Page(_) => unreachable!(), } } diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs index 822f59478a0..6856de8c236 100644 --- a/components/style/stylesheets.rs +++ b/components/style/stylesheets.rs @@ -258,6 +258,7 @@ pub enum CssRule { Viewport(Arc>), Keyframes(Arc>), Supports(Arc>), + Page(Arc>), } #[allow(missing_docs)] @@ -316,6 +317,7 @@ impl CssRule { CssRule::Namespace(_) => CssRuleType::Namespace, CssRule::Viewport(_) => CssRuleType::Viewport, CssRule::Supports(_) => CssRuleType::Supports, + CssRule::Page(_) => CssRuleType::Page, } } @@ -349,7 +351,8 @@ impl CssRule { CssRule::Style(_) | CssRule::FontFace(_) | CssRule::Viewport(_) | - CssRule::Keyframes(_) => { + CssRule::Keyframes(_) | + CssRule::Page(_) => { f(&[], None) } CssRule::Media(ref lock) => { @@ -422,6 +425,7 @@ impl ToCssWithGuard for CssRule { 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), } } } @@ -560,6 +564,28 @@ impl ToCssWithGuard for SupportsRule { } } +/// 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>); + +impl ToCssWithGuard for PageRule { + // Serialization of PageRule is not specced, adapted from steps for StyleRule. + fn to_css(&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 { @@ -782,6 +808,7 @@ rule_filter! { 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 @@ -858,6 +885,8 @@ enum AtRulePrelude { Viewport, /// A @keyframes rule, with its animation name. Keyframes(Atom), + /// A @page rule prelude. + Page, } @@ -1043,6 +1072,13 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> { Ok(AtRuleType::WithBlock(AtRulePrelude::Keyframes(Atom::from(name)))) }, + "page" => { + if cfg!(feature = "gecko") { + Ok(AtRuleType::WithBlock(AtRulePrelude::Page)) + } else { + Err(()) + } + }, _ => Err(()) } } @@ -1077,6 +1113,12 @@ impl<'a, 'b> AtRuleParser for NestedRuleParser<'a, 'b> { 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)) + ))))) + } } } }