Bug 1845744: Move selector-specific node flags to a separate field. r=emilio

Upcoming :has invalidation (Bug 1792501) requires 4 more flags, and we're out of space.
This change consumes the remaining 32-bit hole in `nsINode` to migrate selector-specific
node flags.
This has implications on 32-bit platforms, specifically on text nodes.

Differential Revision: https://phabricator.services.mozilla.com/D184718
This commit is contained in:
David Shin 2023-08-01 00:29:56 +00:00
Родитель 7998255fe4
Коммит ec30a6eea6
7 изменённых файлов: 139 добавлений и 107 удалений

Просмотреть файл

@ -231,7 +231,7 @@ ASSERT_NODE_SIZE(HTMLParagraphElement, 128, 80);
ASSERT_NODE_SIZE(HTMLPreElement, 128, 80);
ASSERT_NODE_SIZE(HTMLSpanElement, 128, 80);
ASSERT_NODE_SIZE(HTMLTableCellElement, 128, 80);
ASSERT_NODE_SIZE(Text, 120, 64);
ASSERT_NODE_SIZE(Text, 120, 80);
#undef ASSERT_NODE_SIZE
#undef EXTRA_DOM_NODE_BYTES
@ -3025,6 +3025,8 @@ void Element::List(FILE* out, int32_t aIndent, const nsCString& aPrefix) const {
fprintf(out, " state=[%llx]",
static_cast<unsigned long long>(State().GetInternalValue()));
fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
fprintf(out, " selectorflags=[%08x]",
static_cast<unsigned int>(GetSelectorFlags()));
if (IsClosestCommonInclusiveAncestorForRangeInSelection()) {
const LinkedList<AbstractRange>* ranges =
GetExistingClosestCommonInclusiveAncestorRanges();

Просмотреть файл

@ -143,74 +143,82 @@ enum : uint32_t {
// Whether the node participates in a shadow tree.
NODE_IS_IN_SHADOW_TREE = NODE_FLAG_BIT(5),
// Node has an :empty or :-moz-only-whitespace selector
NODE_HAS_EMPTY_SELECTOR = NODE_FLAG_BIT(6),
// A child of the node has a selector such that any insertion,
// removal, or appending of children requires restyling the parent, if the
// parent is an element. If the parent is the shadow root, the child's
// siblings are restyled.
NODE_HAS_SLOW_SELECTOR = NODE_FLAG_BIT(7),
// A child of the node has a :first-child, :-moz-first-node,
// :only-child, :last-child or :-moz-last-node selector.
NODE_HAS_EDGE_CHILD_SELECTOR = NODE_FLAG_BIT(8),
// A child of the node has a selector such that any insertion or
// removal of children requires restyling later siblings of that
// element. Additionally (in this manner it is stronger than
// NODE_HAS_SLOW_SELECTOR), if a child's style changes due to any
// other content tree changes (e.g., the child changes to or from
// matching :empty due to a grandchild insertion or removal), the
// child's later siblings must also be restyled.
NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS = NODE_FLAG_BIT(9),
// A child of this node might be matched by :nth-child(.. of <selector>) or
// :nth-last-child(.. of <selector>). If a DOM mutation may have caused the
// selector to either match or no longer match that child, the child's
// siblings are restyled.
NODE_HAS_SLOW_SELECTOR_NTH_OF = NODE_FLAG_BIT(10),
// Set of selector flags that may trigger a restyle as a result of DOM
// mutation.
NODE_RESTYLE_SELECTOR_FLAGS =
NODE_HAS_EMPTY_SELECTOR | NODE_HAS_SLOW_SELECTOR |
NODE_HAS_EDGE_CHILD_SELECTOR | NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS |
NODE_HAS_SLOW_SELECTOR_NTH_OF,
// This node needs to go through frame construction to get a frame (or
// undisplayed entry).
NODE_NEEDS_FRAME = NODE_FLAG_BIT(11),
NODE_NEEDS_FRAME = NODE_FLAG_BIT(6),
// At least one descendant in the flattened tree has NODE_NEEDS_FRAME set.
// This should be set on every node on the flattened tree path between the
// node(s) with NODE_NEEDS_FRAME and the root content.
NODE_DESCENDANTS_NEED_FRAMES = NODE_FLAG_BIT(12),
NODE_DESCENDANTS_NEED_FRAMES = NODE_FLAG_BIT(7),
// Set if the node has the accesskey attribute set.
NODE_HAS_ACCESSKEY = NODE_FLAG_BIT(13),
NODE_HAS_ACCESSKEY = NODE_FLAG_BIT(8),
// Set if the node has right-to-left directionality
NODE_HAS_DIRECTION_RTL = NODE_FLAG_BIT(14),
NODE_HAS_DIRECTION_RTL = NODE_FLAG_BIT(9),
// Set if the node has left-to-right directionality
NODE_HAS_DIRECTION_LTR = NODE_FLAG_BIT(15),
NODE_HAS_DIRECTION_LTR = NODE_FLAG_BIT(10),
NODE_ALL_DIRECTION_FLAGS = NODE_HAS_DIRECTION_LTR | NODE_HAS_DIRECTION_RTL,
NODE_HAS_BEEN_IN_UA_WIDGET = NODE_FLAG_BIT(16),
NODE_HAS_BEEN_IN_UA_WIDGET = NODE_FLAG_BIT(11),
// Set if the node has a nonce value and a header delivered CSP.
NODE_HAS_NONCE_AND_HEADER_CSP = NODE_FLAG_BIT(17),
NODE_HAS_NONCE_AND_HEADER_CSP = NODE_FLAG_BIT(12),
NODE_KEEPS_DOMARENA = NODE_FLAG_BIT(18),
NODE_KEEPS_DOMARENA = NODE_FLAG_BIT(13),
NODE_MAY_HAVE_ELEMENT_CHILDREN = NODE_FLAG_BIT(19),
NODE_MAY_HAVE_ELEMENT_CHILDREN = NODE_FLAG_BIT(14),
// Remaining bits are node type specific.
NODE_TYPE_SPECIFIC_BITS_OFFSET = 20
NODE_TYPE_SPECIFIC_BITS_OFFSET = 15
};
// Flags for selectors that persist to the DOM node.
enum class NodeSelectorFlags : uint32_t {
// Node has an :empty or :-moz-only-whitespace selector
HasEmptySelector = 1 << 0,
/// A child of the node has a selector such that any insertion,
/// removal, or appending of children requires restyling the parent, if the
/// parent is an element. If the parent is the shadow root, the child's
/// siblings are restyled.
HasSlowSelector = 1 << 1,
/// A child of the node has a :first-child, :-moz-first-node,
/// :only-child, :last-child or :-moz-last-node selector.
HasEdgeChildSelector = 1 << 2,
/// A child of the node has a selector such that any insertion or
/// removal of children requires restyling later siblings of that
/// element. Additionally (in this manner it is stronger than
/// NODE_HAS_SLOW_SELECTOR), if a child's style changes due to any
/// other content tree changes (e.g., the child changes to or from
/// matching :empty due to a grandchild insertion or removal), the
/// child's later siblings must also be restyled.
HasSlowSelectorLaterSiblings = 1 << 3,
/// A child of this node might be matched by :nth-child(.. of <selector>) or
/// :nth-last-child(.. of <selector>). If a DOM mutation may have caused the
/// selector to either match or no longer match that child, the child's
/// siblings are restyled.
HasSlowSelectorNthOf = 1 << 4,
/// Set of selector flags that may trigger a restyle on DOM append, with
/// restyle on siblings or a single parent (And perhaps their subtrees).
AllSimpleRestyleFlagsForAppend = HasEmptySelector | HasSlowSelector |
HasEdgeChildSelector | HasSlowSelectorNthOf,
/// Set of selector flags that may trigger a restyle as a result of any
/// DOM mutation.
AllSimpleRestyleFlags =
AllSimpleRestyleFlagsForAppend | HasSlowSelectorLaterSiblings,
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(NodeSelectorFlags);
// Make sure we have space for our bits
#define ASSERT_NODE_FLAGS_SPACE(n) \
static_assert(WRAPPER_CACHE_FLAGS_BITS_USED + (n) <= \
@ -2317,6 +2325,10 @@ class nsINode : public mozilla::dom::EventTarget {
#undef TOUCH_EVENT
#undef EVENT
NodeSelectorFlags GetSelectorFlags() const {
return static_cast<NodeSelectorFlags>(mSelectorFlags.Get());
}
protected:
static bool Traverse(nsINode* tmp, nsCycleCollectionTraversalCallback& cb);
static void Unlink(nsINode* tmp);
@ -2334,7 +2346,7 @@ class nsINode : public mozilla::dom::EventTarget {
uint32_t mBoolFlags;
#endif
// NOTE, there are 32 bits left here, at least in 64 bit builds.
mozilla::RustCell<uint32_t> mSelectorFlags{0};
uint32_t mChildCount;

Просмотреть файл

@ -40,7 +40,10 @@ class nsWindowRoot;
// Both sets of flags are 32 bits. On 64-bit platforms, this can cause two
// wasted 32-bit fields due to alignment requirements. Some compilers are
// smart enough to coalesce the fields if we make mBoolFlags the first member
// of nsINode, but others (such as MSVC) are not.
// of nsINode, but others (such as MSVC, but that's not officially supported
// by us anymore) are not. Also note that this kind of coalascing tends to
// interact poorly with rust's bindgen, see:
// https://github.com/rust-lang/rust-bindgen/issues/380
//
// So we just store mBoolFlags directly on nsWrapperCache on 64-bit platforms.
// This may waste space for some other nsWrapperCache-derived objects that have

Просмотреть файл

@ -94,17 +94,16 @@ void RestyleManager::ContentAppended(nsIContent* aFirstNewContent) {
}
}
#endif
uint32_t selectorFlags =
container->GetFlags() &
(NODE_RESTYLE_SELECTOR_FLAGS & ~NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS);
if (selectorFlags == 0) {
const auto selectorFlags = container->GetSelectorFlags() &
NodeSelectorFlags::AllSimpleRestyleFlagsForAppend;
if (!selectorFlags) {
return;
}
// The container cannot be a document.
MOZ_ASSERT(container->IsElement() || container->IsShadowRoot());
if (selectorFlags & NODE_HAS_EMPTY_SELECTOR) {
if (selectorFlags & NodeSelectorFlags::HasEmptySelector) {
// see whether we need to restyle the container
bool wasEmpty = true; // :empty or :-moz-only-whitespace
for (nsIContent* cur = container->GetFirstChild(); cur != aFirstNewContent;
@ -124,7 +123,7 @@ void RestyleManager::ContentAppended(nsIContent* aFirstNewContent) {
}
}
if (selectorFlags & NODE_HAS_SLOW_SELECTOR) {
if (selectorFlags & NodeSelectorFlags::HasSlowSelector) {
if (container->IsElement()) {
PostRestyleEvent(container->AsElement(), RestyleHint::RestyleSubtree(),
nsChangeHint(0));
@ -136,7 +135,7 @@ void RestyleManager::ContentAppended(nsIContent* aFirstNewContent) {
return;
}
if (selectorFlags & NODE_HAS_EDGE_CHILD_SELECTOR) {
if (selectorFlags & NodeSelectorFlags::HasEdgeChildSelector) {
// restyle the last element child before this node
for (nsIContent* cur = aFirstNewContent->GetPreviousSibling(); cur;
cur = cur->GetPreviousSibling()) {
@ -173,8 +172,8 @@ void RestyleManager::RestyleForEmptyChange(Element* aContainer) {
// In some cases (:empty + E, :empty ~ E), a change in the content of
// an element requires restyling its parent's siblings.
nsIContent* grandparent = aContainer->GetParent();
if (!grandparent ||
!(grandparent->GetFlags() & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS)) {
if (!grandparent || !(grandparent->GetSelectorFlags() &
NodeSelectorFlags::HasSlowSelectorLaterSiblings)) {
return;
}
RestyleSiblingsStartingWith(aContainer->GetNextSibling());
@ -182,7 +181,8 @@ void RestyleManager::RestyleForEmptyChange(Element* aContainer) {
void RestyleManager::MaybeRestyleForEdgeChildChange(nsINode* aContainer,
nsIContent* aChangedChild) {
MOZ_ASSERT(aContainer->GetFlags() & NODE_HAS_EDGE_CHILD_SELECTOR);
MOZ_ASSERT(aContainer->GetSelectorFlags() &
NodeSelectorFlags::HasEdgeChildSelector);
MOZ_ASSERT(aChangedChild->GetParent() == aContainer);
// restyle the previously-first element child if it is after this node
bool passedChild = false;
@ -264,9 +264,10 @@ void RestyleManager::CharacterDataChanged(
nsINode* parent = aContent->GetParentNode();
MOZ_ASSERT(parent, "How were we notified of a stray node?");
uint32_t slowSelectorFlags = parent->GetFlags() & NODE_RESTYLE_SELECTOR_FLAGS;
if (!(slowSelectorFlags &
(NODE_HAS_EMPTY_SELECTOR | NODE_HAS_EDGE_CHILD_SELECTOR))) {
const auto slowSelectorFlags =
parent->GetSelectorFlags() & NodeSelectorFlags::AllSimpleRestyleFlags;
if (!(slowSelectorFlags & (NodeSelectorFlags::HasEmptySelector |
NodeSelectorFlags::HasEdgeChildSelector))) {
// Nothing to do, no other slow selector can change as a result of this.
return;
}
@ -321,7 +322,7 @@ void RestyleManager::CharacterDataChanged(
return;
}
if (slowSelectorFlags & NODE_HAS_EMPTY_SELECTOR) {
if (slowSelectorFlags & NodeSelectorFlags::HasEmptySelector) {
if (!HasAnySignificantSibling(parent->AsElement(), aContent)) {
// We used to be empty, restyle the parent.
RestyleForEmptyChange(parent->AsElement());
@ -329,7 +330,7 @@ void RestyleManager::CharacterDataChanged(
}
}
if (slowSelectorFlags & NODE_HAS_EDGE_CHILD_SELECTOR) {
if (slowSelectorFlags & NodeSelectorFlags::HasEdgeChildSelector) {
MaybeRestyleForEdgeChildChange(parent, aContent);
}
}
@ -344,8 +345,9 @@ void RestyleManager::RestyleForInsertOrChange(nsIContent* aChild) {
nsINode* container = aChild->GetParentNode();
MOZ_ASSERT(container);
uint32_t selectorFlags = container->GetFlags() & NODE_RESTYLE_SELECTOR_FLAGS;
if (selectorFlags == 0) {
const auto selectorFlags =
container->GetSelectorFlags() & NodeSelectorFlags::AllSimpleRestyleFlags;
if (!selectorFlags) {
return;
}
@ -355,7 +357,8 @@ void RestyleManager::RestyleForInsertOrChange(nsIContent* aChild) {
// The container cannot be a document.
MOZ_ASSERT(container->IsElement() || container->IsShadowRoot());
if (selectorFlags & NODE_HAS_EMPTY_SELECTOR && container->IsElement()) {
if (selectorFlags & NodeSelectorFlags::HasEmptySelector &&
container->IsElement()) {
// See whether we need to restyle the container due to :empty /
// :-moz-only-whitespace.
const bool wasEmpty =
@ -369,7 +372,7 @@ void RestyleManager::RestyleForInsertOrChange(nsIContent* aChild) {
}
}
if (selectorFlags & NODE_HAS_SLOW_SELECTOR) {
if (selectorFlags & NodeSelectorFlags::HasSlowSelector) {
if (container->IsElement()) {
PostRestyleEvent(container->AsElement(), RestyleHint::RestyleSubtree(),
nsChangeHint(0));
@ -381,12 +384,12 @@ void RestyleManager::RestyleForInsertOrChange(nsIContent* aChild) {
return;
}
if (selectorFlags & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS) {
if (selectorFlags & NodeSelectorFlags::HasSlowSelectorLaterSiblings) {
// Restyle all later siblings.
RestyleSiblingsStartingWith(aChild->GetNextSibling());
}
if (selectorFlags & NODE_HAS_EDGE_CHILD_SELECTOR) {
if (selectorFlags & NodeSelectorFlags::HasEdgeChildSelector) {
MaybeRestyleForEdgeChildChange(container, aChild);
}
}
@ -408,8 +411,9 @@ void RestyleManager::ContentRemoved(nsIContent* aOldChild,
IncrementUndisplayedRestyleGeneration();
}
uint32_t selectorFlags = container->GetFlags() & NODE_RESTYLE_SELECTOR_FLAGS;
if (selectorFlags == 0) {
const auto selectorFlags =
container->GetSelectorFlags() & NodeSelectorFlags::AllSimpleRestyleFlags;
if (!selectorFlags) {
return;
}
@ -424,7 +428,8 @@ void RestyleManager::ContentRemoved(nsIContent* aOldChild,
// The container cannot be a document.
MOZ_ASSERT(container->IsElement() || container->IsShadowRoot());
if (selectorFlags & NODE_HAS_EMPTY_SELECTOR && container->IsElement()) {
if (selectorFlags & NodeSelectorFlags::HasEmptySelector &&
container->IsElement()) {
// see whether we need to restyle the container
bool isEmpty = true; // :empty or :-moz-only-whitespace
for (nsIContent* child = container->GetFirstChild(); child;
@ -444,7 +449,7 @@ void RestyleManager::ContentRemoved(nsIContent* aOldChild,
}
}
if (selectorFlags & NODE_HAS_SLOW_SELECTOR) {
if (selectorFlags & NodeSelectorFlags::HasSlowSelector) {
if (container->IsElement()) {
PostRestyleEvent(container->AsElement(), RestyleHint::RestyleSubtree(),
nsChangeHint(0));
@ -456,12 +461,12 @@ void RestyleManager::ContentRemoved(nsIContent* aOldChild,
return;
}
if (selectorFlags & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS) {
if (selectorFlags & NodeSelectorFlags::HasSlowSelectorLaterSiblings) {
// Restyle all later siblings.
RestyleSiblingsStartingWith(aFollowingSibling);
}
if (selectorFlags & NODE_HAS_EDGE_CHILD_SELECTOR) {
if (selectorFlags & NodeSelectorFlags::HasEdgeChildSelector) {
// restyle the now-first element child if it was after aOldChild
bool reachedFollowingSibling = false;
for (nsIContent* content = container->GetFirstChild(); content;
@ -3355,8 +3360,8 @@ void RestyleManager::MaybeRestyleForNthOfState(ServoStyleSet& aStyleSet,
ElementState aChangedBits) {
const auto* parentNode = aChild->GetParentNode();
MOZ_ASSERT(parentNode);
const auto parentFlags = parentNode->GetFlags();
if (!(parentFlags & NODE_HAS_SLOW_SELECTOR_NTH_OF)) {
const auto parentFlags = parentNode->GetSelectorFlags();
if (!(parentFlags & NodeSelectorFlags::HasSlowSelectorNthOf)) {
return;
}
@ -3535,20 +3540,21 @@ void RestyleManager::AttributeChanged(Element* aElement, int32_t aNameSpaceID,
}
}
void RestyleManager::RestyleSiblings(
Element* aChild, nsBaseContentList::FlagsType aParentFlags) {
void RestyleManager::RestyleSiblings(Element* aChild,
NodeSelectorFlags aParentFlags) {
const DebugOnly<nsINode*> parentNode = aChild->GetParentNode();
MOZ_ASSERT(parentNode->IsElement() || parentNode->IsShadowRoot());
DebugOnly<bool> restyledSiblings = false;
// NODE_HAS_SLOW_SELECTOR typically indicates restyling the parent, but since
// we know we're restyling for :nth-last-child(.. of <selector>), we can
// restyle only previous siblings without under-invalidating.
if (aParentFlags & NODE_HAS_SLOW_SELECTOR) {
// NodeSelectorFlags::HasSlowSelector typically indicates restyling the
// parent, but since we know we're restyling for :nth-last-child(.. of
// <selector>), we can restyle only previous siblings without
// under-invalidating.
if (aParentFlags & NodeSelectorFlags::HasSlowSelector) {
RestylePreviousSiblings(aChild->GetPreviousSibling());
restyledSiblings = true;
}
if (aParentFlags & NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS) {
if (aParentFlags & NodeSelectorFlags::HasSlowSelectorLaterSiblings) {
RestyleSiblingsStartingWith(aChild->GetNextSibling());
restyledSiblings = true;
}
@ -3560,8 +3566,8 @@ void RestyleManager::MaybeRestyleForNthOfAttribute(
Element* aChild, nsAtom* aAttribute, const nsAttrValue* aOldValue) {
const auto* parentNode = aChild->GetParentNode();
MOZ_ASSERT(parentNode);
const auto parentFlags = parentNode->GetFlags();
if (!(parentFlags & NODE_HAS_SLOW_SELECTOR_NTH_OF)) {
const auto parentFlags = parentNode->GetSelectorFlags();
if (!(parentFlags & NodeSelectorFlags::HasSlowSelectorNthOf)) {
return;
}
if (!aChild->HasServoData()) {

Просмотреть файл

@ -379,8 +379,7 @@ class RestyleManager {
/**
* Restyle an element's previous and/or next siblings.
*/
void RestyleSiblings(dom::Element* aChild,
nsBaseContentList::FlagsType aParentFlags);
void RestyleSiblings(dom::Element* aChild, NodeSelectorFlags aParentFlags);
/**
* Posts restyle hints for siblings of an element and their descendants if the

Просмотреть файл

@ -58,6 +58,7 @@ hide-types = [
bitfield-enums = [
"nsChangeHint",
"mozilla::OriginFlags",
"NodeSelectorFlags",
]
rusty-enums = [
"nsCompatibility",
@ -354,6 +355,7 @@ allowlist-types = [
"mozilla::dom::MediaList",
"mozilla::StyleRuleInclusion",
"nsStyleTransformMatrix::MatrixTransformOperator",
"NodeSelectorFlags",
]
opaque-types = [
"mozilla::StyleThinArc", # https://github.com/rust-lang/rust-bindgen/issues/1557

Просмотреть файл

@ -76,6 +76,7 @@ use selectors::matching::{ElementSelectorFlags, MatchingContext};
use selectors::sink::Push;
use selectors::{Element, OpaqueElement};
use servo_arc::{Arc, ArcBorrow};
use std::cell::Cell;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::mem;
@ -270,17 +271,9 @@ impl<'ln> GeckoNode<'ln> {
self.flags_atomic().fetch_or(flags, Ordering::Relaxed);
}
#[inline]
fn flags_atomic(&self) -> &AtomicU32 {
use std::cell::Cell;
let flags: &Cell<u32> = &(self.0)._base._base_1.mFlags;
#[allow(dead_code)]
fn static_assert() {
let _: [u8; std::mem::size_of::<Cell<u32>>()] = [0u8; std::mem::size_of::<AtomicU32>()];
let _: [u8; std::mem::align_of::<Cell<u32>>()] =
[0u8; std::mem::align_of::<AtomicU32>()];
}
fn flags_atomic_for(flags: &Cell<u32>) -> &AtomicU32 {
const_assert!(std::mem::size_of::<Cell<u32>>() == std::mem::size_of::<AtomicU32>());
const_assert!(std::mem::align_of::<Cell<u32>>() == std::mem::align_of::<AtomicU32>());
// Rust doesn't provide standalone atomic functions like GCC/clang do
// (via the atomic intrinsics) or via std::atomic_ref, but it guarantees
@ -289,11 +282,26 @@ impl<'ln> GeckoNode<'ln> {
unsafe { std::mem::transmute::<&Cell<u32>, &AtomicU32>(flags) }
}
#[inline]
fn flags_atomic(&self) -> &AtomicU32 {
Self::flags_atomic_for(&self.0._base._base_1.mFlags)
}
#[inline]
fn flags(&self) -> u32 {
self.flags_atomic().load(Ordering::Relaxed)
}
#[inline]
fn selector_flags_atomic(&self) -> &AtomicU32 {
Self::flags_atomic_for(&self.0.mSelectorFlags)
}
#[inline]
fn set_selector_flags(&self, flags: u32) {
self.selector_flags_atomic().fetch_or(flags, Ordering::Relaxed);
}
#[inline]
fn node_info(&self) -> &structs::NodeInfo {
debug_assert!(!self.0.mNodeInfo.mRawPtr.is_null());
@ -859,22 +867,22 @@ impl<'le> GeckoElement<'le> {
/// by Gecko. We could align these and then do this without conditionals, but
/// it's probably not worth the trouble.
fn selector_flags_to_node_flags(flags: ElementSelectorFlags) -> u32 {
use crate::gecko_bindings::structs::*;
use crate::gecko_bindings::structs::NodeSelectorFlags;
let mut gecko_flags = 0u32;
if flags.contains(ElementSelectorFlags::HAS_SLOW_SELECTOR) {
gecko_flags |= NODE_HAS_SLOW_SELECTOR;
gecko_flags |= NodeSelectorFlags::HasSlowSelector.0;
}
if flags.contains(ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS) {
gecko_flags |= NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS;
gecko_flags |= NodeSelectorFlags::HasSlowSelectorLaterSiblings.0;
}
if flags.contains(ElementSelectorFlags::HAS_SLOW_SELECTOR_NTH_OF) {
gecko_flags |= NODE_HAS_SLOW_SELECTOR_NTH_OF;
gecko_flags |= NodeSelectorFlags::HasSlowSelectorNthOf.0;
}
if flags.contains(ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR) {
gecko_flags |= NODE_HAS_EDGE_CHILD_SELECTOR;
gecko_flags |= NodeSelectorFlags::HasEdgeChildSelector.0;
}
if flags.contains(ElementSelectorFlags::HAS_EMPTY_SELECTOR) {
gecko_flags |= NODE_HAS_EMPTY_SELECTOR;
gecko_flags |= NodeSelectorFlags::HasEmptySelector.0;
}
gecko_flags
@ -1810,7 +1818,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
// Handle flags that apply to the element.
let self_flags = flags.for_self();
if !self_flags.is_empty() {
self.set_flags(selector_flags_to_node_flags(flags))
self.as_node().set_selector_flags(selector_flags_to_node_flags(flags))
}
// Handle flags that apply to the parent.
@ -1818,7 +1826,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
if !parent_flags.is_empty() {
if let Some(p) = self.as_node().parent_node() {
if p.is_element() || p.is_shadow_root() {
p.set_flags(selector_flags_to_node_flags(parent_flags));
p.set_selector_flags(selector_flags_to_node_flags(parent_flags));
}
}
}