mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-29 11:57:32 +09:00
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
This commit is contained in:
parent
cb2b45e472
commit
a03838af22
14 changed files with 226 additions and 35 deletions
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2742,6 +2742,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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -920,6 +920,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
|
||||
|
|
|
|||
|
|
@ -66,7 +66,9 @@ public:
|
|||
* Appends "native" anonymous children created by CreateAnonymousContent()
|
||||
* to the given content list depending on the filter.
|
||||
*
|
||||
* @see nsIContent::GetChildren for set of values used for filter.
|
||||
* @see nsIContent::GetChildren for set of values used for filter. Currently,
|
||||
* eSkipPlaceholderContent is the only flag that any implementation of
|
||||
* this method heeds.
|
||||
*/
|
||||
virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
|
||||
uint32_t aFilter) = 0;
|
||||
|
|
|
|||
41
layout/style/DocumentStyleRootIterator.cpp
Normal file
41
layout/style/DocumentStyleRootIterator.cpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "DocumentStyleRootIterator.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
DocumentStyleRootIterator::DocumentStyleRootIterator(nsIDocument* aDocument)
|
||||
: mPosition(0)
|
||||
{
|
||||
MOZ_COUNT_CTOR(DocumentStyleRootIterator);
|
||||
if (Element* root = aDocument->GetRootElement()) {
|
||||
mStyleRoots.AppendElement(root);
|
||||
}
|
||||
nsContentUtils::AppendDocumentLevelNativeAnonymousContentTo(
|
||||
aDocument, mStyleRoots);
|
||||
}
|
||||
|
||||
Element*
|
||||
DocumentStyleRootIterator::GetNextStyleRoot()
|
||||
{
|
||||
for (;;) {
|
||||
if (mPosition >= mStyleRoots.Length()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIContent* next = mStyleRoots[mPosition];
|
||||
++mPosition;
|
||||
|
||||
if (next->IsElement()) {
|
||||
return next->AsElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
37
layout/style/DocumentStyleRootIterator.h
Normal file
37
layout/style/DocumentStyleRootIterator.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef DocumentStyleRootIterator_h
|
||||
#define DocumentStyleRootIterator_h
|
||||
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsIContent;
|
||||
class nsIDocument;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* DocumentStyleRootIterator traverses the roots of the document from the
|
||||
* perspective of the Servo-backed style system. This will first traverse
|
||||
* the document root, followed by any document level native anonymous content.
|
||||
*/
|
||||
class DocumentStyleRootIterator
|
||||
{
|
||||
public:
|
||||
explicit DocumentStyleRootIterator(nsIDocument* aDocument);
|
||||
~DocumentStyleRootIterator() { MOZ_COUNT_DTOR(DocumentStyleRootIterator); }
|
||||
|
||||
Element* GetNextStyleRoot();
|
||||
|
||||
private:
|
||||
AutoTArray<nsIContent*, 8> mStyleRoots;
|
||||
uint32_t mPosition;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // DocumentStyleRootIterator_h
|
||||
|
|
@ -88,6 +88,7 @@ EXPORTS.mozilla += [
|
|||
'CSSVariableValues.h',
|
||||
'DeclarationBlock.h',
|
||||
'DeclarationBlockInlines.h',
|
||||
'DocumentStyleRootIterator.h',
|
||||
'HandleRefPtr.h',
|
||||
'IncrementalClearCOMRuleArray.h',
|
||||
'LayerAnimationInfo.h',
|
||||
|
|
@ -151,6 +152,7 @@ UNIFIED_SOURCES += [
|
|||
'CSSVariableResolver.cpp',
|
||||
'CSSVariableValues.cpp',
|
||||
'Declaration.cpp',
|
||||
'DocumentStyleRootIterator.cpp',
|
||||
'ErrorReporter.cpp',
|
||||
'FontFace.cpp',
|
||||
'FontFaceSet.cpp',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue