зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
7998255fe4
Коммит
ec30a6eea6
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче