servo: Merge #18652 - style: Fix various issues with XBL rule matching (from emilio:xbl-stuff); r=TYLin
authorEmilio Cobos Álvarez <emilio@crisal.io>
Wed, 27 Sep 2017 09:15:16 -0500
changeset 383296 44053b9ef955feebc91703fab88c8719c02e1ffd
parent 383295 4f9b0c2f439dd1bb7a7c8542090b017e2e1ab177
child 383297 7fc714dba604f7c47747e043a11e9d1bd23afb60
push id95539
push userkwierso@gmail.com
push dateThu, 28 Sep 2017 00:01:12 +0000
treeherdermozilla-inbound@72de90e66155 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersTYLin
milestone58.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 #18652 - style: Fix various issues with XBL rule matching (from emilio:xbl-stuff); r=TYLin See the commit details. Source-Repo: https://github.com/servo/servo Source-Revision: bad77b6a20ee9bdba27d0af9edd1dd638c73d64b
servo/components/style/dom.rs
servo/components/style/stylist.rs
--- a/servo/components/style/dom.rs
+++ b/servo/components/style/dom.rs
@@ -21,17 +21,16 @@ use properties::{AnimationRules, Compute
 #[cfg(feature = "gecko")] use properties::animated_properties::TransitionProperty;
 use rule_tree::CascadeLevel;
 use selector_parser::{AttrValue, ElementExt};
 use selector_parser::{PseudoClassStringArg, PseudoElement};
 use selectors::matching::{ElementSelectorFlags, VisitedHandlingMode};
 use selectors::sink::Push;
 use servo_arc::{Arc, ArcBorrow};
 use shared_lock::Locked;
-use smallvec::VecLike;
 use std::fmt;
 #[cfg(feature = "gecko")] use hash::HashMap;
 use std::fmt::Debug;
 use std::hash::Hash;
 use std::ops::Deref;
 use stylist::Stylist;
 use traversal_flags::{TraversalFlags, self};
 
@@ -643,34 +642,16 @@ pub trait TElement : Eq + PartialEq + De
     /// Returns whether to cut off the inheritance.
     fn each_xbl_stylist<F>(&self, _: F) -> bool
     where
         F: FnMut(&Stylist),
     {
         false
     }
 
-    /// Gets declarations from XBL bindings from the element.
-    fn get_declarations_from_xbl_bindings<V>(
-        &self,
-        pseudo_element: Option<&PseudoElement>,
-        applicable_declarations: &mut V
-    ) -> bool
-    where
-        V: Push<ApplicableDeclarationBlock> + VecLike<ApplicableDeclarationBlock>
-    {
-        self.each_xbl_stylist(|stylist| {
-            stylist.push_applicable_declarations_as_xbl_only_stylist(
-                self,
-                pseudo_element,
-                applicable_declarations
-            );
-        })
-    }
-
     /// Gets the current existing CSS transitions, by |property, end value| pairs in a HashMap.
     #[cfg(feature = "gecko")]
     fn get_css_transitions_info(&self)
                                 -> HashMap<TransitionProperty, Arc<AnimationValue>>;
 
     /// Does a rough (and cheap) check for whether or not transitions might need to be updated that
     /// will quickly return false for the common case of no transitions specified or running. If
     /// this returns false, we definitely don't need to update transitions but if it returns true
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -959,22 +959,16 @@ impl Stylist {
             font_metrics,
             cascade_flags,
             self.quirks_mode,
             /* rule_cache = */ None,
             &mut Default::default(),
         )
     }
 
-    fn has_rules_for_pseudo(&self, pseudo: &PseudoElement) -> bool {
-        self.cascade_data
-            .iter_origins()
-            .any(|(d, _)| d.has_rules_for_pseudo(pseudo))
-    }
-
     /// Computes the cascade inputs for a lazily-cascaded pseudo-element.
     ///
     /// See the documentation on lazy pseudo-elements in
     /// docs/components/style.md
     pub fn lazy_pseudo_rules<E>(
         &self,
         guards: &StylesheetGuards,
         element: &E,
@@ -983,20 +977,16 @@ impl Stylist {
         rule_inclusion: RuleInclusion
     ) -> CascadeInputs
     where
         E: TElement
     {
         let pseudo = pseudo.canonical();
         debug_assert!(pseudo.is_lazy());
 
-        if !self.has_rules_for_pseudo(&pseudo) {
-            return CascadeInputs::default()
-        }
-
         // Apply the selector flags. We should be in sequential mode
         // already, so we can directly apply the parent flags.
         let mut set_selector_flags = |element: &E, flags: ElementSelectorFlags| {
             if cfg!(feature = "servo") {
                 // Servo calls this function from the worker, but only for internal
                 // pseudos, so we should never generate selector flags here.
                 unreachable!("internal pseudo generated slow selector flags?");
             }
@@ -1020,20 +1010,22 @@ impl Stylist {
                     unsafe { p.set_selector_flags(parent_flags); }
                 }
             }
         };
 
         let mut inputs = CascadeInputs::default();
         let mut declarations = ApplicableDeclarationList::new();
         let mut matching_context =
-            MatchingContext::new(MatchingMode::ForStatelessPseudoElement,
-                                 None,
-                                 None,
-                                 self.quirks_mode);
+            MatchingContext::new(
+                MatchingMode::ForStatelessPseudoElement,
+                None,
+                None,
+                self.quirks_mode,
+            );
 
         self.push_applicable_declarations(
             element,
             Some(&pseudo),
             None,
             None,
             AnimationRules(None, None),
             rule_inclusion,
@@ -1186,49 +1178,16 @@ impl Stylist {
         // during multiple layout passes, but this is totally bogus, in the
         // sense that it's updated asynchronously.
         //
         // This should probably be an argument to `update`, and use the quirks
         // mode info in the `SharedLayoutContext`.
         self.quirks_mode = quirks_mode;
     }
 
-    /// Returns the applicable CSS declarations for the given element by
-    /// treating us as an XBL stylesheet-only stylist.
-    pub fn push_applicable_declarations_as_xbl_only_stylist<E, V>(
-        &self,
-        element: &E,
-        pseudo_element: Option<&PseudoElement>,
-        applicable_declarations: &mut V
-    )
-    where
-        E: TElement,
-        V: Push<ApplicableDeclarationBlock> + VecLike<ApplicableDeclarationBlock>,
-    {
-        let mut matching_context =
-            MatchingContext::new(MatchingMode::Normal, None, None, self.quirks_mode);
-        let mut dummy_flag_setter = |_: &E, _: ElementSelectorFlags| {};
-
-        let rule_hash_target = element.rule_hash_target();
-
-        // nsXBLPrototypeResources::LoadResources() loads Chrome XBL style
-        // sheets under eAuthorSheetFeatures level.
-        if let Some(map) = self.cascade_data.author.borrow_for_pseudo(pseudo_element) {
-            map.get_all_matching_rules(
-                element,
-                &rule_hash_target,
-                applicable_declarations,
-                &mut matching_context,
-                self.quirks_mode,
-                &mut dummy_flag_setter,
-                CascadeLevel::XBL,
-            );
-        }
-    }
-
     /// Returns the applicable CSS declarations for the given element.
     ///
     /// This corresponds to `ElementRuleCollector` in WebKit.
     pub fn push_applicable_declarations<E, V, F>(
         &self,
         element: &E,
         pseudo_element: Option<&PseudoElement>,
         style_attribute: Option<ArcBorrow<Locked<PropertyDeclarationBlock>>>,
@@ -1308,21 +1267,31 @@ impl Stylist {
                     CascadeLevel::UserNormal,
                 );
             }
         } else {
             debug!("skipping user rules");
         }
 
         // Step 3b: XBL rules.
-        let cut_off_inheritance =
-            element.get_declarations_from_xbl_bindings(
-                pseudo_element,
-                applicable_declarations,
-            );
+        let cut_off_inheritance = element.each_xbl_stylist(|stylist| {
+            // ServoStyleSet::CreateXBLServoStyleSet() loads XBL style sheets
+            // under eAuthorSheetFeatures level.
+            if let Some(map) = stylist.cascade_data.author.borrow_for_pseudo(pseudo_element) {
+                map.get_all_matching_rules(
+                    element,
+                    &rule_hash_target,
+                    applicable_declarations,
+                    context,
+                    self.quirks_mode,
+                    flags_setter,
+                    CascadeLevel::XBL,
+                );
+            }
+        });
 
         if rule_hash_target.matches_user_and_author_rules() && !only_default_rules {
             // Gecko skips author normal rules if cutting off inheritance.
             // See nsStyleSet::FileRules().
             if !cut_off_inheritance {
                 // Step 3c: Author normal rules.
                 if let Some(map) = self.cascade_data.author.borrow_for_pseudo(pseudo_element) {
                     map.get_all_matching_rules(
@@ -2190,20 +2159,16 @@ impl CascadeData {
     #[inline]
     fn borrow_for_pseudo(&self, pseudo: Option<&PseudoElement>) -> Option<&SelectorMap<Rule>> {
         match pseudo {
             Some(pseudo) => self.pseudos_map.get(&pseudo.canonical()).map(|p| &**p),
             None => Some(&self.element_map),
         }
     }
 
-    fn has_rules_for_pseudo(&self, pseudo: &PseudoElement) -> bool {
-        self.pseudos_map.get(pseudo).is_some()
-    }
-
     /// Clears the cascade data, but not the invalidation data.
     fn clear_cascade_data(&mut self) {
         self.element_map.clear();
         self.pseudos_map.clear();
         self.animations.clear();
         self.extra_data.clear();
         self.rules_source_order = 0;
         self.num_selectors = 0;