mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
auto merge of #1971 : Constellation/servo/quick-fail-selector-matching, r=SimonSapin
Restart selector matching from an appropriate selector Introducing 3 matching failure statuses, + NotMatchedGlobally + NotMatchedAndRestartFromClosestDescendant + NotMatchedAndRestartFromClosestLaterSibling When NotMatchedGlobally appears, stop selector matching completely since the succeeding selector never matches. It is raised when + Child selector cannot find the candidate element + Descendant selector cannot find the candidate element When NotMatchedAndRestartFromClosestDescendant appears, the selector matching does backtracking and restarts from the closest Descendant selector. It is raised when + NextSibling selector cannot find the candidate element. + LaterSibling selector cannot find the candidate element. + Child selector doesn't match on the found element. When NotMatchedAndRestartFromClosestLaterSibling appears, the selector matching does backtracking and restarts from the closest LaterSibling selector. It is raised when + NextSibling selector doesn't match on the found element. For example, when the selector "d1 d2 a" is provided and we cannot *find* an appropriate ancestor node for "d1", this selector matching raises NotMatchedGlobally since even if "d2" is moved to more upper node, the candidates for "d1" becomes less than before and d1 . The next example is siblings. When the selector "b1 + b2 ~ d1 a" is providied and we cannot *find* an appropriate brother node for b1, the selector matching raises NotMatchedAndRestartFromClosestDescendant. The selectors ("b1 + b2 ~") doesn't match and matching restart from "d1". The additional example is child and sibling. When the selector "b1 + c1 > b2 ~ d1 a" is provided and the selector "b1" doesn't match on the element, this "b1" raises NotMatchedAndRestartFromClosestLaterSibling. However since the selector "c1" raises NotMatchedAndRestartFromClosestDescendant. So the selector "b1 + c1 > b2 ~ " doesn't match and restart matching from "d1".
This commit is contained in:
commit
7ece5f92db
1 changed files with 96 additions and 12 deletions
|
@ -527,19 +527,80 @@ fn matches_compound_selector<E:TElement,
|
||||||
element: &N,
|
element: &N,
|
||||||
shareable: &mut bool)
|
shareable: &mut bool)
|
||||||
-> bool {
|
-> bool {
|
||||||
|
match matches_compound_selector_internal(selector, element, shareable) {
|
||||||
|
Matched => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A result of selector matching, includes 3 failure types,
|
||||||
|
///
|
||||||
|
/// NotMatchedAndRestartFromClosestLaterSibling
|
||||||
|
/// NotMatchedAndRestartFromClosestDescendant
|
||||||
|
/// NotMatchedGlobally
|
||||||
|
///
|
||||||
|
/// When NotMatchedGlobally appears, stop selector matching completely since
|
||||||
|
/// the succeeding selectors never matches.
|
||||||
|
/// It is raised when
|
||||||
|
/// Child combinator cannot find the candidate element.
|
||||||
|
/// Descendant combinator cannot find the candidate element.
|
||||||
|
///
|
||||||
|
/// When NotMatchedAndRestartFromClosestDescendant appears, the selector
|
||||||
|
/// matching does backtracking and restarts from the closest Descendant
|
||||||
|
/// combinator.
|
||||||
|
/// It is raised when
|
||||||
|
/// NextSibling combinator cannot find the candidate element.
|
||||||
|
/// LaterSibling combinator cannot find the candidate element.
|
||||||
|
/// Child combinator doesn't match on the found element.
|
||||||
|
///
|
||||||
|
/// When NotMatchedAndRestartFromClosestLaterSibling appears, the selector
|
||||||
|
/// matching does backtracking and restarts from the closest LaterSibling
|
||||||
|
/// combinator.
|
||||||
|
/// It is raised when
|
||||||
|
/// NextSibling combinator doesn't match on the found element.
|
||||||
|
///
|
||||||
|
/// For example, when the selector "d1 d2 a" is provided and we cannot *find*
|
||||||
|
/// an appropriate ancestor node for "d1", this selector matching raises
|
||||||
|
/// NotMatchedGlobally since even if "d2" is moved to more upper node, the
|
||||||
|
/// candidates for "d1" becomes less than before and d1 .
|
||||||
|
///
|
||||||
|
/// The next example is siblings. When the selector "b1 + b2 ~ d1 a" is
|
||||||
|
/// providied and we cannot *find* an appropriate brother node for b1,
|
||||||
|
/// the selector matching raises NotMatchedAndRestartFromClosestDescendant.
|
||||||
|
/// The selectors ("b1 + b2 ~") doesn't match and matching restart from "d1".
|
||||||
|
///
|
||||||
|
/// The additional example is child and sibling. When the selector
|
||||||
|
/// "b1 + c1 > b2 ~ d1 a" is provided and the selector "b1" doesn't match on
|
||||||
|
/// the element, this "b1" raises NotMatchedAndRestartFromClosestLaterSibling.
|
||||||
|
/// However since the selector "c1" raises
|
||||||
|
/// NotMatchedAndRestartFromClosestDescendant. So the selector
|
||||||
|
/// "b1 + c1 > b2 ~ " doesn't match and restart matching from "d1".
|
||||||
|
enum SelectorMatchingResult {
|
||||||
|
Matched,
|
||||||
|
NotMatchedAndRestartFromClosestLaterSibling,
|
||||||
|
NotMatchedAndRestartFromClosestDescendant,
|
||||||
|
NotMatchedGlobally,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matches_compound_selector_internal<E:TElement,
|
||||||
|
N:TNode<E>>(
|
||||||
|
selector: &CompoundSelector,
|
||||||
|
element: &N,
|
||||||
|
shareable: &mut bool)
|
||||||
|
-> SelectorMatchingResult {
|
||||||
if !selector.simple_selectors.iter().all(|simple_selector| {
|
if !selector.simple_selectors.iter().all(|simple_selector| {
|
||||||
matches_simple_selector(simple_selector, element, shareable)
|
matches_simple_selector(simple_selector, element, shareable)
|
||||||
}) {
|
}) {
|
||||||
return false
|
return NotMatchedAndRestartFromClosestLaterSibling
|
||||||
}
|
}
|
||||||
match selector.next {
|
match selector.next {
|
||||||
None => true,
|
None => Matched,
|
||||||
Some((ref next_selector, combinator)) => {
|
Some((ref next_selector, combinator)) => {
|
||||||
let (siblings, just_one) = match combinator {
|
let (siblings, candidate_not_found) = match combinator {
|
||||||
Child => (false, true),
|
Child => (false, NotMatchedGlobally),
|
||||||
Descendant => (false, false),
|
Descendant => (false, NotMatchedGlobally),
|
||||||
NextSibling => (true, true),
|
NextSibling => (true, NotMatchedAndRestartFromClosestDescendant),
|
||||||
LaterSibling => (true, false),
|
LaterSibling => (true, NotMatchedAndRestartFromClosestDescendant),
|
||||||
};
|
};
|
||||||
let mut node = (*element).clone();
|
let mut node = (*element).clone();
|
||||||
loop {
|
loop {
|
||||||
|
@ -549,14 +610,37 @@ fn matches_compound_selector<E:TElement,
|
||||||
node.parent_node()
|
node.parent_node()
|
||||||
};
|
};
|
||||||
match next_node {
|
match next_node {
|
||||||
None => return false,
|
None => return candidate_not_found,
|
||||||
Some(next_node) => node = next_node,
|
Some(next_node) => node = next_node,
|
||||||
}
|
}
|
||||||
if node.is_element() {
|
if node.is_element() {
|
||||||
if matches_compound_selector(&**next_selector, &node, shareable) {
|
let result = matches_compound_selector_internal(&**next_selector,
|
||||||
return true
|
&node,
|
||||||
} else if just_one {
|
shareable);
|
||||||
return false
|
match (result, combinator) {
|
||||||
|
// Return the status immediately.
|
||||||
|
(Matched, _) => return result,
|
||||||
|
(NotMatchedGlobally, _) => return result,
|
||||||
|
|
||||||
|
// Upgrade the failure status to
|
||||||
|
// NotMatchedAndRestartFromClosestDescendant.
|
||||||
|
(_, Child) => return NotMatchedAndRestartFromClosestDescendant,
|
||||||
|
|
||||||
|
// Return the status directly.
|
||||||
|
(_, NextSibling) => return result,
|
||||||
|
|
||||||
|
// If the failure status is NotMatchedAndRestartFromClosestDescendant
|
||||||
|
// and combinator is LaterSibling, give up this LaterSibling matching
|
||||||
|
// and restart from the closest descendant combinator.
|
||||||
|
(NotMatchedAndRestartFromClosestDescendant, LaterSibling) => return result,
|
||||||
|
|
||||||
|
// The Descendant combinator and the status is
|
||||||
|
// NotMatchedAndRestartFromClosestLaterSibling or
|
||||||
|
// NotMatchedAndRestartFromClosestDescendant,
|
||||||
|
// or the LaterSibling combinator and the status is
|
||||||
|
// NotMatchedAndRestartFromClosestDescendant
|
||||||
|
// can continue to matching on the next candidate element.
|
||||||
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue