Bug 1371963 - stylo: Fix :active and :hover quirk r?bholley draft
authorNazım Can Altınova <canaltinova@gmail.com>
Tue, 13 Jun 2017 04:51:19 +0300
changeset 592964 9c19a20865b760d2a820fa70ded2d320742ae76d
parent 592285 981da978f1f686ad024fa958c9d27d2f8acc5ad0
child 592965 9febbf440108644c1c269c7f14f8ec0a7686dcc0
push id63556
push userbmo:canaltinova@gmail.com
push dateTue, 13 Jun 2017 01:52:34 +0000
reviewersbholley
bugs1371963
milestone55.0a1
Bug 1371963 - stylo: Fix :active and :hover quirk r?bholley MozReview-Commit-ID: J8izztV7UNN
servo/components/selectors/matching.rs
servo/components/style/gecko/wrapper.rs
--- a/servo/components/selectors/matching.rs
+++ b/servo/components/selectors/matching.rs
@@ -179,50 +179,58 @@ pub struct LocalMatchingContext<'a, 'b: 
     pub selector: &'a Selector<Impl>,
     /// The offset of the current compound selector being matched, kept up to date by
     /// the callees when the iterator is advanced. This, in conjunction with the selector
     /// reference above, allows callees to synthesize an iterator for the current compound
     /// selector on-demand. This is necessary because the primary iterator may already have
     /// been advanced partway through the current compound selector, and the callee may need
     /// the whole thing.
     offset: usize,
-    /// Holds a bool flag to see if LocalMatchingContext is within a functional
-    /// pseudo class argument. This is used for pseudo classes like
-    /// `:-moz-any` or `:not`. If this flag is true, :active and :hover
-    /// quirk shouldn't match.
-    pub within_functional_pseudo_class_argument: bool,
+    /// Holds a bool flag to see whether :active and :hover quirk should try to
+    /// match or not. This flag can only be true in these two cases:
+    /// - LocalMatchingContext is currently within a functional pseudo class
+    /// like `:-moz-any` or `:not`.
+    /// - PseudoElements are encountered when matching mode is ForStatelessPseudoElement.
+    pub hover_active_quirk_disabled: bool,
 }
 
 impl<'a, 'b, Impl> LocalMatchingContext<'a, 'b, Impl>
     where Impl: SelectorImpl
 {
     /// Constructs a new `LocalMatchingContext`.
     pub fn new(shared: &'a mut MatchingContext<'b>,
                selector: &'a Selector<Impl>) -> Self {
         Self {
             shared: shared,
             selector: selector,
             offset: 0,
-            within_functional_pseudo_class_argument: false,
+            hover_active_quirk_disabled: selector.has_pseudo_element(),
         }
     }
 
     /// Updates offset of Selector to show new compound selector.
     /// To be able to correctly re-synthesize main SelectorIter.
     pub fn note_next_sequence(&mut self, selector_iter: &SelectorIter<Impl>) {
         if let QuirksMode::Quirks = self.shared.quirks_mode {
+            if self.selector.has_pseudo_element() && self.offset != 0 {
+                // This is the _second_ call to note_next_sequence,
+                // which means we've moved past the compound
+                // selector adjacent to the pseudo-element.
+                self.hover_active_quirk_disabled = false;
+            }
+
             self.offset = self.selector.len() - selector_iter.selector_length();
         }
     }
 
     /// Returns true if current compound selector matches :active and :hover quirk.
     /// https://quirks.spec.whatwg.org/#the-active-and-hover-quirk
     pub fn active_hover_quirk_matches(&mut self) -> bool {
         if self.shared.quirks_mode != QuirksMode::Quirks ||
-           self.within_functional_pseudo_class_argument {
+           self.hover_active_quirk_disabled {
             return false;
         }
 
         let mut iter = if self.offset == 0 {
             self.selector.iter()
         } else {
             self.selector.iter_from(self.offset)
         };
@@ -756,23 +764,23 @@ fn matches_simple_selector<E, F>(
         Component::LastOfType => {
             matches_generic_nth_child(element, 0, 1, true, true, flags_setter)
         }
         Component::OnlyOfType => {
             matches_generic_nth_child(element, 0, 1, true, false, flags_setter) &&
             matches_generic_nth_child(element, 0, 1, true, true, flags_setter)
         }
         Component::Negation(ref negated) => {
-            let old_value = context.within_functional_pseudo_class_argument;
-            context.within_functional_pseudo_class_argument = true;
+            let old_value = context.hover_active_quirk_disabled;
+            context.hover_active_quirk_disabled = true;
             let result = !negated.iter().all(|ss| {
                 matches_simple_selector(ss, element, context,
                                         relevant_link, flags_setter)
             });
-            context.within_functional_pseudo_class_argument = old_value;
+            context.hover_active_quirk_disabled = old_value;
             result
         }
     }
 }
 
 fn select_name<'a, T>(is_html: bool, local_name: &'a T, local_name_lower: &'a T) -> &'a T {
     if is_html {
         local_name_lower
--- a/servo/components/style/gecko/wrapper.rs
+++ b/servo/components/style/gecko/wrapper.rs
@@ -1521,22 +1521,22 @@ impl<'le> ::selectors::Element for Gecko
             NonTSPseudoClass::MozNativeAnonymous => unsafe {
                 Gecko_MatchesElement(pseudo_class.to_gecko_pseudoclasstype().unwrap(), self.0)
             },
             NonTSPseudoClass::MozIsHTML => {
                 self.is_html_element_in_html_document()
             }
             NonTSPseudoClass::MozPlaceholder => false,
             NonTSPseudoClass::MozAny(ref sels) => {
-                let old_value = context.within_functional_pseudo_class_argument;
-                context.within_functional_pseudo_class_argument = true;
+                let old_value = context.hover_active_quirk_disabled;
+                context.hover_active_quirk_disabled = true;
                 let result = sels.iter().any(|s| {
                     matches_complex_selector(s, 0, self, context, flags_setter)
                 });
-                context.within_functional_pseudo_class_argument = old_value;
+                context.hover_active_quirk_disabled = old_value;
                 result
             }
             NonTSPseudoClass::Lang(ref lang_arg) => {
                 self.match_element_lang(None, lang_arg)
             }
             NonTSPseudoClass::MozSystemMetric(ref s) |
             NonTSPseudoClass::MozLocaleDir(ref s) |
             NonTSPseudoClass::MozEmptyExceptChildrenWithLocalname(ref s) |