summaryrefslogtreecommitdiffstats
path: root/dom/base
diff options
context:
space:
mode:
authorMatt A. Tobin <email@mattatobin.com>2020-04-14 21:50:13 -0400
committerMatt A. Tobin <email@mattatobin.com>2020-04-14 21:50:13 -0400
commitbebec8fcb84dba6b684dfe1cc6c8a1e7741df374 (patch)
tree682329072ca4d617d06295c6576ba1c45c3db78e /dom/base
parent5352b69a9286223272c0ed072900b4c78ba2ed7c (diff)
downloadUXP-bebec8fcb84dba6b684dfe1cc6c8a1e7741df374.tar
UXP-bebec8fcb84dba6b684dfe1cc6c8a1e7741df374.tar.gz
UXP-bebec8fcb84dba6b684dfe1cc6c8a1e7741df374.tar.lz
UXP-bebec8fcb84dba6b684dfe1cc6c8a1e7741df374.tar.xz
UXP-bebec8fcb84dba6b684dfe1cc6c8a1e7741df374.zip
Bug 1321284 - Crash in nsCSSFrameConstructor::GetInsertionPrevSibling when trying to reframe native anonymous content
* Make StyleChildrenIterator skip NAC generated by root element primary frame ancestors. * Add nsINode::GetFlattenedTreeParentNodeForStyle. * Add iterator class to find all restyle roots. NOTE: Parts 1, 2, and "4.2" Tag #1375
Diffstat (limited to 'dom/base')
-rw-r--r--dom/base/ChildIterator.cpp16
-rw-r--r--dom/base/ChildIterator.h13
-rw-r--r--dom/base/Element.h2
-rw-r--r--dom/base/ElementInlines.h11
-rw-r--r--dom/base/FragmentOrElement.cpp41
-rw-r--r--dom/base/nsContentUtils.cpp19
-rw-r--r--dom/base/nsContentUtils.h10
-rw-r--r--dom/base/nsIContent.h16
-rw-r--r--dom/base/nsIContentInlines.h41
-rw-r--r--dom/base/nsINode.h8
10 files changed, 143 insertions, 34 deletions
diff --git a/dom/base/ChildIterator.cpp b/dom/base/ChildIterator.cpp
index d8c454ae8..fb07e9a21 100644
--- a/dom/base/ChildIterator.cpp
+++ b/dom/base/ChildIterator.cpp
@@ -383,12 +383,10 @@ AllChildrenIterator::AppendNativeAnonymousChildren()
// The root scroll frame is not the primary frame of the root element.
// Detect and handle this case.
- if (mOriginalContent == mOriginalContent->OwnerDoc()->GetRootElement()) {
- nsIPresShell* presShell = mOriginalContent->OwnerDoc()->GetShell();
- nsIFrame* scrollFrame = presShell ? presShell->GetRootScrollFrame() : nullptr;
- if (scrollFrame) {
- AppendNativeAnonymousChildrenFromFrame(scrollFrame);
- }
+ if (!(mFlags & nsIContent::eSkipDocumentLevelNativeAnonymousContent) &&
+ mOriginalContent == mOriginalContent->OwnerDoc()->GetRootElement()) {
+ nsContentUtils::AppendDocumentLevelNativeAnonymousContentTo(
+ mOriginalContent->OwnerDoc(), mAnonKids);
}
}
@@ -585,12 +583,6 @@ StyleChildrenIterator::IsNeeded(const Element* aElement)
return true;
}
- // The root element has a scroll frame that is not the primary frame, so we
- // need to do special checking for that case.
- if (aElement == aElement->OwnerDoc()->GetRootElement()) {
- return true;
- }
-
return false;
}
diff --git a/dom/base/ChildIterator.h b/dom/base/ChildIterator.h
index ffff8dce5..63425149a 100644
--- a/dom/base/ChildIterator.h
+++ b/dom/base/ChildIterator.h
@@ -256,10 +256,11 @@ private:
/**
* StyleChildrenIterator traverses the children of the element from the
* perspective of the style system, particularly the children we need to traverse
- * during restyle. This is identical to AllChildrenIterator with eAllChildren,
- * _except_ that we detect and skip any native anonymous children that are used
- * to implement pseudo-elements (since the style system needs to cascade those
- * using different algorithms).
+ * during restyle. This is identical to AllChildrenIterator with
+ * (eAllChildren | eSkipDocumentLevelNativeAnonymousContent), _except_ that we
+ * detect and skip any native anonymous children that are used to implement
+ * pseudo-elements (since the style system needs to cascade those using
+ * different algorithms).
*
* Note: it assumes that no mutation of the DOM or frame tree takes place during
* iteration, and will break horribly if that is not true.
@@ -267,7 +268,9 @@ private:
class StyleChildrenIterator : private AllChildrenIterator {
public:
explicit StyleChildrenIterator(const nsIContent* aContent)
- : AllChildrenIterator(aContent, nsIContent::eAllChildren)
+ : AllChildrenIterator(aContent,
+ nsIContent::eAllChildren |
+ nsIContent::eSkipDocumentLevelNativeAnonymousContent)
{
MOZ_COUNT_CTOR(StyleChildrenIterator);
}
diff --git a/dom/base/Element.h b/dom/base/Element.h
index 0104d795c..1b29f0346 100644
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -390,6 +390,8 @@ public:
Directionality GetComputedDirectionality() const;
+ inline Element* GetFlattenedTreeParentElementForStyle() const;
+
/**
* Gets the custom element data used by web components custom element.
* Custom element data is created at the first attempt to enqueue a callback.
diff --git a/dom/base/ElementInlines.h b/dom/base/ElementInlines.h
index c68bd012e..df2cc2e24 100644
--- a/dom/base/ElementInlines.h
+++ b/dom/base/ElementInlines.h
@@ -25,6 +25,17 @@ Element::UnregisterActivityObserver()
OwnerDoc()->UnregisterActivityObserver(this);
}
+inline Element*
+Element::GetFlattenedTreeParentElementForStyle() const
+{
+ nsINode* parentNode = GetFlattenedTreeParentNodeForStyle();
+ if MOZ_LIKELY(parentNode && parentNode->IsElement()) {
+ return parentNode->AsElement();
+ }
+
+ return nullptr;
+}
+
} // namespace dom
} // namespace mozilla
diff --git a/dom/base/FragmentOrElement.cpp b/dom/base/FragmentOrElement.cpp
index ca00a49a5..d7e7a78f4 100644
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -152,7 +152,7 @@ nsIContent::FindFirstNonChromeOnlyAccessContent() const
}
nsINode*
-nsIContent::GetFlattenedTreeParentNodeInternal() const
+nsIContent::GetFlattenedTreeParentNodeInternal(FlattenedParentType aType) const
{
nsINode* parentNode = GetParentNode();
if (!parentNode || !parentNode->IsContent()) {
@@ -161,6 +161,45 @@ nsIContent::GetFlattenedTreeParentNodeInternal() const
}
nsIContent* parent = parentNode->AsContent();
+ if (aType == eForStyle &&
+ IsRootOfNativeAnonymousSubtree() &&
+ OwnerDoc()->GetRootElement() == parent) {
+ // When getting the flattened tree parent for style, we return null
+ // for any "document level" native anonymous content subtree root.
+ // This is NAC generated by an ancestor frame of the document element's
+ // primary frame, and includes scrollbar elements created by the root
+ // scroll frame, and the "custom content container" and accessible caret
+ // generated by the nsCanvasFrame. We distinguish document level NAC
+ // from NAC generated by the root element's primary frame below.
+ nsIFrame* parentFrame = parent->GetPrimaryFrame();
+ if (!parentFrame) {
+ // If the root element has no primary frame, it means it can't have
+ // generated any NAC itself. Thus any NAC we have here must have
+ // been generated by an ancestor frame.
+ //
+ // If we are in here, then either the root element is display:none, or
+ // we are in the middle of constructing the root of the frame tree and
+ // we are trying to eagerly restyle document level NAC in
+ // nsCSSFrameConstructor::GetAnonymousContent before the root
+ // element's frame has been constructed.
+ return nullptr;
+ }
+ nsIAnonymousContentCreator* creator = do_QueryFrame(parentFrame);
+ if (!creator) {
+ // If the root element does have a frame, but does not implement
+ // nsIAnonymousContentCreator, then this must be document level NAC.
+ return nullptr;
+ }
+ AutoTArray<nsIContent*, 8> elements;
+ creator->AppendAnonymousContentTo(elements, 0);
+ if (!elements.Contains(this)) {
+ // If the root element does have a frame, and also does implement
+ // nsIAnonymousContentCreator, but didn't create this node, then
+ // it must be document level NAC.
+ return nullptr;
+ }
+ }
+
if (parent && nsContentUtils::HasDistributedChildren(parent) &&
nsContentUtils::IsInSameAnonymousTree(parent, this)) {
// This node is distributed to insertion points, thus we
diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp
index 4f7b71b19..6a819818c 100644
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -103,6 +103,7 @@
#include "nsHtml5Module.h"
#include "nsHtml5StringParser.h"
#include "nsIAddonPolicyService.h"
+#include "nsIAnonymousContentCreator.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "nsICategoryManager.h"
#include "nsIChannelEventSink.h"
@@ -9837,6 +9838,24 @@ nsContentUtils::AttemptLargeAllocationLoad(nsIHttpChannel* aChannel)
return reloadSucceeded;
}
+/* static */ void
+nsContentUtils::AppendDocumentLevelNativeAnonymousContentTo(
+ nsIDocument* aDocument,
+ nsTArray<nsIContent*>& aElements)
+{
+ MOZ_ASSERT(aDocument);
+
+ // XXXheycam This probably needs to find the nsCanvasFrame's NAC too.
+ if (nsIPresShell* presShell = aDocument->GetShell()) {
+ if (nsIFrame* scrollFrame = presShell->GetRootScrollFrame()) {
+ nsIAnonymousContentCreator* creator = do_QueryFrame(scrollFrame);
+ MOZ_ASSERT(creator,
+ "scroll frame should always implement nsIAnonymousContentCreator");
+ creator->AppendAnonymousContentTo(aElements, 0);
+ }
+ }
+}
+
/* static */ bool
nsContentUtils::IsLocalRefURL(const nsString& aString)
{
diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h
index 64f7485cb..3f1a25504 100644
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -2743,6 +2743,16 @@ public:
static bool AttemptLargeAllocationLoad(nsIHttpChannel* aChannel);
/**
+ * Appends all "document level" native anonymous content subtree roots for
+ * aDocument to aElements. Document level NAC subtrees are those created
+ * by ancestor frames of the document element's primary frame, such as
+ * the scrollbar elements created by the root scroll frame.
+ */
+ static void AppendDocumentLevelNativeAnonymousContentTo(
+ nsIDocument* aDocument,
+ nsTArray<nsIContent*>& aElements);
+
+ /**
* Detect whether a string is a (CSS) local-url.
* https://drafts.csswg.org/css-values/#local-urls
*/
diff --git a/dom/base/nsIContent.h b/dom/base/nsIContent.h
index e179d6ebc..52f2ba5b2 100644
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -144,7 +144,14 @@ public:
* Skip native anonymous content created for placeholder of HTML input,
* used in conjunction with eAllChildren or eAllButXBL.
*/
- eSkipPlaceholderContent = 2
+ eSkipPlaceholderContent = 2,
+
+ /**
+ * Skip native anonymous content created by ancestor frames of the root
+ * element's primary frame, such as scrollbar elements created by the root
+ * scroll frame.
+ */
+ eSkipDocumentLevelNativeAnonymousContent = 4,
};
/**
@@ -723,10 +730,9 @@ public:
*/
inline nsIContent *GetFlattenedTreeParent() const;
- /**
- * Helper method, which we leave public so that it's accessible from nsINode.
- */
- nsINode *GetFlattenedTreeParentNodeInternal() const;
+ // Helper method, which we leave public so that it's accessible from nsINode.
+ enum FlattenedParentType { eNotForStyle, eForStyle };
+ nsINode* GetFlattenedTreeParentNodeInternal(FlattenedParentType aType) const;
/**
* API to check if this is a link that's traversed in response to user input
diff --git a/dom/base/nsIContentInlines.h b/dom/base/nsIContentInlines.h
index 368a0422b..6a82f7f65 100644
--- a/dom/base/nsIContentInlines.h
+++ b/dom/base/nsIContentInlines.h
@@ -33,14 +33,15 @@ inline mozilla::dom::ShadowRoot* nsIContent::GetShadowRoot() const
return AsElement()->FastGetShadowRoot();
}
-inline nsINode* nsINode::GetFlattenedTreeParentNode() const
+template<nsIContent::FlattenedParentType Type>
+static inline nsINode*
+GetFlattenedTreeParentNode(const nsINode* aNode)
{
- nsINode* parent = GetParentNode();
-
+ nsINode* parent = aNode->GetParentNode();
// Try to short-circuit past the complicated and not-exactly-fast logic for
// computing the flattened parent.
//
- // There are three cases where we need might something other than parentNode:
+ // There are four cases where we need might something other than parentNode:
// (1) The node is an explicit child of an XBL-bound element, re-bound
// to an XBL insertion point.
// (2) The node is a top-level element in a shadow tree, whose flattened
@@ -48,18 +49,31 @@ inline nsINode* nsINode::GetFlattenedTreeParentNode() const
// is the shadow root).
// (3) The node is an explicit child of an element with a shadow root,
// re-bound to an insertion point.
- bool needSlowCall = HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) ||
- IsInShadowTree() ||
- (parent && parent->IsContent() &&
- parent->AsContent()->GetShadowRoot());
+ // (4) We want the flattened parent for style, and the node is the root
+ // of a native anonymous content subtree parented to the document's
+ // root element.
+ bool needSlowCall = aNode->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) ||
+ aNode->IsInShadowTree() ||
+ (parent &&
+ parent->IsContent() &&
+ parent->AsContent()->GetShadowRoot()) ||
+ (Type == nsIContent::eForStyle &&
+ aNode->IsContent() &&
+ aNode->AsContent()->IsRootOfNativeAnonymousSubtree() &&
+ aNode->OwnerDoc()->GetRootElement() == parent);
if (MOZ_UNLIKELY(needSlowCall)) {
- MOZ_ASSERT(IsContent());
- return AsContent()->GetFlattenedTreeParentNodeInternal();
+ MOZ_ASSERT(aNode->IsContent());
+ return aNode->AsContent()->GetFlattenedTreeParentNodeInternal(Type);
}
-
return parent;
}
+inline nsINode*
+nsINode::GetFlattenedTreeParentNode() const
+{
+ return ::GetFlattenedTreeParentNode<nsIContent::eNotForStyle>(this);
+}
+
inline nsIContent*
nsIContent::GetFlattenedTreeParent() const
{
@@ -67,5 +81,10 @@ nsIContent::GetFlattenedTreeParent() const
return (parent && parent->IsContent()) ? parent->AsContent() : nullptr;
}
+inline nsINode*
+nsINode::GetFlattenedTreeParentNodeForStyle() const
+{
+ return ::GetFlattenedTreeParentNode<nsIContent::eForStyle>(this);
+}
#endif // nsIContentInlines_h
diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h
index d82f5f899..a0d972f80 100644
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -921,6 +921,14 @@ public:
inline nsINode* GetFlattenedTreeParentNode() const;
/**
+ * Like GetFlattenedTreeParentNode, but returns null for any native
+ * anonymous content that was generated for ancestor frames of the
+ * root element's primary frame, such as scrollbar elements created
+ * by the root scroll frame.
+ */
+ inline nsINode* GetFlattenedTreeParentNodeForStyle() const;
+
+ /**
* Get the parent nsINode for this node if it is an Element.
* @return the parent node
*/