Bug 1371963 - stylo: Fix :active and :hover quirk r?bholley
MozReview-Commit-ID: J8izztV7UNN
--- 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) |