mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-14 22:05:44 +00:00
Bug 1440258: Flag doc level anonymous content instead of guessing. r=bholley
Poking at the frame tree has problems: If we poke in negative (using eSkipNativeAnonymousContent), as we were doing, we mess up the case where we're actually _not_ doc-level, and _not_ ::before or ::after. This can't happen for content documents, but can happen for chrome (since nsDocElementBoxFrame implements nsIAnonymousContentCreator). If we poke in positive, as we used to, you get that right, but mess up the root scrollbar case. Instead, use a node property to mark doc level anon content. This is a case rare enough that it seems worth to not steal a node bit. To recap the failure: * The initial value of -moz-control-character-visiblity is different on beta and nightly. * XUL has a global rule setting -moz-control-character-visibility on the root, to a value so that it's the initial one on nightly, but the non-initial one on beta. * Changes to this property cause a reframe. * Reframes of a nsIAnonymousContentCreator anon content reframe the container. * We were failing to inherit correctly for the nsIAnonymousContentCreator content for the root XUL element on the initial styling, inheriting from the default computed values instead, since we failed to reach the root element's primary frame from GetFlattenedTreeParentForDocumentElementNAC -> AppendDocumentLevelNativeAnonymousContentTo, since the primary frame is set _after_ processing children. This seems somewhat risky to change, and inconsistent with any other stuff the frame constructor does, see bug 973390. * Given that, the next restyle of the root element, in this case caused due to the customizable UI, we _found_ the actual correct parent, recomputed the style, saw that -moz-control-character-visiblity had changed, and reframed. But we were reframing the whole window, not just the NAC, because of the fourth bullet point. Reframing the whole window caused us to lose the popup state (that's bug 1440506). Worse than that is the fact that given we reframe and reconstruct the anonymous countent again, we go back to the initial bogus state, just awaiting for the next restyle to reframe the whole window. I wish there was a bullet-proof way to test it that isn't just counting reframes and relying on which properties reframe or not, but due to the nature of nsIAnonymousContentCreator's NAC, it's not possible in any easy way I can think of. MozReview-Commit-ID: IPYB5trsN8R
This commit is contained in:
parent
022b3fe431
commit
b26f7c3694
@ -180,38 +180,6 @@ nsIContent::GetAssignedSlotByMode() const
|
||||
return slot;
|
||||
}
|
||||
|
||||
nsINode*
|
||||
nsIContent::GetFlattenedTreeParentForDocumentElementNAC() const
|
||||
{
|
||||
MOZ_ASSERT(IsRootOfNativeAnonymousSubtree());
|
||||
MOZ_ASSERT(GetParent());
|
||||
MOZ_ASSERT(GetParent() == OwnerDoc()->GetRootElement());
|
||||
MOZ_ASSERT(!IsGeneratedContentContainerForAfter());
|
||||
MOZ_ASSERT(!IsGeneratedContentContainerForBefore());
|
||||
|
||||
nsIContent* parent = GetParent();
|
||||
AutoTArray<nsIContent*, 8> rootElementNAC;
|
||||
nsContentUtils::AppendNativeAnonymousChildren(
|
||||
parent, rootElementNAC, nsIContent::eSkipDocumentLevelNativeAnonymousContent);
|
||||
const bool isDocLevelNAC = !rootElementNAC.Contains(this);
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
// The code below would be slightly more direct, but it gets the wrong
|
||||
// answer when the root scrollframe is being bootstrapped and we're
|
||||
// trying to style the scrollbars (since GetRootScrollFrame() still returns
|
||||
// null at that point). Verify that the results match otherwise.
|
||||
AutoTArray<nsIContent*, 8> docLevelNAC;
|
||||
nsContentUtils::AppendDocumentLevelNativeAnonymousContentTo(OwnerDoc(), docLevelNAC);
|
||||
nsIPresShell* shell = OwnerDoc()->GetShell();
|
||||
MOZ_ASSERT_IF(shell && shell->GetRootScrollFrame(),
|
||||
isDocLevelNAC == docLevelNAC.Contains(this));
|
||||
}
|
||||
#endif
|
||||
|
||||
return isDocLevelNAC ? OwnerDocAsNode() : parent;
|
||||
}
|
||||
|
||||
nsIContent::IMEState
|
||||
nsIContent::GetDesiredIMEState()
|
||||
{
|
||||
|
@ -10490,6 +10490,9 @@ nsContentUtils::AppendDocumentLevelNativeAnonymousContentTo(
|
||||
nsTArray<nsIContent*>& aElements)
|
||||
{
|
||||
MOZ_ASSERT(aDocument);
|
||||
#ifdef DEBUG
|
||||
size_t oldLength = aElements.Length();
|
||||
#endif
|
||||
|
||||
if (nsIPresShell* presShell = aDocument->GetShell()) {
|
||||
if (nsIFrame* scrollFrame = presShell->GetRootScrollFrame()) {
|
||||
@ -10505,6 +10508,14 @@ nsContentUtils::AppendDocumentLevelNativeAnonymousContentTo(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
for (size_t i = oldLength; i < aElements.Length(); i++) {
|
||||
MOZ_ASSERT(
|
||||
aElements[i]->GetProperty(nsGkAtoms::docLevelNativeAnonymousContent),
|
||||
"Someone here has lied, or missed to flag the node");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2182,7 +2182,8 @@ GK_ATOM(genConInitializerProperty, "QuoteNodeProperty")
|
||||
GK_ATOM(labelMouseDownPtProperty, "LabelMouseDownPtProperty")
|
||||
GK_ATOM(lockedStyleStates, "lockedStyleStates")
|
||||
GK_ATOM(apzCallbackTransform, "apzCallbackTransform")
|
||||
GK_ATOM(restylableAnonymousNode, "restylableAnonymousNode")
|
||||
GK_ATOM(restylableAnonymousNode, "restylableAnonymousNode") // bool
|
||||
GK_ATOM(docLevelNativeAnonymousContent, "docLevelNativeAnonymousContent") // bool
|
||||
GK_ATOM(paintRequestTime, "PaintRequestTime")
|
||||
GK_ATOM(pseudoProperty, "PseudoProperty") // CSSPseudoElementType
|
||||
GK_ATOM(manualNACProperty, "ManualNACProperty") // ManualNAC*
|
||||
|
@ -616,16 +616,6 @@ public:
|
||||
*/
|
||||
inline nsIContent* GetFlattenedTreeParent() const;
|
||||
|
||||
/**
|
||||
* Get the flattened tree parent for NAC holding from the document element,
|
||||
* from the point of view of the style system.
|
||||
*
|
||||
* Document-level anonymous content holds from the document element, even
|
||||
* though they should not be treated as such (they should be parented to the
|
||||
* document instead, and shouldn't inherit from the document element).
|
||||
*/
|
||||
nsINode* GetFlattenedTreeParentForDocumentElementNAC() const;
|
||||
|
||||
/**
|
||||
* API to check if this is a link that's traversed in response to user input
|
||||
* (e.g. a click event). Specializations for HTML/SVG/generic XML allow for
|
||||
|
@ -78,10 +78,10 @@ GetFlattenedTreeParentNode(const nsINode* aNode)
|
||||
|
||||
if (aType == nsINode::eForStyle &&
|
||||
content->IsRootOfNativeAnonymousSubtree() &&
|
||||
parentAsContent == content->OwnerDoc()->GetRootElement() &&
|
||||
!content->IsGeneratedContentContainerForAfter() &&
|
||||
!content->IsGeneratedContentContainerForBefore()) {
|
||||
return content->GetFlattenedTreeParentForDocumentElementNAC();
|
||||
parentAsContent == content->OwnerDoc()->GetRootElement()) {
|
||||
const bool docLevel =
|
||||
content->GetProperty(nsGkAtoms::docLevelNativeAnonymousContent);
|
||||
return docLevel ? content->OwnerDocAsNode() : parent;
|
||||
}
|
||||
|
||||
if (content->IsRootOfAnonymousSubtree()) {
|
||||
|
@ -557,7 +557,7 @@ public:
|
||||
*
|
||||
* For all other cases OwnerDoc and GetOwnerDocument behave identically.
|
||||
*/
|
||||
nsIDocument *OwnerDoc() const
|
||||
nsIDocument* OwnerDoc() const
|
||||
{
|
||||
return mNodeInfo->GetDocument();
|
||||
}
|
||||
@ -566,7 +566,7 @@ public:
|
||||
* Return the "owner document" of this node as an nsINode*. Implemented
|
||||
* in nsIDocument.h.
|
||||
*/
|
||||
nsINode *OwnerDocAsNode() const;
|
||||
inline nsINode* OwnerDocAsNode() const;
|
||||
|
||||
/**
|
||||
* Returns true if the content has an ancestor that is a document.
|
||||
|
@ -93,6 +93,9 @@ nsCanvasFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
|
||||
reinterpret_cast<void*>(true));
|
||||
#endif // DEBUG
|
||||
|
||||
mCustomContentContainer->SetProperty(nsGkAtoms::docLevelNativeAnonymousContent,
|
||||
reinterpret_cast<void*>(true));
|
||||
|
||||
aElements.AppendElement(mCustomContentContainer);
|
||||
|
||||
// Do not create an accessible object for the container.
|
||||
|
@ -4612,12 +4612,11 @@ ScrollFrameHelper::CreateAnonymousContent(
|
||||
}
|
||||
}
|
||||
|
||||
nsNodeInfoManager *nodeInfoManager =
|
||||
presContext->Document()->NodeInfoManager();
|
||||
RefPtr<NodeInfo> nodeInfo;
|
||||
nodeInfo = nodeInfoManager->GetNodeInfo(nsGkAtoms::scrollbar, nullptr,
|
||||
kNameSpaceID_XUL,
|
||||
nsINode::ELEMENT_NODE);
|
||||
nsNodeInfoManager* nodeInfoManager = presContext->Document()->NodeInfoManager();
|
||||
RefPtr<NodeInfo> nodeInfo =
|
||||
nodeInfoManager->GetNodeInfo(nsGkAtoms::scrollbar, nullptr,
|
||||
kNameSpaceID_XUL,
|
||||
nsINode::ELEMENT_NODE);
|
||||
NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
if (canHaveHorizontal) {
|
||||
@ -4636,6 +4635,9 @@ ScrollFrameHelper::CreateAnonymousContent(
|
||||
mHScrollbarContent->SetAttr(kNameSpaceID_None, nsGkAtoms::clickthrough,
|
||||
NS_LITERAL_STRING("always"), false);
|
||||
if (mIsRoot) {
|
||||
mHScrollbarContent->SetProperty(nsGkAtoms::docLevelNativeAnonymousContent,
|
||||
reinterpret_cast<void*>(true));
|
||||
|
||||
mHScrollbarContent->SetAttr(kNameSpaceID_None, nsGkAtoms::root_,
|
||||
NS_LITERAL_STRING("true"), false);
|
||||
}
|
||||
@ -4659,6 +4661,8 @@ ScrollFrameHelper::CreateAnonymousContent(
|
||||
mVScrollbarContent->SetAttr(kNameSpaceID_None, nsGkAtoms::clickthrough,
|
||||
NS_LITERAL_STRING("always"), false);
|
||||
if (mIsRoot) {
|
||||
mVScrollbarContent->SetProperty(nsGkAtoms::docLevelNativeAnonymousContent,
|
||||
reinterpret_cast<void*>(true));
|
||||
mVScrollbarContent->SetAttr(kNameSpaceID_None, nsGkAtoms::root_,
|
||||
NS_LITERAL_STRING("true"), false);
|
||||
}
|
||||
@ -4697,11 +4701,13 @@ ScrollFrameHelper::CreateAnonymousContent(
|
||||
mResizerContent->SetAttr(kNameSpaceID_None, nsGkAtoms::dir, dir, false);
|
||||
|
||||
if (mIsRoot) {
|
||||
mResizerContent->SetProperty(nsGkAtoms::docLevelNativeAnonymousContent,
|
||||
reinterpret_cast<void*>(true));
|
||||
|
||||
Element* browserRoot = GetBrowserRoot(mOuter->GetContent());
|
||||
mCollapsedResizer = !(browserRoot &&
|
||||
browserRoot->HasAttr(kNameSpaceID_None, nsGkAtoms::showresizer));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
mResizerContent->SetAttr(kNameSpaceID_None, nsGkAtoms::element,
|
||||
NS_LITERAL_STRING("_parent"), false);
|
||||
}
|
||||
@ -4718,6 +4724,10 @@ ScrollFrameHelper::CreateAnonymousContent(
|
||||
kNameSpaceID_XUL,
|
||||
nsINode::ELEMENT_NODE);
|
||||
NS_TrustedNewXULElement(getter_AddRefs(mScrollCornerContent), nodeInfo.forget());
|
||||
if (mIsRoot) {
|
||||
mScrollCornerContent->SetProperty(nsGkAtoms::docLevelNativeAnonymousContent,
|
||||
reinterpret_cast<void*>(true));
|
||||
}
|
||||
if (!aElements.AppendElement(mScrollCornerContent))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user