mirror of
https://github.com/servo/servo.git
synced 2025-08-07 14:35:33 +01:00
Auto merge of #19027 - emilio:svg-use-bug, r=upsuper
selectors: Be consistent about how we get a parent element for selector matching This fixes bug 1412011. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/19027) <!-- Reviewable:end -->
This commit is contained in:
commit
de7595f16f
1 changed files with 94 additions and 72 deletions
|
@ -486,6 +486,32 @@ enum Rightmost {
|
||||||
No,
|
No,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn next_element_for_combinator<E>(
|
||||||
|
element: &E,
|
||||||
|
combinator: Combinator,
|
||||||
|
) -> Option<E>
|
||||||
|
where
|
||||||
|
E: Element,
|
||||||
|
{
|
||||||
|
match combinator {
|
||||||
|
Combinator::NextSibling |
|
||||||
|
Combinator::LaterSibling => {
|
||||||
|
element.prev_sibling_element()
|
||||||
|
}
|
||||||
|
Combinator::Child |
|
||||||
|
Combinator::Descendant => {
|
||||||
|
if element.blocks_ancestor_combinators() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
element.parent_element()
|
||||||
|
}
|
||||||
|
Combinator::PseudoElement => {
|
||||||
|
element.pseudo_element_originating_element()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn matches_complex_selector_internal<E, F>(
|
fn matches_complex_selector_internal<E, F>(
|
||||||
mut selector_iter: SelectorIter<E::Impl>,
|
mut selector_iter: SelectorIter<E::Impl>,
|
||||||
element: &E,
|
element: &E,
|
||||||
|
@ -524,8 +550,7 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
let combinator = selector_iter.next_sequence();
|
let combinator = selector_iter.next_sequence();
|
||||||
let siblings = combinator.map_or(false, |c| c.is_sibling());
|
if combinator.map_or(false, |c| c.is_sibling()) {
|
||||||
if siblings {
|
|
||||||
flags_setter(element, HAS_SLOW_SELECTOR_LATER_SIBLINGS);
|
flags_setter(element, HAS_SLOW_SELECTOR_LATER_SIBLINGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -533,31 +558,28 @@ where
|
||||||
return SelectorMatchingResult::NotMatchedAndRestartFromClosestLaterSibling;
|
return SelectorMatchingResult::NotMatchedAndRestartFromClosestLaterSibling;
|
||||||
}
|
}
|
||||||
|
|
||||||
match combinator {
|
let combinator = match combinator {
|
||||||
None => SelectorMatchingResult::Matched,
|
None => return SelectorMatchingResult::Matched,
|
||||||
Some(c) => {
|
Some(c) => c,
|
||||||
let (mut next_element, candidate_not_found) = match c {
|
};
|
||||||
Combinator::NextSibling | Combinator::LaterSibling => {
|
|
||||||
|
let candidate_not_found = match combinator {
|
||||||
|
Combinator::NextSibling |
|
||||||
|
Combinator::LaterSibling => {
|
||||||
// Only ancestor combinators are allowed while looking for
|
// Only ancestor combinators are allowed while looking for
|
||||||
// relevant links, so switch to not looking.
|
// relevant links, so switch to not looking.
|
||||||
*relevant_link = RelevantLinkStatus::NotLooking;
|
*relevant_link = RelevantLinkStatus::NotLooking;
|
||||||
(element.prev_sibling_element(),
|
SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant
|
||||||
SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant)
|
|
||||||
}
|
|
||||||
Combinator::Child | Combinator::Descendant => {
|
|
||||||
if element.blocks_ancestor_combinators() {
|
|
||||||
(None, SelectorMatchingResult::NotMatchedGlobally)
|
|
||||||
} else {
|
|
||||||
(element.parent_element(),
|
|
||||||
SelectorMatchingResult::NotMatchedGlobally)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Combinator::Child |
|
||||||
|
Combinator::Descendant |
|
||||||
Combinator::PseudoElement => {
|
Combinator::PseudoElement => {
|
||||||
(element.pseudo_element_originating_element(),
|
SelectorMatchingResult::NotMatchedGlobally
|
||||||
SelectorMatchingResult::NotMatchedGlobally)
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut next_element = next_element_for_combinator(element, combinator);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let element = match next_element {
|
let element = match next_element {
|
||||||
None => return candidate_not_found,
|
None => return candidate_not_found,
|
||||||
|
@ -571,40 +593,40 @@ where
|
||||||
flags_setter,
|
flags_setter,
|
||||||
Rightmost::No,
|
Rightmost::No,
|
||||||
);
|
);
|
||||||
match (result, c) {
|
|
||||||
|
match (result, combinator) {
|
||||||
// Return the status immediately.
|
// Return the status immediately.
|
||||||
(SelectorMatchingResult::Matched, _) => return result,
|
(SelectorMatchingResult::Matched, _) |
|
||||||
(SelectorMatchingResult::NotMatchedGlobally, _) => return result,
|
(SelectorMatchingResult::NotMatchedGlobally, _) |
|
||||||
|
(_, Combinator::NextSibling) => {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Upgrade the failure status to
|
// Upgrade the failure status to
|
||||||
// NotMatchedAndRestartFromClosestDescendant.
|
// NotMatchedAndRestartFromClosestDescendant.
|
||||||
(_, Combinator::PseudoElement) |
|
(_, Combinator::PseudoElement) |
|
||||||
(_, Combinator::Child) => return SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant,
|
(_, Combinator::Child) => {
|
||||||
|
return SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant;
|
||||||
|
}
|
||||||
|
|
||||||
// Return the status directly.
|
// If the failure status is
|
||||||
(_, Combinator::NextSibling) => return result,
|
// NotMatchedAndRestartFromClosestDescendant and combinator is
|
||||||
|
// Combinator::LaterSibling, give up this Combinator::LaterSibling
|
||||||
// If the failure status is NotMatchedAndRestartFromClosestDescendant
|
// matching and restart from the closest descendant combinator.
|
||||||
// and combinator is Combinator::LaterSibling, give up this Combinator::LaterSibling matching
|
(SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant, Combinator::LaterSibling) => {
|
||||||
// and restart from the closest descendant combinator.
|
return result;
|
||||||
(SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant, Combinator::LaterSibling)
|
}
|
||||||
=> return result,
|
|
||||||
|
|
||||||
// The Combinator::Descendant combinator and the status is
|
// The Combinator::Descendant combinator and the status is
|
||||||
// NotMatchedAndRestartFromClosestLaterSibling or
|
// NotMatchedAndRestartFromClosestLaterSibling or
|
||||||
// NotMatchedAndRestartFromClosestDescendant,
|
// NotMatchedAndRestartFromClosestDescendant, or the
|
||||||
// or the Combinator::LaterSibling combinator and the status is
|
// Combinator::LaterSibling combinator and the status is
|
||||||
// NotMatchedAndRestartFromClosestDescendant
|
// NotMatchedAndRestartFromClosestDescendant, we can continue to
|
||||||
// can continue to matching on the next candidate element.
|
// matching on the next candidate element.
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
next_element = if siblings {
|
|
||||||
element.prev_sibling_element()
|
next_element = next_element_for_combinator(&element, combinator);
|
||||||
} else {
|
|
||||||
element.parent_element()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue