Bug 1370358 - Stop looking for relevant links once found. r=emilio draft
authorJ. Ryan Stinnett <jryans@gmail.com>
Tue, 06 Jun 2017 17:04:03 -0500
changeset 589821 a8dda4cabce71851d42222b59996ac58b72e2a21
parent 589820 787661f9033fbc08337641f3b8e363c77cd8cffa
child 589822 f28486381bf253be0e8a39744dc279927b73430a
push id62533
push userbmo:jryans@gmail.com
push dateTue, 06 Jun 2017 22:27:16 +0000
reviewersemilio
bugs1370358
milestone55.0a1
Bug 1370358 - Stop looking for relevant links once found. r=emilio Once we've encountered a relevant link, stop looking for potential relevant link. A relevant link is only the nearest ancestor link, so it is incorrect to keep looking once one is found. This only matters for the somewhat unusual case of nested links. MozReview-Commit-ID: LiXsUGWfxg3
servo/components/selectors/matching.rs
--- a/servo/components/selectors/matching.rs
+++ b/servo/components/selectors/matching.rs
@@ -217,17 +217,23 @@ impl Default for RelevantLinkStatus {
 impl RelevantLinkStatus {
     /// If we found the relevant link for this element, record that in the
     /// overall matching context for the element as a whole and stop looking for
     /// addtional links.
     fn examine_potential_link<E>(&self, element: &E, context: &mut MatchingContext)
                                  -> RelevantLinkStatus
         where E: Element,
     {
-        if *self != RelevantLinkStatus::Looking {
+        // If a relevant link was previously found, we no longer want to look
+        // for links.  Only the nearest ancestor link is considered relevant.
+        if *self == RelevantLinkStatus::Found {
+            return RelevantLinkStatus::NotLooking
+        }
+
+        if *self == RelevantLinkStatus::NotLooking {
             return *self
         }
 
         if !element.is_link() {
             return *self
         }
 
         // We found a relevant link. Record this in the `MatchingContext`,
@@ -386,33 +392,33 @@ pub fn matches_complex_selector<E, F>(co
             }
             _ => panic!("Used MatchingMode::ForStatelessPseudoElement in a non-pseudo selector"),
         }
     }
 
     match matches_complex_selector_internal(iter,
                                             element,
                                             context,
-                                            RelevantLinkStatus::Looking,
+                                            &mut RelevantLinkStatus::Looking,
                                             flags_setter) {
         SelectorMatchingResult::Matched => true,
         _ => false
     }
 }
 
 fn matches_complex_selector_internal<E, F>(mut selector_iter: SelectorIter<E::Impl>,
                                            element: &E,
                                            context: &mut MatchingContext,
-                                           relevant_link: RelevantLinkStatus,
+                                           relevant_link: &mut RelevantLinkStatus,
                                            flags_setter: &mut F)
                                            -> SelectorMatchingResult
      where E: Element,
            F: FnMut(&E, ElementSelectorFlags),
 {
-    let mut relevant_link = relevant_link.examine_potential_link(element, context);
+    *relevant_link = relevant_link.examine_potential_link(element, context);
 
     let matches_all_simple_selectors = selector_iter.all(|simple| {
         matches_simple_selector(simple, element, context, &relevant_link, flags_setter)
     });
 
     debug!("Matching for {:?}, simple selector {:?}, relevant link {:?}",
            element, selector_iter, relevant_link);
 
@@ -428,17 +434,17 @@ fn matches_complex_selector_internal<E, 
 
     match combinator {
         None => SelectorMatchingResult::Matched,
         Some(c) => {
             let (mut next_element, candidate_not_found) = match c {
                 Combinator::NextSibling | Combinator::LaterSibling => {
                     // Only ancestor combinators are allowed while looking for
                     // relevant links, so switch to not looking.
-                    relevant_link = RelevantLinkStatus::NotLooking;
+                    *relevant_link = RelevantLinkStatus::NotLooking;
                     (element.prev_sibling_element(),
                      SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant)
                 }
                 Combinator::Child | Combinator::Descendant => {
                     (element.parent_element(),
                      SelectorMatchingResult::NotMatchedGlobally)
                 }
                 Combinator::PseudoElement => {