--- 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;