servo: Merge #18398 - stylo: Pass the @page values to precomputed pseudo element declarations (from canaltinova:at-page-rule); r=emilio
authorNazım Can Altınova <canaltinova@gmail.com>
Wed, 06 Sep 2017 16:40:33 -0500
changeset 428747 c6d22c5e19ab5bcbfadd012dc6f712839c613774
parent 428746 7efa30ab3893c3eb67e99ca115200c7e403bf941
child 428748 d3fc822d7cf65b08c5e03bb63cc1c38ea0ea8093
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio
bugs1394035
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
servo: Merge #18398 - stylo: Pass the @page values to precomputed pseudo element declarations (from canaltinova:at-page-rule); r=emilio We were parsing @page rules correctly and serializing for cssom when we we need. But we weren't actually including them to the pseudo element declarations when we need to print a page. Reviewed by emilio on Bugzilla. --- - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix [Bug 1394035](https://bugzilla.mozilla.org/show_bug.cgi?id=1394035) Source-Repo: https://github.com/servo/servo Source-Revision: 094502e55f246b7c21d788385dda5c350ecf783a
servo/components/style/stylist.rs
servo/ports/geckolib/glue.rs
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -16,17 +16,17 @@ use gecko_bindings::structs::{nsIAtom, S
 use invalidation::element::invalidation_map::InvalidationMap;
 use invalidation::media_queries::{EffectiveMediaQueryResults, ToMediaListKey};
 use media_queries::Device;
 use properties::{self, CascadeFlags, ComputedValues};
 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;
 use selectors::bloom::{BloomFilter, NonCountingBloomFilter};
 use selectors::matching::{ElementSelectorFlags, matches_selector, MatchingContext, MatchingMode};
 use selectors::matching::VisitedHandlingMode;
 use selectors::parser::{AncestorHashes, Combinator, Component, Selector};
 use selectors::parser::{SelectorIter, SelectorMethods};
@@ -35,17 +35,17 @@ use selectors::visitor::SelectorVisitor;
 use servo_arc::{Arc, ArcBorrow};
 use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
 use smallvec::VecLike;
 use std::fmt::Debug;
 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};
 #[cfg(feature = "gecko")]
 use stylesheets::{MallocSizeOfHash, MallocSizeOfVec};
 use stylesheets::StyleRule;
 use stylesheets::StylesheetInDocument;
 use stylesheets::UserAgentStylesheets;
@@ -352,16 +352,22 @@ impl DocumentCascadeData {
                         .add_font_feature_values(rule);
                 }
                 #[cfg(feature = "gecko")]
                 CssRule::CounterStyle(ref rule) => {
                     _extra_data
                         .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.
                 _ => {}
             }
         }
     }
 
     /// Measures heap usage.
     #[cfg(feature = "gecko")]
@@ -706,27 +712,43 @@ impl Stylist {
         guards: &StylesheetGuards,
         pseudo: &PseudoElement,
         parent: Option<&ComputedValues>,
         cascade_flags: CascadeFlags,
         font_metrics: &FontMetricsProvider
     ) -> Arc<ComputedValues> {
         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<ComputedValues> {
         // NOTE(emilio): We skip calculating the proper layout parent style
         // here.
         //
         // It'd be fine to assert that this isn't called with a parent style
         // where display contents is in effect, but in practice this is hard to
         // do for stuff like :-moz-fieldset-content with a
         // <fieldset style="display: contents">. That is, the computed value of
         // display for the fieldset is "contents", even though it's not the used
@@ -734,28 +756,65 @@ impl Stylist {
         //
         // In practice, I don't think any anonymous content can be a direct
         // descendant of a display: contents element where display: contents is
         // the actual used value, and the computed value of it would need
         // blockification.
         properties::cascade(
             &self.device,
             Some(pseudo),
-            &rule_node,
+            rule_node,
             guards,
             parent,
             parent,
             parent,
             None,
             font_metrics,
             cascade_flags,
             self.quirks_mode,
         )
     }
 
+    /// 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<Vec<ApplicableDeclarationBlock>>,
+    ) -> 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(
         &self,
         guards: &StylesheetGuards,
         pseudo: &PseudoElement,
         parent_style: &ComputedValues
     ) -> Arc<ComputedValues> {
@@ -1606,16 +1665,20 @@ pub struct ExtraStyleData {
 
     /// A list of effective font-feature-values rules.
     #[cfg(feature = "gecko")]
     pub font_feature_values: Vec<Arc<Locked<FontFeatureValuesRule>>>,
 
     /// A map of effective counter-style rules.
     #[cfg(feature = "gecko")]
     pub counter_styles: PrecomputedHashMap<Atom, Arc<Locked<CounterStyleRule>>>,
+
+    /// A map of effective page rules.
+    #[cfg(feature = "gecko")]
+    pub pages: Vec<Arc<Locked<PageRule>>>,
 }
 
 #[cfg(feature = "gecko")]
 impl ExtraStyleData {
     /// Add the given @font-face rule.
     fn add_font_face(&mut self, rule: &Arc<Locked<FontFaceRule>>) {
         self.font_faces.push(rule.clone());
     }
@@ -1629,25 +1692,31 @@ impl ExtraStyleData {
     fn add_counter_style(
         &mut self,
         guard: &SharedRwLockReadGuard,
         rule: &Arc<Locked<CounterStyleRule>>,
     ) {
         let name = rule.read_with(guard).mName.raw::<nsIAtom>().into();
         self.counter_styles.insert(name, rule.clone());
     }
+
+    /// Add the given @page rule.
+    fn add_page(&mut self, rule: &Arc<Locked<PageRule>>) {
+        self.pages.push(rule.clone());
+    }
 }
 
 impl ExtraStyleData {
     fn clear(&mut self) {
         #[cfg(feature = "gecko")]
         {
             self.font_faces.clear();
             self.font_feature_values.clear();
             self.counter_styles.clear();
+            self.pages.clear();
         }
     }
 
     /// Measure heap usage.
     #[cfg(feature = "gecko")]
     pub fn malloc_size_of_children(&self, malloc_size_of: MallocSizeOfFn,
                                    malloc_enclosing_size_of: MallocEnclosingSizeOfFn) -> usize {
         let mut n = 0;
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -7,16 +7,17 @@ use cssparser::ToCss as ParserToCss;
 use env_logger::LogBuilder;
 use selectors::Element;
 use selectors::matching::{MatchingContext, MatchingMode, matches_selector};
 use servo_arc::{Arc, ArcBorrow, RawOffsetArc};
 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;
 use style::dom::{ShowSubtreeData, TElement, TNode};
 use style::driver;
 use style::element_state::ElementState;
 use style::error_reporting::{NullReporter, ParseErrorReporter};
 use style::font_metrics::{FontMetricsProvider, get_metrics_provider_for_product};
@@ -108,17 +109,17 @@ use style::parser::{ParserContext, self}
 use style::properties::{CascadeFlags, ComputedValues, Importance};
 use style::properties::{IS_FIELDSET_CONTENT, IS_LINK, IS_VISITED_LINK, LonghandIdSet};
 use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, PropertyId, ShorthandId};
 use style::properties::{SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP, SourcePropertyDeclaration, StyleBuilder};
 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;
 use style::style_adjuster::StyleAdjuster;
 use style::stylesheets::{CssRule, CssRules, CssRuleType, CssRulesHelpers, DocumentRule};
 use style::stylesheets::{FontFeatureValuesRule, ImportRule, KeyframesRule, MallocEnclosingSizeOfFn};
 use style::stylesheets::{MallocSizeOfFn, MallocSizeOfWithGuard, MediaRule};
 use style::stylesheets::{NamespaceRule, Origin, OriginSet, PageRule, SizeOfState, StyleRule};
@@ -1674,21 +1675,54 @@ pub extern "C" fn Servo_ComputedValues_G
     let pseudo = PseudoElement::from_anon_box_atom(&atom)
         .expect("Not an anon box pseudo?");
 
     let mut cascade_flags = SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP;
     if pseudo.is_fieldset_content() {
         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()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_ResolvePseudoStyle(element: RawGeckoElementBorrowed,
                                            pseudo_type: CSSPseudoElementType,
                                            is_probe: bool,
                                            inherited_style: ServoStyleContextBorrowedOrNull,