diff --git a/components/style/stylist.rs b/components/style/stylist.rs index c9211d8267c..29a0ae59a48 100644 --- a/components/style/stylist.rs +++ b/components/style/stylist.rs @@ -21,7 +21,7 @@ use properties::{AnimationRules, PropertyDeclarationBlock}; #[cfg(feature = "servo")] use properties::INHERIT_ALL; use properties::IS_LINK; -use rule_tree::{CascadeLevel, RuleTree, StyleSource}; +use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource}; use selector_map::{PrecomputedHashMap, SelectorMap, SelectorMapEntry}; use selector_parser::{SelectorImpl, PerPseudoElementMap, PseudoElement}; use selectors::attr::NamespaceConstraint; @@ -40,7 +40,7 @@ use std::ops; use style_traits::viewport::ViewportConstraints; use stylesheet_set::{OriginValidity, SheetRebuildKind, StylesheetSet, StylesheetIterator, StylesheetFlusher}; #[cfg(feature = "gecko")] -use stylesheets::{CounterStyleRule, FontFaceRule, FontFeatureValuesRule}; +use stylesheets::{CounterStyleRule, FontFaceRule, FontFeatureValuesRule, PageRule}; use stylesheets::{CssRule, Origin, OriginSet, PerOrigin, PerOriginIter}; #[cfg(feature = "gecko")] use stylesheets::{MallocEnclosingSizeOfFn, MallocSizeOf, MallocSizeOfBox, MallocSizeOfFn}; @@ -357,6 +357,12 @@ impl DocumentCascadeData { .borrow_mut_for_origin(&origin) .add_counter_style(guard, rule); } + #[cfg(feature = "gecko")] + CssRule::Page(ref rule) => { + _extra_data + .borrow_mut_for_origin(&origin) + .add_page(rule); + } // We don't care about any other rule. _ => {} } @@ -711,17 +717,33 @@ impl Stylist { ) -> Arc { debug_assert!(pseudo.is_precomputed()); - let rule_node = - match self.cascade_data.precomputed_pseudo_element_decls.get(pseudo) { - Some(declarations) => { - self.rule_tree.insert_ordered_rules_with_important( - declarations.into_iter().map(|a| (a.source.clone(), a.level())), - guards - ) - } - None => self.rule_tree.root().clone(), - }; + let rule_node = self.rule_node_for_precomputed_pseudo( + guards, + pseudo, + None, + ); + self.precomputed_values_for_pseudo_with_rule_node( + guards, + pseudo, + parent, + cascade_flags, + font_metrics, + &rule_node + ) + } + + /// Computes the style for a given "precomputed" pseudo-element with + /// given rule node. + pub fn precomputed_values_for_pseudo_with_rule_node( + &self, + guards: &StylesheetGuards, + pseudo: &PseudoElement, + parent: Option<&ComputedValues>, + cascade_flags: CascadeFlags, + font_metrics: &FontMetricsProvider, + rule_node: &StrongRuleNode + ) -> Arc { // NOTE(emilio): We skip calculating the proper layout parent style // here. // @@ -739,7 +761,7 @@ impl Stylist { properties::cascade( &self.device, Some(pseudo), - &rule_node, + rule_node, guards, parent, parent, @@ -751,6 +773,43 @@ impl Stylist { ) } + /// Returns the rule node for given precomputed pseudo-element. + /// + /// If we want to include extra declarations to this precomputed pseudo-element, + /// we can provide a vector of ApplicableDeclarationBlock to extra_declarations + /// argument. This is useful for providing extra @page rules. + pub fn rule_node_for_precomputed_pseudo( + &self, + guards: &StylesheetGuards, + pseudo: &PseudoElement, + extra_declarations: Option>, + ) -> StrongRuleNode { + let mut decl; + let declarations = match self.cascade_data.precomputed_pseudo_element_decls.get(pseudo) { + Some(declarations) => { + match extra_declarations { + Some(mut extra_decls) => { + decl = declarations.clone(); + decl.append(&mut extra_decls); + Some(&decl) + }, + None => Some(declarations), + } + } + None => extra_declarations.as_ref(), + }; + + match declarations { + Some(decls) => { + self.rule_tree.insert_ordered_rules_with_important( + decls.into_iter().map(|a| (a.source.clone(), a.level())), + guards + ) + }, + None => self.rule_tree.root().clone(), + } + } + /// Returns the style for an anonymous box of the given type. #[cfg(feature = "servo")] pub fn style_for_anonymous( @@ -1611,6 +1670,10 @@ pub struct ExtraStyleData { /// A map of effective counter-style rules. #[cfg(feature = "gecko")] pub counter_styles: PrecomputedHashMap>>, + + /// A map of effective page rules. + #[cfg(feature = "gecko")] + pub pages: Vec>>, } #[cfg(feature = "gecko")] @@ -1634,6 +1697,11 @@ impl ExtraStyleData { let name = rule.read_with(guard).mName.raw::().into(); self.counter_styles.insert(name, rule.clone()); } + + /// Add the given @page rule. + fn add_page(&mut self, rule: &Arc>) { + self.pages.push(rule.clone()); + } } impl ExtraStyleData { @@ -1643,6 +1711,7 @@ impl ExtraStyleData { self.font_faces.clear(); self.font_feature_values.clear(); self.counter_styles.clear(); + self.pages.clear(); } } diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index e13fe3b64d2..c615e082c79 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -12,6 +12,7 @@ use std::env; use std::fmt::Write; use std::iter; use std::ptr; +use style::applicable_declarations::ApplicableDeclarationBlock; use style::context::{CascadeInputs, QuirksMode, SharedStyleContext, StyleContext}; use style::context::ThreadLocalStyleContext; use style::data::ElementStyles; @@ -113,7 +114,7 @@ use style::properties::PROHIBIT_DISPLAY_CONTENTS; use style::properties::animated_properties::{AnimatableLonghand, AnimationValue}; use style::properties::animated_properties::compare_property_priority; use style::properties::parse_one_declaration_into; -use style::rule_tree::StyleSource; +use style::rule_tree::{CascadeLevel, StyleSource}; use style::selector_parser::PseudoElementCascadeType; use style::shared_lock::{SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard, Locked}; use style::string_cache::Atom; @@ -1679,11 +1680,44 @@ pub extern "C" fn Servo_ComputedValues_GetForAnonymousBox(parent_style_or_null: cascade_flags.insert(IS_FIELDSET_CONTENT); } let metrics = get_metrics_provider_for_product(); - data.stylist.precomputed_values_for_pseudo( + + // If the pseudo element is PageContent, we should append the precomputed + // pseudo element declerations with specified page rules. + let page_decls = match pseudo { + PseudoElement::PageContent => { + let mut declarations = vec![]; + let iter = data.extra_style_data.iter_origins_rev(); + for (data, origin) in iter { + let level = match origin { + Origin::UserAgent => CascadeLevel::UANormal, + Origin::User => CascadeLevel::UserNormal, + Origin::Author => CascadeLevel::AuthorNormal, + }; + for rule in data.pages.iter() { + declarations.push(ApplicableDeclarationBlock::from_declarations( + rule.read_with(level.guard(&guards)).block.clone(), + level + )); + } + } + Some(declarations) + }, + _ => None, + }; + + let rule_node = data.stylist.rule_node_for_precomputed_pseudo( + &guards, + &pseudo, + page_decls, + ); + + data.stylist.precomputed_values_for_pseudo_with_rule_node( &guards, &pseudo, parent_style_or_null.map(|x| &*x), - cascade_flags, &metrics + cascade_flags, + &metrics, + &rule_node ).into() }