mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 02:14:43 +00:00
Bug 1792501: Part 1 - Mark relative selector search path. r=emilio
Differential Revision: https://phabricator.services.mozilla.com/D185674
This commit is contained in:
parent
01fdd66543
commit
7b00e82664
@ -207,6 +207,25 @@ enum class NodeSelectorFlags : uint32_t {
|
||||
/// DOM mutation.
|
||||
AllSimpleRestyleFlags =
|
||||
AllSimpleRestyleFlagsForAppend | HasSlowSelectorLaterSiblings,
|
||||
|
||||
// This node was evaluated as an anchor for a relative selector.
|
||||
RelativeSelectorAnchor = 1 << 5,
|
||||
|
||||
// This node was evaluated as an anchor for a relative selector, and that
|
||||
// relative selector was not the subject of the overall selector.
|
||||
RelativeSelectorAnchorNonSubject = 1 << 6,
|
||||
|
||||
// This node's sibling(s) performed a relative selector search to this node.
|
||||
RelativeSelectorSearchDirectionSibling = 1 << 7,
|
||||
|
||||
// This node's ancestor(s) performed a relative selector search to this node.
|
||||
RelativeSelectorSearchDirectionAncestor = 1 << 8,
|
||||
|
||||
// This node's sibling(s) and ancestor(s), and/or this node's ancestor's
|
||||
// sibling(s) performed a relative selector search to this node.
|
||||
RelativeSelectorSearchDirectionAncestorSibling =
|
||||
RelativeSelectorSearchDirectionSibling |
|
||||
RelativeSelectorSearchDirectionAncestor,
|
||||
};
|
||||
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(NodeSelectorFlags);
|
||||
|
@ -57,13 +57,35 @@ bitflags! {
|
||||
/// The element has an empty selector, so when a child is appended we
|
||||
/// might need to restyle the parent completely.
|
||||
const HAS_EMPTY_SELECTOR = 1 << 4;
|
||||
|
||||
/// The element may anchor a relative selector.
|
||||
const ANCHORS_RELATIVE_SELECTOR = 1 << 5;
|
||||
|
||||
/// The element may anchor a relative selector that is not the subject
|
||||
/// of the whole selector.
|
||||
const ANCHORS_RELATIVE_SELECTOR_NON_SUBJECT = 1 << 6;
|
||||
|
||||
/// The element is reached by a relative selector search in the sibling direction.
|
||||
const RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING = 1 << 7;
|
||||
|
||||
/// The element is reached by a relative selector search in the ancestor direction.
|
||||
const RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR = 1 << 8;
|
||||
|
||||
// The element is reached by a relative selector search in both sibling and ancestor directions.
|
||||
const RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR_SIBLING =
|
||||
Self::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING.bits |
|
||||
Self::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR.bits;
|
||||
}
|
||||
}
|
||||
|
||||
impl ElementSelectorFlags {
|
||||
/// Returns the subset of flags that apply to the element.
|
||||
pub fn for_self(self) -> ElementSelectorFlags {
|
||||
self & ElementSelectorFlags::HAS_EMPTY_SELECTOR
|
||||
self & (ElementSelectorFlags::HAS_EMPTY_SELECTOR |
|
||||
ElementSelectorFlags::ANCHORS_RELATIVE_SELECTOR |
|
||||
ElementSelectorFlags::ANCHORS_RELATIVE_SELECTOR_NON_SUBJECT |
|
||||
ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING |
|
||||
ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR)
|
||||
}
|
||||
|
||||
/// Returns the subset of flags that apply to the parent.
|
||||
@ -376,9 +398,21 @@ fn matches_relative_selector<E: Element>(
|
||||
context: &mut MatchingContext<E::Impl>,
|
||||
rightmost: Rightmost,
|
||||
) -> bool {
|
||||
// Overall, we want to mark the path that we've traversed so that when an element
|
||||
// is invalidated, we early-reject unnecessary relative selector invalidations.
|
||||
if relative_selector.match_hint.is_descendant_direction() {
|
||||
if context.needs_selector_flags() {
|
||||
element.apply_selector_flags(
|
||||
ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR,
|
||||
);
|
||||
}
|
||||
let mut next_element = element.first_element_child();
|
||||
while let Some(el) = next_element {
|
||||
if context.needs_selector_flags() {
|
||||
el.apply_selector_flags(
|
||||
ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR,
|
||||
);
|
||||
}
|
||||
let mut matched = matches_complex_selector(
|
||||
relative_selector.selector.iter(),
|
||||
&el,
|
||||
@ -409,8 +443,21 @@ fn matches_relative_selector<E: Element>(
|
||||
),
|
||||
"Not descendant direction, but also not sibling direction?"
|
||||
);
|
||||
if context.needs_selector_flags() {
|
||||
element.apply_selector_flags(
|
||||
ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING,
|
||||
);
|
||||
}
|
||||
let sibling_flag = if relative_selector.match_hint.is_subtree() {
|
||||
ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR_SIBLING
|
||||
} else {
|
||||
ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING
|
||||
};
|
||||
let mut next_element = element.next_sibling_element();
|
||||
while let Some(el) = next_element {
|
||||
if context.needs_selector_flags() {
|
||||
el.apply_selector_flags(sibling_flag);
|
||||
}
|
||||
let matched = if relative_selector.match_hint.is_subtree() {
|
||||
matches_relative_selector_subtree(
|
||||
&relative_selector.selector,
|
||||
@ -480,13 +527,20 @@ fn matches_relative_selectors<E: Element>(
|
||||
context: &mut MatchingContext<E::Impl>,
|
||||
rightmost: Rightmost,
|
||||
) -> bool {
|
||||
// Relative selectors have different implications, depending on if the relative
|
||||
// selector is in the subject position or not (See style sharing code for
|
||||
// further information)
|
||||
// Due to style sharing implications (See style sharing code), we mark the current styling context
|
||||
// to mark elements considered for :has matching. Additionally, we want to mark the elements themselves,
|
||||
// since we don't want to indiscriminately invalidate every element as a potential anchor.
|
||||
if rightmost == Rightmost::Yes {
|
||||
context.considered_relative_selector.considered_anchor();
|
||||
if context.needs_selector_flags() {
|
||||
element.apply_selector_flags(ElementSelectorFlags::ANCHORS_RELATIVE_SELECTOR);
|
||||
}
|
||||
} else {
|
||||
context.considered_relative_selector.considered();
|
||||
if context.needs_selector_flags() {
|
||||
element
|
||||
.apply_selector_flags(ElementSelectorFlags::ANCHORS_RELATIVE_SELECTOR_NON_SUBJECT);
|
||||
}
|
||||
}
|
||||
|
||||
for relative_selector in selectors.iter() {
|
||||
@ -525,6 +579,11 @@ fn matches_relative_selector_subtree<E: Element>(
|
||||
let mut current = element.first_element_child();
|
||||
|
||||
while let Some(el) = current {
|
||||
if context.needs_selector_flags() {
|
||||
el.apply_selector_flags(
|
||||
ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR,
|
||||
);
|
||||
}
|
||||
if matches_complex_selector(selector.iter(), &el, context, rightmost) {
|
||||
return true;
|
||||
}
|
||||
|
@ -884,6 +884,18 @@ fn selector_flags_to_node_flags(flags: ElementSelectorFlags) -> u32 {
|
||||
if flags.contains(ElementSelectorFlags::HAS_EMPTY_SELECTOR) {
|
||||
gecko_flags |= NodeSelectorFlags::HasEmptySelector.0;
|
||||
}
|
||||
if flags.contains(ElementSelectorFlags::ANCHORS_RELATIVE_SELECTOR) {
|
||||
gecko_flags |= NodeSelectorFlags::RelativeSelectorAnchor.0;
|
||||
}
|
||||
if flags.contains(ElementSelectorFlags::ANCHORS_RELATIVE_SELECTOR_NON_SUBJECT) {
|
||||
gecko_flags |= NodeSelectorFlags::RelativeSelectorAnchorNonSubject.0;
|
||||
}
|
||||
if flags.contains(ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_ANCESTOR) {
|
||||
gecko_flags |= NodeSelectorFlags::RelativeSelectorSearchDirectionAncestor.0;
|
||||
}
|
||||
if flags.contains(ElementSelectorFlags::RELATIVE_SELECTOR_SEARCH_DIRECTION_SIBLING) {
|
||||
gecko_flags |= NodeSelectorFlags::RelativeSelectorSearchDirectionSibling.0;
|
||||
}
|
||||
|
||||
gecko_flags
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user