forked from mirrors/gecko-dev
Bug 1825825 - Simplify NAC setup. r=smaug
Make all UA widgets also NAC. Keep the UA widget flag but break at anonymous subtree boundaries, so that only nodes inside the UA widget directly (and not NAC from those) get the flag. This is important because two callers depend on this difference: * The style system, since we still want to match content rules from stylesheets in the UA widget. We also match user rules, which is a bit sketchy, but that was the previous behavior, will file a follow-up for that. * The reflector code, since we want the scope for UA widgets to not include the NAC nodes inside that UA widget. nsINode::IsInUAWidget got it wrong. After this patch, ChromeOnlyAccess is equivalent to IsInNativeAnonymousSubtree, so we should probably unify the naming. That's left for a follow-up patch because I don't have a strong preference. Differential Revision: https://phabricator.services.mozilla.com/D174310
This commit is contained in:
parent
ae16da3b5f
commit
641fa20731
29 changed files with 190 additions and 218 deletions
|
|
@ -657,7 +657,7 @@ void DocAccessible::HandleScroll(nsINode* aTarget) {
|
||||||
if (!targetAcc && target->IsInNativeAnonymousSubtree()) {
|
if (!targetAcc && target->IsInNativeAnonymousSubtree()) {
|
||||||
// The scroll event for textareas comes from a native anonymous div. We need
|
// The scroll event for textareas comes from a native anonymous div. We need
|
||||||
// the closest non-anonymous ancestor to get the right Accessible.
|
// the closest non-anonymous ancestor to get the right Accessible.
|
||||||
target = target->GetClosestNativeAnonymousSubtreeRootParent();
|
target = target->GetClosestNativeAnonymousSubtreeRootParentOrHost();
|
||||||
targetAcc = GetAccessible(target);
|
targetAcc = GetAccessible(target);
|
||||||
}
|
}
|
||||||
// Regardless of our scroll timer, we need to send a cache update
|
// Regardless of our scroll timer, we need to send a cache update
|
||||||
|
|
|
||||||
|
|
@ -416,11 +416,10 @@ nsresult CharacterData::BindToTree(BindContext& aContext, nsINode& aParent) {
|
||||||
if (aParent.IsInNativeAnonymousSubtree()) {
|
if (aParent.IsInNativeAnonymousSubtree()) {
|
||||||
SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
|
SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
|
||||||
}
|
}
|
||||||
if (aParent.HasFlag(NODE_HAS_BEEN_IN_UA_WIDGET)) {
|
|
||||||
SetFlags(NODE_HAS_BEEN_IN_UA_WIDGET);
|
|
||||||
}
|
|
||||||
if (IsRootOfNativeAnonymousSubtree()) {
|
if (IsRootOfNativeAnonymousSubtree()) {
|
||||||
aParent.SetMayHaveAnonymousChildren();
|
aParent.SetMayHaveAnonymousChildren();
|
||||||
|
} else if (aParent.HasFlag(NODE_HAS_BEEN_IN_UA_WIDGET)) {
|
||||||
|
SetFlags(NODE_HAS_BEEN_IN_UA_WIDGET);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set parent
|
// Set parent
|
||||||
|
|
|
||||||
|
|
@ -1810,11 +1810,10 @@ nsresult Element::BindToTree(BindContext& aContext, nsINode& aParent) {
|
||||||
if (aParent.IsInNativeAnonymousSubtree()) {
|
if (aParent.IsInNativeAnonymousSubtree()) {
|
||||||
SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
|
SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
|
||||||
}
|
}
|
||||||
if (aParent.HasFlag(NODE_HAS_BEEN_IN_UA_WIDGET)) {
|
|
||||||
SetFlags(NODE_HAS_BEEN_IN_UA_WIDGET);
|
|
||||||
}
|
|
||||||
if (IsRootOfNativeAnonymousSubtree()) {
|
if (IsRootOfNativeAnonymousSubtree()) {
|
||||||
aParent.SetMayHaveAnonymousChildren();
|
aParent.SetMayHaveAnonymousChildren();
|
||||||
|
} else if (aParent.HasFlag(NODE_HAS_BEEN_IN_UA_WIDGET)) {
|
||||||
|
SetFlags(NODE_HAS_BEEN_IN_UA_WIDGET);
|
||||||
}
|
}
|
||||||
if (aParent.HasFlag(ELEMENT_IS_DATALIST_OR_HAS_DATALIST_ANCESTOR)) {
|
if (aParent.HasFlag(ELEMENT_IS_DATALIST_OR_HAS_DATALIST_ANCESTOR)) {
|
||||||
SetFlags(ELEMENT_IS_DATALIST_OR_HAS_DATALIST_ANCESTOR);
|
SetFlags(ELEMENT_IS_DATALIST_OR_HAS_DATALIST_ANCESTOR);
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ already_AddRefed<nsContentList> NS_GetContentList(nsINode* aRootNode,
|
||||||
NODE_FLAG_BIT(NODE_TYPE_SPECIFIC_BITS_OFFSET + (n_))
|
NODE_FLAG_BIT(NODE_TYPE_SPECIFIC_BITS_OFFSET + (n_))
|
||||||
|
|
||||||
// Element-specific flags
|
// Element-specific flags
|
||||||
enum {
|
enum : uint32_t {
|
||||||
// Whether this node has dirty descendants for Servo's style system.
|
// Whether this node has dirty descendants for Servo's style system.
|
||||||
ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO = ELEMENT_FLAG_BIT(0),
|
ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO = ELEMENT_FLAG_BIT(0),
|
||||||
// Whether this node has dirty descendants for animation-only restyle for
|
// Whether this node has dirty descendants for animation-only restyle for
|
||||||
|
|
|
||||||
|
|
@ -866,7 +866,7 @@ void nsIContent::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
|
||||||
nsCOMPtr<nsIContent> content(
|
nsCOMPtr<nsIContent> content(
|
||||||
nsIContent::FromEventTargetOrNull(aVisitor.mEvent->mTarget));
|
nsIContent::FromEventTargetOrNull(aVisitor.mEvent->mTarget));
|
||||||
if (content &&
|
if (content &&
|
||||||
content->GetClosestNativeAnonymousSubtreeRootParent() == parent) {
|
content->GetClosestNativeAnonymousSubtreeRootParentOrHost() == parent) {
|
||||||
aVisitor.mEventTargetAtParent = parent;
|
aVisitor.mEventTargetAtParent = parent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,8 @@ nsINode* RangeUtils::ComputeRootNode(nsINode* aNode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the node is in NAC, then the NAC parent should be the root.
|
// If the node is in NAC, then the NAC parent should be the root.
|
||||||
if (nsINode* root = content->GetClosestNativeAnonymousSubtreeRootParent()) {
|
if (nsINode* root =
|
||||||
|
content->GetClosestNativeAnonymousSubtreeRootParentOrHost()) {
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,7 @@ void SelectionChangeEventDispatcher::OnSelectionChange(Document* aDoc,
|
||||||
maybeHasSelectionChangeEventListeners) {
|
maybeHasSelectionChangeEventListeners) {
|
||||||
if (const nsFrameSelection* fs = aSel->GetFrameSelection()) {
|
if (const nsFrameSelection* fs = aSel->GetFrameSelection()) {
|
||||||
if (nsCOMPtr<nsIContent> root = fs->GetLimiter()) {
|
if (nsCOMPtr<nsIContent> root = fs->GetLimiter()) {
|
||||||
textControl = root->GetClosestNativeAnonymousSubtreeRootParent();
|
textControl = root->GetClosestNativeAnonymousSubtreeRootParentOrHost();
|
||||||
MOZ_ASSERT_IF(textControl,
|
MOZ_ASSERT_IF(textControl,
|
||||||
textControl->IsTextControlElement() &&
|
textControl->IsTextControlElement() &&
|
||||||
!textControl->IsInNativeAnonymousSubtree());
|
!textControl->IsInNativeAnonymousSubtree());
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#include "mozilla/dom/DocumentFragment.h"
|
#include "mozilla/dom/DocumentFragment.h"
|
||||||
#include "ChildIterator.h"
|
#include "ChildIterator.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
|
#include "nsINode.h"
|
||||||
#include "nsWindowSizes.h"
|
#include "nsWindowSizes.h"
|
||||||
#include "mozilla/dom/DirectionalityUtils.h"
|
#include "mozilla/dom/DirectionalityUtils.h"
|
||||||
#include "mozilla/dom/Element.h"
|
#include "mozilla/dom/Element.h"
|
||||||
|
|
@ -68,6 +69,17 @@ ShadowRoot::ShadowRoot(Element* aElement, ShadowRootMode aMode,
|
||||||
ClearSubtreeRootPointer();
|
ClearSubtreeRootPointer();
|
||||||
|
|
||||||
SetFlags(NODE_IS_IN_SHADOW_TREE);
|
SetFlags(NODE_IS_IN_SHADOW_TREE);
|
||||||
|
if (Host()->IsInNativeAnonymousSubtree()) {
|
||||||
|
// NOTE(emilio): We could consider just propagating the
|
||||||
|
// IN_NATIVE_ANONYMOUS_SUBTREE flag (not making this an anonymous root), but
|
||||||
|
// that breaks the invariant that if two nodes have the same
|
||||||
|
// NativeAnonymousSubtreeRoot() they are in the same DOM tree, which we rely
|
||||||
|
// on a couple places and would need extra fixes.
|
||||||
|
//
|
||||||
|
// We don't hit this case for now anyways, bug 1824886 would start hitting
|
||||||
|
// it.
|
||||||
|
SetIsNativeAnonymousRoot();
|
||||||
|
}
|
||||||
Bind();
|
Bind();
|
||||||
|
|
||||||
ExtendedDOMSlots()->mContainingShadow = this;
|
ExtendedDOMSlots()->mContainingShadow = this;
|
||||||
|
|
@ -115,6 +127,10 @@ void ShadowRoot::NodeInfoChanged(Document* aOldDoc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShadowRoot::CloneInternalDataFrom(ShadowRoot* aOther) {
|
void ShadowRoot::CloneInternalDataFrom(ShadowRoot* aOther) {
|
||||||
|
if (aOther->IsRootOfNativeAnonymousSubtree()) {
|
||||||
|
SetIsNativeAnonymousRoot();
|
||||||
|
}
|
||||||
|
|
||||||
if (aOther->IsUAWidget()) {
|
if (aOther->IsUAWidget()) {
|
||||||
SetIsUAWidget();
|
SetIsUAWidget();
|
||||||
}
|
}
|
||||||
|
|
@ -747,7 +763,7 @@ nsINode* ShadowRoot::ImportNodeAndAppendChildAt(nsINode& aParentNode,
|
||||||
mozilla::ErrorResult& rv) {
|
mozilla::ErrorResult& rv) {
|
||||||
MOZ_ASSERT(IsUAWidget());
|
MOZ_ASSERT(IsUAWidget());
|
||||||
|
|
||||||
if (!aParentNode.IsInUAWidget()) {
|
if (aParentNode.SubtreeRoot() != this) {
|
||||||
rv.Throw(NS_ERROR_INVALID_ARG);
|
rv.Throw(NS_ERROR_INVALID_ARG);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
@ -765,7 +781,7 @@ nsINode* ShadowRoot::CreateElementAndAppendChildAt(nsINode& aParentNode,
|
||||||
mozilla::ErrorResult& rv) {
|
mozilla::ErrorResult& rv) {
|
||||||
MOZ_ASSERT(IsUAWidget());
|
MOZ_ASSERT(IsUAWidget());
|
||||||
|
|
||||||
if (!aParentNode.IsInUAWidget()) {
|
if (aParentNode.SubtreeRoot() != this) {
|
||||||
rv.Throw(NS_ERROR_INVALID_ARG);
|
rv.Throw(NS_ERROR_INVALID_ARG);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -222,6 +222,7 @@ class ShadowRoot final : public DocumentFragment,
|
||||||
|
|
||||||
void SetIsUAWidget() {
|
void SetIsUAWidget() {
|
||||||
MOZ_ASSERT(!HasChildren());
|
MOZ_ASSERT(!HasChildren());
|
||||||
|
SetIsNativeAnonymousRoot();
|
||||||
SetFlags(NODE_HAS_BEEN_IN_UA_WIDGET);
|
SetFlags(NODE_HAS_BEEN_IN_UA_WIDGET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,23 +16,6 @@
|
||||||
#include "mozilla/dom/HTMLSlotElement.h"
|
#include "mozilla/dom/HTMLSlotElement.h"
|
||||||
#include "mozilla/dom/ShadowRoot.h"
|
#include "mozilla/dom/ShadowRoot.h"
|
||||||
|
|
||||||
inline bool nsINode::IsUAWidget() const {
|
|
||||||
auto* shadow = mozilla::dom::ShadowRoot::FromNode(this);
|
|
||||||
return shadow && shadow->IsUAWidget();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool nsINode::IsInUAWidget() const {
|
|
||||||
if (!IsInShadowTree()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
mozilla::dom::ShadowRoot* shadow = AsContent()->GetContainingShadow();
|
|
||||||
return shadow && shadow->IsUAWidget();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool nsINode::IsRootOfChromeAccessOnlySubtree() const {
|
|
||||||
return IsRootOfNativeAnonymousSubtree() || IsUAWidget();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool nsIContent::IsInHTMLDocument() const {
|
inline bool nsIContent::IsInHTMLDocument() const {
|
||||||
return OwnerDoc()->IsHTMLDocument();
|
return OwnerDoc()->IsHTMLDocument();
|
||||||
}
|
}
|
||||||
|
|
@ -194,18 +177,10 @@ inline bool nsINode::IsInDesignMode() const {
|
||||||
|
|
||||||
// If the shadow host is not in design mode, this can never be in design
|
// If the shadow host is not in design mode, this can never be in design
|
||||||
// mode. Otherwise, the content is never editable by design mode of
|
// mode. Otherwise, the content is never editable by design mode of
|
||||||
// composed document.
|
// composed document. If we're in a native anonymous subtree, we should
|
||||||
if (IsInUAWidget()) {
|
// consider it with the host.
|
||||||
nsIContent* host = GetContainingShadowHost();
|
|
||||||
MOZ_DIAGNOSTIC_ASSERT(host != this);
|
|
||||||
return host && host->IsInDesignMode();
|
|
||||||
}
|
|
||||||
MOZ_ASSERT(!IsUAWidget());
|
|
||||||
|
|
||||||
// If we're in a native anonymous subtree, we should consider it with the
|
|
||||||
// host.
|
|
||||||
if (IsInNativeAnonymousSubtree()) {
|
if (IsInNativeAnonymousSubtree()) {
|
||||||
nsIContent* host = GetClosestNativeAnonymousSubtreeRootParent();
|
nsIContent* host = GetClosestNativeAnonymousSubtreeRootParentOrHost();
|
||||||
MOZ_DIAGNOSTIC_ASSERT(host != this);
|
MOZ_DIAGNOSTIC_ASSERT(host != this);
|
||||||
return host && host->IsInDesignMode();
|
return host && host->IsInDesignMode();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -420,7 +420,7 @@ Element* nsINode::GetAnonymousRootElementOfTextEditor(
|
||||||
RefPtr<TextControlElement> textControlElement;
|
RefPtr<TextControlElement> textControlElement;
|
||||||
if (IsInNativeAnonymousSubtree()) {
|
if (IsInNativeAnonymousSubtree()) {
|
||||||
textControlElement = TextControlElement::FromNodeOrNull(
|
textControlElement = TextControlElement::FromNodeOrNull(
|
||||||
GetClosestNativeAnonymousSubtreeRootParent());
|
GetClosestNativeAnonymousSubtreeRootParentOrHost());
|
||||||
} else {
|
} else {
|
||||||
textControlElement = TextControlElement::FromNode(this);
|
textControlElement = TextControlElement::FromNode(this);
|
||||||
}
|
}
|
||||||
|
|
@ -474,15 +474,6 @@ nsIContent* nsINode::GetFirstChildOfTemplateOrNode() {
|
||||||
return GetFirstChild();
|
return GetFirstChild();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsINode* nsINode::GetParentOrShadowHostNode() const {
|
|
||||||
if (mParent) {
|
|
||||||
return mParent;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ShadowRoot* shadowRoot = ShadowRoot::FromNode(this);
|
|
||||||
return shadowRoot ? shadowRoot->GetHost() : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsINode* nsINode::SubtreeRoot() const {
|
nsINode* nsINode::SubtreeRoot() const {
|
||||||
auto RootOfNode = [](const nsINode* aStart) -> nsINode* {
|
auto RootOfNode = [](const nsINode* aStart) -> nsINode* {
|
||||||
const nsINode* node = aStart;
|
const nsINode* node = aStart;
|
||||||
|
|
@ -797,6 +788,11 @@ std::ostream& operator<<(std::ostream& aStream, const nsINode& aNode) {
|
||||||
return aStream << str.get();
|
return aStream << str.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsIContent* nsINode::DoGetShadowHost() const {
|
||||||
|
MOZ_ASSERT(IsShadowRoot());
|
||||||
|
return static_cast<const ShadowRoot*>(this)->GetHost();
|
||||||
|
}
|
||||||
|
|
||||||
ShadowRoot* nsINode::GetContainingShadow() const {
|
ShadowRoot* nsINode::GetContainingShadow() const {
|
||||||
if (!IsInShadowTree()) {
|
if (!IsInShadowTree()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
@ -3614,12 +3610,12 @@ nsINode* nsINode::GetFlattenedTreeParentNodeNonInline() const {
|
||||||
|
|
||||||
ParentObject nsINode::GetParentObject() const {
|
ParentObject nsINode::GetParentObject() const {
|
||||||
ParentObject p(OwnerDoc());
|
ParentObject p(OwnerDoc());
|
||||||
// Note that mReflectionScope is a no-op for chrome, and other places
|
// Note that mReflectionScope is a no-op for chrome, and other places where we
|
||||||
// where we don't check this value.
|
// don't check this value.
|
||||||
if (ShouldUseNACScope(this)) {
|
if (ShouldUseUAWidgetScope(this)) {
|
||||||
p.mReflectionScope = ReflectionScope::NAC;
|
|
||||||
} else if (ShouldUseUAWidgetScope(this)) {
|
|
||||||
p.mReflectionScope = ReflectionScope::UAWidget;
|
p.mReflectionScope = ReflectionScope::UAWidget;
|
||||||
|
} else if (ShouldUseNACScope(this)) {
|
||||||
|
p.mReflectionScope = ReflectionScope::NAC;
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ enum class CallerType : uint32_t;
|
||||||
#define NODE_FLAG_BIT(n_) \
|
#define NODE_FLAG_BIT(n_) \
|
||||||
(nsWrapperCache::FlagsType(1U) << (WRAPPER_CACHE_FLAGS_BITS_USED + (n_)))
|
(nsWrapperCache::FlagsType(1U) << (WRAPPER_CACHE_FLAGS_BITS_USED + (n_)))
|
||||||
|
|
||||||
enum {
|
enum : uint32_t {
|
||||||
// This bit will be set if the node has a listener manager.
|
// This bit will be set if the node has a listener manager.
|
||||||
NODE_HAS_LISTENERMANAGER = NODE_FLAG_BIT(0),
|
NODE_HAS_LISTENERMANAGER = NODE_FLAG_BIT(0),
|
||||||
|
|
||||||
|
|
@ -1034,7 +1034,19 @@ class nsINode : public mozilla::dom::EventTarget {
|
||||||
*/
|
*/
|
||||||
nsINode* GetParentNode() const { return mParent; }
|
nsINode* GetParentNode() const { return mParent; }
|
||||||
|
|
||||||
nsINode* GetParentOrShadowHostNode() const;
|
private:
|
||||||
|
nsIContent* DoGetShadowHost() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
nsINode* GetParentOrShadowHostNode() const {
|
||||||
|
if (MOZ_LIKELY(mParent)) {
|
||||||
|
return mParent;
|
||||||
|
}
|
||||||
|
// We could put this in nsIContentInlines.h or such to avoid this
|
||||||
|
// reinterpret_cast, but it doesn't seem worth it.
|
||||||
|
return IsInShadowTree() ? reinterpret_cast<nsINode*>(DoGetShadowHost())
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
enum FlattenedParentType { eNotForStyle, eForStyle };
|
enum FlattenedParentType { eNotForStyle, eForStyle };
|
||||||
|
|
||||||
|
|
@ -1416,16 +1428,24 @@ class nsINode : public mozilla::dom::EventTarget {
|
||||||
/**
|
/**
|
||||||
* If |this| or any ancestor is native anonymous, return the parent of the
|
* If |this| or any ancestor is native anonymous, return the parent of the
|
||||||
* native anonymous subtree. Note that in case of nested native anonymous
|
* native anonymous subtree. Note that in case of nested native anonymous
|
||||||
* content, this returns the parent of the innermost root, not the outermost.
|
* content, this returns the parent or host of the innermost root, not the
|
||||||
|
* outermost.
|
||||||
*/
|
*/
|
||||||
nsIContent* GetClosestNativeAnonymousSubtreeRootParent() const {
|
nsIContent* GetClosestNativeAnonymousSubtreeRootParentOrHost() const {
|
||||||
const nsIContent* root = GetClosestNativeAnonymousSubtreeRoot();
|
// We could put this in nsIContentInlines.h or such to avoid this
|
||||||
|
// reinterpret_cast, but it doesn't seem worth it.
|
||||||
|
const auto* root = reinterpret_cast<const nsINode*>(
|
||||||
|
GetClosestNativeAnonymousSubtreeRoot());
|
||||||
if (!root) {
|
if (!root) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
// We could put this in nsIContentInlines.h or such to avoid this
|
if (nsIContent* parent = root->GetParent()) {
|
||||||
// reinterpret_cast, but it doesn't seem worth it.
|
return parent;
|
||||||
return reinterpret_cast<const nsINode*>(root)->GetParent();
|
}
|
||||||
|
if (MOZ_UNLIKELY(root->IsInShadowTree())) {
|
||||||
|
return root->DoGetShadowHost();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1456,20 +1476,10 @@ class nsINode : public mozilla::dom::EventTarget {
|
||||||
|
|
||||||
// True for native anonymous content and for content in UA widgets.
|
// True for native anonymous content and for content in UA widgets.
|
||||||
// Only nsIContent can fulfill this condition.
|
// Only nsIContent can fulfill this condition.
|
||||||
bool ChromeOnlyAccess() const {
|
bool ChromeOnlyAccess() const { return IsInNativeAnonymousSubtree(); }
|
||||||
return HasFlag(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE |
|
|
||||||
NODE_HAS_BEEN_IN_UA_WIDGET);
|
|
||||||
}
|
|
||||||
|
|
||||||
const nsIContent* GetChromeOnlyAccessSubtreeRootParent() const {
|
const nsIContent* GetChromeOnlyAccessSubtreeRootParent() const {
|
||||||
if (!ChromeOnlyAccess()) {
|
return GetClosestNativeAnonymousSubtreeRootParentOrHost();
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
// We can have NAC in UA widgets, but not the other way around.
|
|
||||||
if (IsInNativeAnonymousSubtree()) {
|
|
||||||
return GetClosestNativeAnonymousSubtreeRootParent();
|
|
||||||
}
|
|
||||||
return GetContainingShadowHost();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsInShadowTree() const { return HasFlag(NODE_IS_IN_SHADOW_TREE); }
|
bool IsInShadowTree() const { return HasFlag(NODE_IS_IN_SHADOW_TREE); }
|
||||||
|
|
@ -1486,12 +1496,10 @@ class nsINode : public mozilla::dom::EventTarget {
|
||||||
return HasFlag(NODE_IS_NATIVE_ANONYMOUS_ROOT);
|
return HasFlag(NODE_IS_NATIVE_ANONYMOUS_ROOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Whether this node is a UA Widget ShadowRoot.
|
|
||||||
inline bool IsUAWidget() const;
|
|
||||||
// Whether this node is currently in a UA Widget Shadow tree.
|
|
||||||
inline bool IsInUAWidget() const;
|
|
||||||
// Whether this node is the root of a ChromeOnlyAccess DOM subtree.
|
// Whether this node is the root of a ChromeOnlyAccess DOM subtree.
|
||||||
inline bool IsRootOfChromeAccessOnlySubtree() const;
|
bool IsRootOfChromeAccessOnlySubtree() const {
|
||||||
|
return IsRootOfNativeAnonymousSubtree();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if |this| node is the closest common inclusive ancestor
|
* Returns true if |this| node is the closest common inclusive ancestor
|
||||||
|
|
|
||||||
|
|
@ -1157,7 +1157,7 @@ bool EventStateManager::LookForAccessKeyAndExecute(
|
||||||
start = mAccessKeys.IndexOf(focusedElement);
|
start = mAccessKeys.IndexOf(focusedElement);
|
||||||
if (start == -1 && focusedElement->IsInNativeAnonymousSubtree()) {
|
if (start == -1 && focusedElement->IsInNativeAnonymousSubtree()) {
|
||||||
start = mAccessKeys.IndexOf(Element::FromNodeOrNull(
|
start = mAccessKeys.IndexOf(Element::FromNodeOrNull(
|
||||||
focusedElement->GetClosestNativeAnonymousSubtreeRootParent()));
|
focusedElement->GetClosestNativeAnonymousSubtreeRootParentOrHost()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RefPtr<Element> element;
|
RefPtr<Element> element;
|
||||||
|
|
@ -1935,7 +1935,7 @@ void EventStateManager::BeginTrackingRemoteDragGesture(
|
||||||
mGestureDownInTextControl =
|
mGestureDownInTextControl =
|
||||||
aContent && aContent->IsInNativeAnonymousSubtree() &&
|
aContent && aContent->IsInNativeAnonymousSubtree() &&
|
||||||
TextControlElement::FromNodeOrNull(
|
TextControlElement::FromNodeOrNull(
|
||||||
aContent->GetClosestNativeAnonymousSubtreeRootParent());
|
aContent->GetClosestNativeAnonymousSubtreeRootParentOrHost());
|
||||||
mGestureDownDragStartData = aDragStartData;
|
mGestureDownDragStartData = aDragStartData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5887,7 +5887,8 @@ void EventStateManager::TextControlRootWillBeRemoved(
|
||||||
// caused by reframing aTextControlElement which may not be intended by the
|
// caused by reframing aTextControlElement which may not be intended by the
|
||||||
// user.
|
// user.
|
||||||
if (&aTextControlElement ==
|
if (&aTextControlElement ==
|
||||||
mGestureDownFrameOwner->GetClosestNativeAnonymousSubtreeRootParent()) {
|
mGestureDownFrameOwner
|
||||||
|
->GetClosestNativeAnonymousSubtreeRootParentOrHost()) {
|
||||||
mGestureDownFrameOwner = &aTextControlElement;
|
mGestureDownFrameOwner = &aTextControlElement;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ WheelHandlingUtils::GetDisregardedWheelScrollDirection(const nsIFrame* aFrame) {
|
||||||
}
|
}
|
||||||
TextControlElement* textControlElement = TextControlElement::FromNodeOrNull(
|
TextControlElement* textControlElement = TextControlElement::FromNodeOrNull(
|
||||||
content->IsInNativeAnonymousSubtree()
|
content->IsInNativeAnonymousSubtree()
|
||||||
? content->GetClosestNativeAnonymousSubtreeRootParent()
|
? content->GetClosestNativeAnonymousSubtreeRootParentOrHost()
|
||||||
: content);
|
: content);
|
||||||
if (!textControlElement || !textControlElement->IsSingleLineTextControl()) {
|
if (!textControlElement || !textControlElement->IsSingleLineTextControl()) {
|
||||||
return Nothing();
|
return Nothing();
|
||||||
|
|
|
||||||
|
|
@ -4660,7 +4660,7 @@ void HTMLMediaElement::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
HTMLInputElement* el = nullptr;
|
HTMLInputElement* el = nullptr;
|
||||||
if (node->IsInNativeAnonymousSubtree() || node->IsInUAWidget()) {
|
if (node->ChromeOnlyAccess()) {
|
||||||
if (node->IsHTMLElement(nsGkAtoms::input)) {
|
if (node->IsHTMLElement(nsGkAtoms::input)) {
|
||||||
// The node is a <input type="range">
|
// The node is a <input type="range">
|
||||||
el = static_cast<HTMLInputElement*>(node);
|
el = static_cast<HTMLInputElement*>(node);
|
||||||
|
|
|
||||||
|
|
@ -4344,9 +4344,9 @@ nsresult EditorBase::HandleDropEvent(DragEvent* aDropEvent) {
|
||||||
// If the source node is in native anonymous tree, it must be in
|
// If the source node is in native anonymous tree, it must be in
|
||||||
// <input> or <textarea> element. If so, its TextEditor can remove it.
|
// <input> or <textarea> element. If so, its TextEditor can remove it.
|
||||||
if (sourceNode->IsInNativeAnonymousSubtree()) {
|
if (sourceNode->IsInNativeAnonymousSubtree()) {
|
||||||
if (RefPtr<TextControlElement> textControlElement =
|
if (RefPtr textControlElement = TextControlElement::FromNodeOrNull(
|
||||||
TextControlElement::FromNodeOrNull(
|
sourceNode
|
||||||
sourceNode->GetClosestNativeAnonymousSubtreeRootParent())) {
|
->GetClosestNativeAnonymousSubtreeRootParentOrHost())) {
|
||||||
editorToDeleteSelection = textControlElement->GetTextEditor();
|
editorToDeleteSelection = textControlElement->GetTextEditor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -5296,7 +5296,7 @@ Element* EditorBase::GetExposedRoot() const {
|
||||||
return rootElement;
|
return rootElement;
|
||||||
}
|
}
|
||||||
return Element::FromNodeOrNull(
|
return Element::FromNodeOrNull(
|
||||||
rootElement->GetClosestNativeAnonymousSubtreeRootParent());
|
rootElement->GetClosestNativeAnonymousSubtreeRootParentOrHost());
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult EditorBase::DetermineCurrentDirection() {
|
nsresult EditorBase::DetermineCurrentDirection() {
|
||||||
|
|
|
||||||
|
|
@ -1375,9 +1375,10 @@ class EditorDOMRangeBase final {
|
||||||
if (mStart.IsInNativeAnonymousSubtree()) {
|
if (mStart.IsInNativeAnonymousSubtree()) {
|
||||||
nsIContent* parent = nullptr;
|
nsIContent* parent = nullptr;
|
||||||
for (parent = mStart.template ContainerAs<nsIContent>()
|
for (parent = mStart.template ContainerAs<nsIContent>()
|
||||||
->GetClosestNativeAnonymousSubtreeRootParent();
|
->GetClosestNativeAnonymousSubtreeRootParentOrHost();
|
||||||
parent && parent->IsInNativeAnonymousSubtree();
|
parent && parent->IsInNativeAnonymousSubtree();
|
||||||
parent = parent->GetClosestNativeAnonymousSubtreeRootParent()) {
|
parent =
|
||||||
|
parent->GetClosestNativeAnonymousSubtreeRootParentOrHost()) {
|
||||||
}
|
}
|
||||||
if (MOZ_UNLIKELY(!parent)) {
|
if (MOZ_UNLIKELY(!parent)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -1387,9 +1388,10 @@ class EditorDOMRangeBase final {
|
||||||
if (mEnd.IsInNativeAnonymousSubtree()) {
|
if (mEnd.IsInNativeAnonymousSubtree()) {
|
||||||
nsIContent* parent = nullptr;
|
nsIContent* parent = nullptr;
|
||||||
for (parent = mEnd.template ContainerAs<nsIContent>()
|
for (parent = mEnd.template ContainerAs<nsIContent>()
|
||||||
->GetClosestNativeAnonymousSubtreeRootParent();
|
->GetClosestNativeAnonymousSubtreeRootParentOrHost();
|
||||||
parent && parent->IsInNativeAnonymousSubtree();
|
parent && parent->IsInNativeAnonymousSubtree();
|
||||||
parent = parent->GetClosestNativeAnonymousSubtreeRootParent()) {
|
parent =
|
||||||
|
parent->GetClosestNativeAnonymousSubtreeRootParentOrHost()) {
|
||||||
}
|
}
|
||||||
if (MOZ_UNLIKELY(!parent)) {
|
if (MOZ_UNLIKELY(!parent)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ nsNumberControlFrame* nsNumberControlFrame::GetNumberControlFrameForSpinButton(
|
||||||
// be wrapped around any of the elements between aFrame and the
|
// be wrapped around any of the elements between aFrame and the
|
||||||
// nsNumberControlFrame that we're looking for (e.g. flex wrappers).
|
// nsNumberControlFrame that we're looking for (e.g. flex wrappers).
|
||||||
nsIContent* content = aFrame->GetContent();
|
nsIContent* content = aFrame->GetContent();
|
||||||
auto* nacHost = content->GetClosestNativeAnonymousSubtreeRootParent();
|
auto* nacHost = content->GetClosestNativeAnonymousSubtreeRootParentOrHost();
|
||||||
if (!nacHost) {
|
if (!nacHost) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1244,7 +1244,7 @@ static bool IsMarqueeScrollbox(const nsIFrame& aScrollFrame) {
|
||||||
if (!aScrollFrame.GetContent()) {
|
if (!aScrollFrame.GetContent()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (MOZ_LIKELY(!aScrollFrame.GetContent()->IsInUAWidget())) {
|
if (MOZ_LIKELY(!aScrollFrame.GetContent()->HasBeenInUAWidget())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
MOZ_ASSERT(aScrollFrame.GetParent() &&
|
MOZ_ASSERT(aScrollFrame.GetParent() &&
|
||||||
|
|
@ -5486,7 +5486,7 @@ bool nsHTMLScrollFrame::IsForTextControlWithNoScrollbars() const {
|
||||||
if (!content) {
|
if (!content) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto* input = content->GetClosestNativeAnonymousSubtreeRootParent();
|
auto* input = content->GetClosestNativeAnonymousSubtreeRootParentOrHost();
|
||||||
return input && input->IsHTMLElement(nsGkAtoms::input);
|
return input && input->IsHTMLElement(nsGkAtoms::input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2389,7 +2389,7 @@ int16_t nsIFrame::DetermineDisplaySelection() {
|
||||||
static Element* FindElementAncestorForMozSelection(nsIContent* aContent) {
|
static Element* FindElementAncestorForMozSelection(nsIContent* aContent) {
|
||||||
NS_ENSURE_TRUE(aContent, nullptr);
|
NS_ENSURE_TRUE(aContent, nullptr);
|
||||||
while (aContent && aContent->IsInNativeAnonymousSubtree()) {
|
while (aContent && aContent->IsInNativeAnonymousSubtree()) {
|
||||||
aContent = aContent->GetClosestNativeAnonymousSubtreeRootParent();
|
aContent = aContent->GetClosestNativeAnonymousSubtreeRootParentOrHost();
|
||||||
}
|
}
|
||||||
NS_ASSERTION(aContent, "aContent isn't in non-anonymous tree?");
|
NS_ASSERTION(aContent, "aContent isn't in non-anonymous tree?");
|
||||||
return aContent ? aContent->GetAsElementOrParentElement() : nullptr;
|
return aContent ? aContent->GetAsElementOrParentElement() : nullptr;
|
||||||
|
|
|
||||||
|
|
@ -1857,8 +1857,8 @@ Result<Loader::LoadSheetResult, nsresult> Loader::LoadStyleLink(
|
||||||
if (!aInfo.mContent) {
|
if (!aInfo.mContent) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const bool privilegedShadowTree = aInfo.mContent->IsInUAWidget() ||
|
const bool privilegedShadowTree = aInfo.mContent->IsInShadowTree() &&
|
||||||
(aInfo.mContent->IsInShadowTree() &&
|
(aInfo.mContent->ChromeOnlyAccess() ||
|
||||||
aInfo.mContent->IsInChromeDocument());
|
aInfo.mContent->IsInChromeDocument());
|
||||||
if (!privilegedShadowTree) {
|
if (!privilegedShadowTree) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -388,10 +388,10 @@ pub trait TElement:
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether this element should match user and author rules.
|
/// Whether this element should match user and content rules.
|
||||||
///
|
///
|
||||||
/// We use this for Native Anonymous Content in Gecko.
|
/// We use this for Native Anonymous Content in Gecko.
|
||||||
fn matches_user_and_author_rules(&self) -> bool {
|
fn matches_user_and_content_rules(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -651,11 +651,6 @@ pub trait TElement:
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if this element is in a native anonymous subtree.
|
|
||||||
fn is_in_native_anonymous_subtree(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the pseudo-element implemented by this element, if any.
|
/// Returns the pseudo-element implemented by this element, if any.
|
||||||
///
|
///
|
||||||
/// Gecko traverses pseudo-elements during the style traversal, and we need
|
/// Gecko traverses pseudo-elements during the style traversal, and we need
|
||||||
|
|
@ -791,11 +786,8 @@ pub trait TElement:
|
||||||
use crate::rule_collector::containing_shadow_ignoring_svg_use;
|
use crate::rule_collector::containing_shadow_ignoring_svg_use;
|
||||||
|
|
||||||
let target = self.rule_hash_target();
|
let target = self.rule_hash_target();
|
||||||
if !target.matches_user_and_author_rules() {
|
let matches_user_and_content_rules = target.matches_user_and_content_rules();
|
||||||
return false;
|
let mut doc_rules_apply = matches_user_and_content_rules;
|
||||||
}
|
|
||||||
|
|
||||||
let mut doc_rules_apply = true;
|
|
||||||
|
|
||||||
// Use the same rules to look for the containing host as we do for rule
|
// Use the same rules to look for the containing host as we do for rule
|
||||||
// collection.
|
// collection.
|
||||||
|
|
@ -843,9 +835,9 @@ pub trait TElement:
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
// TODO(emilio): Should probably distinguish with
|
// TODO(emilio): Should probably distinguish with
|
||||||
// MatchesDocumentRules::{No,Yes,IfPart} or
|
// MatchesDocumentRules::{No,Yes,IfPart} or something so that we could
|
||||||
// something so that we could skip some work.
|
// skip some work.
|
||||||
doc_rules_apply = true;
|
doc_rules_apply = matches_user_and_content_rules;
|
||||||
break;
|
break;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -325,32 +325,34 @@ impl<'ln> GeckoNode<'ln> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_in_shadow_tree(&self) -> bool {
|
fn is_in_shadow_tree(&self) -> bool {
|
||||||
use crate::gecko_bindings::structs::NODE_IS_IN_SHADOW_TREE;
|
use crate::gecko_bindings::structs::NODE_IS_IN_SHADOW_TREE;
|
||||||
self.flags() & (NODE_IS_IN_SHADOW_TREE as u32) != 0
|
self.flags() & NODE_IS_IN_SHADOW_TREE != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// WARNING: This logic is duplicated in Gecko's FlattenedTreeParentIsParent.
|
/// Returns true if we know for sure that `flattened_tree_parent` and `parent_node` return the
|
||||||
/// Make sure to mirror any modifications in both places.
|
/// same thing.
|
||||||
|
///
|
||||||
|
/// TODO(emilio): Measure and consider not doing this fast-path, it's only a function call and
|
||||||
|
/// from profiles it seems that keeping this fast path makes the compiler not inline
|
||||||
|
/// `flattened_tree_parent` as a whole, so we're not gaining much either.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn flattened_tree_parent_is_parent(&self) -> bool {
|
fn flattened_tree_parent_is_parent(&self) -> bool {
|
||||||
use crate::gecko_bindings::structs::*;
|
use crate::gecko_bindings::structs::*;
|
||||||
let flags = self.flags();
|
let flags = self.flags();
|
||||||
|
|
||||||
// FIXME(emilio): The shadow tree condition seems it shouldn't be needed
|
let parent = match self.parent_node() {
|
||||||
// anymore, if we check for slots.
|
Some(p) => p,
|
||||||
if self.is_in_shadow_tree() {
|
None => return true,
|
||||||
|
};
|
||||||
|
|
||||||
|
if parent.is_shadow_root() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let parent = unsafe { self.0.mParent.as_ref() }.map(GeckoNode);
|
if let Some(parent) = parent.as_element() {
|
||||||
let parent_el = parent.and_then(|p| p.as_element());
|
if flags & NODE_IS_NATIVE_ANONYMOUS_ROOT != 0 && parent.is_root() {
|
||||||
if flags & (NODE_IS_NATIVE_ANONYMOUS_ROOT as u32) != 0 &&
|
return false;
|
||||||
parent_el.map_or(false, |el| el.is_root())
|
}
|
||||||
{
|
if parent.shadow_root().is_some() || parent.is_html_slot_element() {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(parent) = parent_el {
|
|
||||||
if parent.shadow_root().is_some() {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -360,10 +362,6 @@ impl<'ln> GeckoNode<'ln> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn flattened_tree_parent(&self) -> Option<Self> {
|
fn flattened_tree_parent(&self) -> Option<Self> {
|
||||||
// TODO(emilio): Measure and consider not doing this fast-path and take
|
|
||||||
// always the common path, it's only a function call and from profiles
|
|
||||||
// it seems that keeping this fast path makes the compiler not inline
|
|
||||||
// `flattened_tree_parent`.
|
|
||||||
if self.flattened_tree_parent_is_parent() {
|
if self.flattened_tree_parent_is_parent() {
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
@ -374,12 +372,10 @@ impl<'ln> GeckoNode<'ln> {
|
||||||
self.parent_node(),
|
self.parent_node(),
|
||||||
"Fast path stopped holding!"
|
"Fast path stopped holding!"
|
||||||
);
|
);
|
||||||
|
|
||||||
return self.parent_node();
|
return self.parent_node();
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(emilio): If this call is too expensive, we could manually
|
// NOTE(emilio): If this call is too expensive, we could manually inline more aggressively.
|
||||||
// inline more aggressively.
|
|
||||||
unsafe {
|
unsafe {
|
||||||
bindings::Gecko_GetFlattenedTreeParentNode(self.0)
|
bindings::Gecko_GetFlattenedTreeParentNode(self.0)
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
|
@ -650,20 +646,6 @@ impl<'le> GeckoElement<'le> {
|
||||||
snapshot_helpers::find_attr(self.non_mapped_attrs(), &atom!("class"))
|
snapshot_helpers::find_attr(self.non_mapped_attrs(), &atom!("class"))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn closest_anon_subtree_root_parent(&self) -> Option<Self> {
|
|
||||||
debug_assert!(self.is_in_native_anonymous_subtree());
|
|
||||||
let mut current = *self;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
if current.is_root_of_native_anonymous_subtree() {
|
|
||||||
return current.traversal_parent();
|
|
||||||
}
|
|
||||||
|
|
||||||
current = current.traversal_parent()?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn may_have_anonymous_children(&self) -> bool {
|
fn may_have_anonymous_children(&self) -> bool {
|
||||||
self.as_node()
|
self.as_node()
|
||||||
|
|
@ -690,13 +672,13 @@ impl<'le> GeckoElement<'le> {
|
||||||
/// Returns true if this element has descendants for lazy frame construction.
|
/// Returns true if this element has descendants for lazy frame construction.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn descendants_need_frames(&self) -> bool {
|
pub fn descendants_need_frames(&self) -> bool {
|
||||||
self.flags() & (NODE_DESCENDANTS_NEED_FRAMES as u32) != 0
|
self.flags() & NODE_DESCENDANTS_NEED_FRAMES != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if this element needs lazy frame construction.
|
/// Returns true if this element needs lazy frame construction.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn needs_frame(&self) -> bool {
|
pub fn needs_frame(&self) -> bool {
|
||||||
self.flags() & (NODE_NEEDS_FRAME as u32) != 0
|
self.flags() & NODE_NEEDS_FRAME != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reference to the DOM slots for this Element, if they exist.
|
/// Returns a reference to the DOM slots for this Element, if they exist.
|
||||||
|
|
@ -754,7 +736,7 @@ impl<'le> GeckoElement<'le> {
|
||||||
fn has_properties(&self) -> bool {
|
fn has_properties(&self) -> bool {
|
||||||
use crate::gecko_bindings::structs::NODE_HAS_PROPERTIES;
|
use crate::gecko_bindings::structs::NODE_HAS_PROPERTIES;
|
||||||
|
|
||||||
(self.flags() & NODE_HAS_PROPERTIES as u32) != 0
|
self.flags() & NODE_HAS_PROPERTIES != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
@ -822,7 +804,7 @@ impl<'le> GeckoElement<'le> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_root_of_native_anonymous_subtree(&self) -> bool {
|
fn is_root_of_native_anonymous_subtree(&self) -> bool {
|
||||||
use crate::gecko_bindings::structs::NODE_IS_NATIVE_ANONYMOUS_ROOT;
|
use crate::gecko_bindings::structs::NODE_IS_NATIVE_ANONYMOUS_ROOT;
|
||||||
return self.flags() & (NODE_IS_NATIVE_ANONYMOUS_ROOT as u32) != 0;
|
return self.flags() & NODE_IS_NATIVE_ANONYMOUS_ROOT != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if this node is the shadow root of an use-element shadow tree.
|
/// Returns true if this node is the shadow root of an use-element shadow tree.
|
||||||
|
|
@ -905,19 +887,19 @@ fn selector_flags_to_node_flags(flags: ElementSelectorFlags) -> u32 {
|
||||||
use crate::gecko_bindings::structs::*;
|
use crate::gecko_bindings::structs::*;
|
||||||
let mut gecko_flags = 0u32;
|
let mut gecko_flags = 0u32;
|
||||||
if flags.contains(ElementSelectorFlags::HAS_SLOW_SELECTOR) {
|
if flags.contains(ElementSelectorFlags::HAS_SLOW_SELECTOR) {
|
||||||
gecko_flags |= NODE_HAS_SLOW_SELECTOR as u32;
|
gecko_flags |= NODE_HAS_SLOW_SELECTOR;
|
||||||
}
|
}
|
||||||
if flags.contains(ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS) {
|
if flags.contains(ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS) {
|
||||||
gecko_flags |= NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS as u32;
|
gecko_flags |= NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS;
|
||||||
}
|
}
|
||||||
if flags.contains(ElementSelectorFlags::HAS_SLOW_SELECTOR_NTH_OF) {
|
if flags.contains(ElementSelectorFlags::HAS_SLOW_SELECTOR_NTH_OF) {
|
||||||
gecko_flags |= NODE_HAS_SLOW_SELECTOR_NTH_OF as u32;
|
gecko_flags |= NODE_HAS_SLOW_SELECTOR_NTH_OF;
|
||||||
}
|
}
|
||||||
if flags.contains(ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR) {
|
if flags.contains(ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR) {
|
||||||
gecko_flags |= NODE_HAS_EDGE_CHILD_SELECTOR as u32;
|
gecko_flags |= NODE_HAS_EDGE_CHILD_SELECTOR;
|
||||||
}
|
}
|
||||||
if flags.contains(ElementSelectorFlags::HAS_EMPTY_SELECTOR) {
|
if flags.contains(ElementSelectorFlags::HAS_EMPTY_SELECTOR) {
|
||||||
gecko_flags |= NODE_HAS_EMPTY_SELECTOR as u32;
|
gecko_flags |= NODE_HAS_EMPTY_SELECTOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
gecko_flags
|
gecko_flags
|
||||||
|
|
@ -974,8 +956,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
// StyleChildrenIterator::IsNeeded does, except that it might return
|
// StyleChildrenIterator::IsNeeded does, except that it might return
|
||||||
// true if we used to (but no longer) have anonymous content from
|
// true if we used to (but no longer) have anonymous content from
|
||||||
// ::before/::after, or nsIAnonymousContentCreators.
|
// ::before/::after, or nsIAnonymousContentCreators.
|
||||||
if self.is_in_native_anonymous_subtree() ||
|
if self.is_html_slot_element() ||
|
||||||
self.is_html_slot_element() ||
|
|
||||||
self.shadow_root().is_some() ||
|
self.shadow_root().is_some() ||
|
||||||
self.may_have_anonymous_children()
|
self.may_have_anonymous_children()
|
||||||
{
|
{
|
||||||
|
|
@ -1296,52 +1277,52 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn has_snapshot(&self) -> bool {
|
fn has_snapshot(&self) -> bool {
|
||||||
self.flags() & (ELEMENT_HAS_SNAPSHOT as u32) != 0
|
self.flags() & ELEMENT_HAS_SNAPSHOT != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn handled_snapshot(&self) -> bool {
|
fn handled_snapshot(&self) -> bool {
|
||||||
self.flags() & (ELEMENT_HANDLED_SNAPSHOT as u32) != 0
|
self.flags() & ELEMENT_HANDLED_SNAPSHOT != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn set_handled_snapshot(&self) {
|
unsafe fn set_handled_snapshot(&self) {
|
||||||
debug_assert!(self.has_data());
|
debug_assert!(self.has_data());
|
||||||
self.set_flags(ELEMENT_HANDLED_SNAPSHOT as u32)
|
self.set_flags(ELEMENT_HANDLED_SNAPSHOT)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn has_dirty_descendants(&self) -> bool {
|
fn has_dirty_descendants(&self) -> bool {
|
||||||
self.flags() & (ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32) != 0
|
self.flags() & ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn set_dirty_descendants(&self) {
|
unsafe fn set_dirty_descendants(&self) {
|
||||||
debug_assert!(self.has_data());
|
debug_assert!(self.has_data());
|
||||||
debug!("Setting dirty descendants: {:?}", self);
|
debug!("Setting dirty descendants: {:?}", self);
|
||||||
self.set_flags(ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32)
|
self.set_flags(ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn unset_dirty_descendants(&self) {
|
unsafe fn unset_dirty_descendants(&self) {
|
||||||
self.unset_flags(ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32)
|
self.unset_flags(ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn has_animation_only_dirty_descendants(&self) -> bool {
|
fn has_animation_only_dirty_descendants(&self) -> bool {
|
||||||
self.flags() & (ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32) != 0
|
self.flags() & ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn set_animation_only_dirty_descendants(&self) {
|
unsafe fn set_animation_only_dirty_descendants(&self) {
|
||||||
self.set_flags(ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32)
|
self.set_flags(ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn unset_animation_only_dirty_descendants(&self) {
|
unsafe fn unset_animation_only_dirty_descendants(&self) {
|
||||||
self.unset_flags(ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32)
|
self.unset_flags(ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn clear_descendant_bits(&self) {
|
unsafe fn clear_descendant_bits(&self) {
|
||||||
self.unset_flags(
|
self.unset_flags(
|
||||||
ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32 |
|
ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO |
|
||||||
ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32 |
|
ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO |
|
||||||
NODE_DESCENDANTS_NEED_FRAMES as u32,
|
NODE_DESCENDANTS_NEED_FRAMES,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1349,21 +1330,19 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
self.state().intersects(ElementState::VISITED)
|
self.state().intersects(ElementState::VISITED)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This logic is duplicated in Gecko's nsINode::IsInNativeAnonymousSubtree.
|
/// We want to match rules from the same tree in all cases, except for native anonymous content
|
||||||
|
/// that _isn't_ part directly of a UA widget (e.g., such generated by form controls, or
|
||||||
|
/// pseudo-elements).
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_in_native_anonymous_subtree(&self) -> bool {
|
fn matches_user_and_content_rules(&self) -> bool {
|
||||||
use crate::gecko_bindings::structs::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE;
|
use crate::gecko_bindings::structs::{NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE, NODE_HAS_BEEN_IN_UA_WIDGET};
|
||||||
self.flags() & (NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE as u32) != 0
|
let flags = self.flags();
|
||||||
}
|
(flags & NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE) == 0 || (flags & NODE_HAS_BEEN_IN_UA_WIDGET) != 0
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn matches_user_and_author_rules(&self) -> bool {
|
|
||||||
!self.is_in_native_anonymous_subtree()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
|
fn implemented_pseudo_element(&self) -> Option<PseudoElement> {
|
||||||
if !self.is_in_native_anonymous_subtree() {
|
if self.matches_user_and_content_rules() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1371,8 +1350,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let pseudo_type = unsafe { bindings::Gecko_GetImplementedPseudo(self.0) };
|
PseudoElement::from_pseudo_type(unsafe { bindings::Gecko_GetImplementedPseudo(self.0) })
|
||||||
PseudoElement::from_pseudo_type(pseudo_type)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
@ -1396,10 +1374,10 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
unsafe fn clear_data(&self) {
|
unsafe fn clear_data(&self) {
|
||||||
let ptr = self.0.mServoData.get();
|
let ptr = self.0.mServoData.get();
|
||||||
self.unset_flags(
|
self.unset_flags(
|
||||||
ELEMENT_HAS_SNAPSHOT as u32 |
|
ELEMENT_HAS_SNAPSHOT |
|
||||||
ELEMENT_HANDLED_SNAPSHOT as u32 |
|
ELEMENT_HANDLED_SNAPSHOT |
|
||||||
structs::Element_kAllServoDescendantBits |
|
structs::Element_kAllServoDescendantBits |
|
||||||
NODE_NEEDS_FRAME as u32,
|
NODE_NEEDS_FRAME,
|
||||||
);
|
);
|
||||||
if !ptr.is_null() {
|
if !ptr.is_null() {
|
||||||
debug!("Dropping ElementData for {:?}", self);
|
debug!("Dropping ElementData for {:?}", self);
|
||||||
|
|
@ -1826,7 +1804,15 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn pseudo_element_originating_element(&self) -> Option<Self> {
|
fn pseudo_element_originating_element(&self) -> Option<Self> {
|
||||||
debug_assert!(self.is_pseudo_element());
|
debug_assert!(self.is_pseudo_element());
|
||||||
self.closest_anon_subtree_root_parent()
|
debug_assert!(!self.matches_user_and_content_rules());
|
||||||
|
let mut current = *self;
|
||||||
|
loop {
|
||||||
|
if current.is_root_of_native_anonymous_subtree() {
|
||||||
|
return current.traversal_parent();
|
||||||
|
}
|
||||||
|
|
||||||
|
current = current.traversal_parent()?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
@ -1977,6 +1963,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
.as_node()
|
.as_node()
|
||||||
.parent_node()
|
.parent_node()
|
||||||
.map_or(false, |p| p.is_document()));
|
.map_or(false, |p| p.is_document()));
|
||||||
|
// XXX this should always return true at this point, shouldn't it?
|
||||||
unsafe { bindings::Gecko_IsRootElement(self.0) }
|
unsafe { bindings::Gecko_IsRootElement(self.0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2102,7 +2089,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
},
|
},
|
||||||
NonTSPseudoClass::MozNativeAnonymous => self.is_in_native_anonymous_subtree(),
|
NonTSPseudoClass::MozNativeAnonymous => !self.matches_user_and_content_rules(),
|
||||||
NonTSPseudoClass::MozUseShadowTreeRoot => self.is_root_of_use_element_shadow_tree(),
|
NonTSPseudoClass::MozUseShadowTreeRoot => self.is_root_of_use_element_shadow_tree(),
|
||||||
NonTSPseudoClass::MozTableBorderNonzero => unsafe {
|
NonTSPseudoClass::MozTableBorderNonzero => unsafe {
|
||||||
bindings::Gecko_IsTableBorderNonzero(self.0)
|
bindings::Gecko_IsTableBorderNonzero(self.0)
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ where
|
||||||
rule_inclusion: RuleInclusion,
|
rule_inclusion: RuleInclusion,
|
||||||
rules: &'a mut ApplicableDeclarationList,
|
rules: &'a mut ApplicableDeclarationList,
|
||||||
context: &'a mut MatchingContext<'b, E::Impl>,
|
context: &'a mut MatchingContext<'b, E::Impl>,
|
||||||
matches_user_and_author_rules: bool,
|
matches_user_and_content_rules: bool,
|
||||||
matches_document_author_rules: bool,
|
matches_document_author_rules: bool,
|
||||||
in_sort_scope: bool,
|
in_sort_scope: bool,
|
||||||
}
|
}
|
||||||
|
|
@ -102,7 +102,7 @@ where
|
||||||
MatchingMode::Normal => element.rule_hash_target(),
|
MatchingMode::Normal => element.rule_hash_target(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let matches_user_and_author_rules = rule_hash_target.matches_user_and_author_rules();
|
let matches_user_and_content_rules = rule_hash_target.matches_user_and_content_rules();
|
||||||
|
|
||||||
// Gecko definitely has pseudo-elements with style attributes, like
|
// Gecko definitely has pseudo-elements with style attributes, like
|
||||||
// ::-moz-color-swatch.
|
// ::-moz-color-swatch.
|
||||||
|
|
@ -123,8 +123,8 @@ where
|
||||||
rule_inclusion,
|
rule_inclusion,
|
||||||
context,
|
context,
|
||||||
rules,
|
rules,
|
||||||
matches_user_and_author_rules,
|
matches_user_and_content_rules,
|
||||||
matches_document_author_rules: matches_user_and_author_rules,
|
matches_document_author_rules: matches_user_and_content_rules,
|
||||||
in_sort_scope: false,
|
in_sort_scope: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -179,7 +179,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_user_rules(&mut self) {
|
fn collect_user_rules(&mut self) {
|
||||||
if !self.matches_user_and_author_rules {
|
if !self.matches_user_and_content_rules {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -257,7 +257,7 @@ where
|
||||||
|
|
||||||
while let Some(slot) = current {
|
while let Some(slot) = current {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
self.matches_user_and_author_rules,
|
self.matches_user_and_content_rules,
|
||||||
"We should not slot NAC anywhere"
|
"We should not slot NAC anywhere"
|
||||||
);
|
);
|
||||||
slots.push(slot);
|
slots.push(slot);
|
||||||
|
|
@ -292,7 +292,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_rules_from_containing_shadow_tree(&mut self) {
|
fn collect_rules_from_containing_shadow_tree(&mut self) {
|
||||||
if !self.matches_user_and_author_rules {
|
if !self.matches_user_and_content_rules {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -341,11 +341,6 @@ where
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
debug_assert!(
|
|
||||||
self.matches_user_and_author_rules,
|
|
||||||
"NAC should not be a shadow host"
|
|
||||||
);
|
|
||||||
|
|
||||||
let style_data = match shadow.style_data() {
|
let style_data = match shadow.style_data() {
|
||||||
Some(d) => d,
|
Some(d) => d,
|
||||||
None => return,
|
None => return,
|
||||||
|
|
|
||||||
|
|
@ -584,8 +584,8 @@ impl<E: TElement> StyleSharingCache<E> {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if element.is_in_native_anonymous_subtree() {
|
if !element.matches_user_and_content_rules() {
|
||||||
debug!("Failing to insert into the cache: NAC");
|
debug!("Failing to insert into the cache: no tree rules:");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -674,8 +674,8 @@ impl<E: TElement> StyleSharingCache<E> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if target.is_in_native_anonymous_subtree() {
|
if !target.matches_user_and_content_rules() {
|
||||||
debug!("{:?} Cannot share style: NAC", target.element);
|
debug!("{:?} Cannot share style: content rules", target.element);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -699,7 +699,7 @@ impl<E: TElement> StyleSharingCache<E> {
|
||||||
nth_index_cache: &mut NthIndexCache,
|
nth_index_cache: &mut NthIndexCache,
|
||||||
shared_context: &SharedStyleContext,
|
shared_context: &SharedStyleContext,
|
||||||
) -> Option<ResolvedElementStyles> {
|
) -> Option<ResolvedElementStyles> {
|
||||||
debug_assert!(!target.is_in_native_anonymous_subtree());
|
debug_assert!(target.matches_user_and_content_rules());
|
||||||
|
|
||||||
// Check that we have the same parent, or at least that the parents
|
// Check that we have the same parent, or at least that the parents
|
||||||
// share styles and permit sharing across their children. The latter
|
// share styles and permit sharing across their children. The latter
|
||||||
|
|
@ -762,8 +762,8 @@ impl<E: TElement> StyleSharingCache<E> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if target.matches_user_and_author_rules() !=
|
if target.matches_user_and_content_rules() !=
|
||||||
candidate.element.matches_user_and_author_rules()
|
candidate.element.matches_user_and_content_rules()
|
||||||
{
|
{
|
||||||
trace!("Miss: User and Author Rules");
|
trace!("Miss: User and Author Rules");
|
||||||
return None;
|
return None;
|
||||||
|
|
|
||||||
|
|
@ -219,7 +219,7 @@ where
|
||||||
) -> PrimaryStyle {
|
) -> PrimaryStyle {
|
||||||
// Before doing the cascade, check the sharing cache and see if we can
|
// Before doing the cascade, check the sharing cache and see if we can
|
||||||
// reuse the style via rule node identity.
|
// reuse the style via rule node identity.
|
||||||
let may_reuse = !self.element.is_in_native_anonymous_subtree() &&
|
let may_reuse = self.element.matches_user_and_content_rules() &&
|
||||||
parent_style.is_some() &&
|
parent_style.is_some() &&
|
||||||
inputs.rules.is_some();
|
inputs.rules.is_some();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -422,7 +422,7 @@ pub fn recalc_style_at<E, D, F>(
|
||||||
if let Some(restyle_kind) = restyle_kind {
|
if let Some(restyle_kind) = restyle_kind {
|
||||||
child_restyle_requirement = compute_style(traversal_data, context, element, data, restyle_kind);
|
child_restyle_requirement = compute_style(traversal_data, context, element, data, restyle_kind);
|
||||||
|
|
||||||
if element.is_in_native_anonymous_subtree() {
|
if !element.matches_user_and_content_rules() {
|
||||||
// We must always cascade native anonymous subtrees, since they
|
// We must always cascade native anonymous subtrees, since they
|
||||||
// may have pseudo-elements underneath that would inherit from the
|
// may have pseudo-elements underneath that would inherit from the
|
||||||
// closest non-NAC ancestor instead of us.
|
// closest non-NAC ancestor instead of us.
|
||||||
|
|
|
||||||
|
|
@ -65,9 +65,9 @@ NS_IMPL_CYCLE_COLLECTION(nsFind)
|
||||||
# define DEBUG_FIND_PRINTF(...) /* nothing */
|
# define DEBUG_FIND_PRINTF(...) /* nothing */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static nsIContent& AnonymousSubtreeRootParent(const nsINode& aNode) {
|
static nsIContent& AnonymousSubtreeRootParentOrHost(const nsINode& aNode) {
|
||||||
MOZ_ASSERT(aNode.IsInNativeAnonymousSubtree());
|
MOZ_ASSERT(aNode.IsInNativeAnonymousSubtree());
|
||||||
return *aNode.GetClosestNativeAnonymousSubtreeRootParent();
|
return *aNode.GetClosestNativeAnonymousSubtreeRootParentOrHost();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DumpNode(const nsINode* aNode) {
|
static void DumpNode(const nsINode* aNode) {
|
||||||
|
|
@ -163,8 +163,8 @@ static bool IsVisibleNode(const nsINode* aNode) {
|
||||||
static bool ShouldFindAnonymousContent(const nsIContent& aContent) {
|
static bool ShouldFindAnonymousContent(const nsIContent& aContent) {
|
||||||
MOZ_ASSERT(aContent.IsInNativeAnonymousSubtree());
|
MOZ_ASSERT(aContent.IsInNativeAnonymousSubtree());
|
||||||
|
|
||||||
nsIContent& parent = AnonymousSubtreeRootParent(aContent);
|
nsIContent& host = AnonymousSubtreeRootParentOrHost(aContent);
|
||||||
if (nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(&parent)) {
|
if (nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(&host)) {
|
||||||
if (formControl->IsTextControl(/* aExcludePassword = */ true)) {
|
if (formControl->IsTextControl(/* aExcludePassword = */ true)) {
|
||||||
// Only editable NAC in textfields should be findable. That is, we want to
|
// Only editable NAC in textfields should be findable. That is, we want to
|
||||||
// find "bar" in `<input value="bar">`, but not in `<input
|
// find "bar" in `<input value="bar">`, but not in `<input
|
||||||
|
|
|
||||||
|
|
@ -322,7 +322,7 @@ nsBaseDragService::InvokeDragSession(
|
||||||
mIsDraggingTextInTextControl =
|
mIsDraggingTextInTextControl =
|
||||||
mSourceNode->IsInNativeAnonymousSubtree() &&
|
mSourceNode->IsInNativeAnonymousSubtree() &&
|
||||||
TextControlElement::FromNodeOrNull(
|
TextControlElement::FromNodeOrNull(
|
||||||
mSourceNode->GetClosestNativeAnonymousSubtreeRootParent());
|
mSourceNode->GetClosestNativeAnonymousSubtreeRootParentOrHost());
|
||||||
mContentPolicyType = aContentPolicyType;
|
mContentPolicyType = aContentPolicyType;
|
||||||
mEndDragPoint = LayoutDeviceIntPoint(0, 0);
|
mEndDragPoint = LayoutDeviceIntPoint(0, 0);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue