mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-27 20:25:44 +00:00
8fb4fb3d6c
The failure mode in the attached crashtest is an inconsistency in the flattened tree. Specifically, we null out mVideoControls in an nsVideoFrame, but defer the UnbindFromTree call on that NAC element, which measn that its mParent still points to the nsVideoFrame's mContent. Because all this stuff runs off of script runners, and the anonymous content destroyer is not guaranteed to run before other potential script runners, we end up running arbitrary script while the tree mismatch exists. This script calls back into ProcessPendingRestyles, which causes trouble. We could build a separate deferral mechanism, but it's not clear that we actually need to defer the unbind anymore. The deferred unbind was added in bug 489008, which predated a lot of simplifications in layout/dom interaction. MozReview-Commit-ID: 1JYAhiXKVJC
139 lines
3.8 KiB
C++
139 lines
3.8 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* 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 "DetailsFrame.h"
|
|
|
|
#include "mozilla/Attributes.h"
|
|
#include "mozilla/dom/HTMLDetailsElement.h"
|
|
#include "mozilla/dom/HTMLSummaryElement.h"
|
|
#include "nsContentUtils.h"
|
|
#include "nsPlaceholderFrame.h"
|
|
#include "nsTextNode.h"
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::dom;
|
|
|
|
NS_IMPL_FRAMEARENA_HELPERS(DetailsFrame)
|
|
|
|
NS_QUERYFRAME_HEAD(DetailsFrame)
|
|
NS_QUERYFRAME_ENTRY(DetailsFrame)
|
|
NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
|
|
NS_QUERYFRAME_TAIL_INHERITING(nsBlockFrame)
|
|
|
|
nsBlockFrame*
|
|
NS_NewDetailsFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
|
|
{
|
|
return new (aPresShell) DetailsFrame(aContext);
|
|
}
|
|
|
|
namespace mozilla {
|
|
|
|
DetailsFrame::DetailsFrame(nsStyleContext* aContext)
|
|
: nsBlockFrame(aContext, kClassID)
|
|
{
|
|
}
|
|
|
|
DetailsFrame::~DetailsFrame()
|
|
{
|
|
}
|
|
|
|
void
|
|
DetailsFrame::SetInitialChildList(ChildListID aListID, nsFrameList& aChildList)
|
|
{
|
|
#ifdef DEBUG
|
|
if (aListID == kPrincipalList) {
|
|
CheckValidMainSummary(aChildList);
|
|
}
|
|
#endif
|
|
|
|
nsBlockFrame::SetInitialChildList(aListID, aChildList);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
bool
|
|
DetailsFrame::CheckValidMainSummary(const nsFrameList& aFrameList) const
|
|
{
|
|
for (nsIFrame* child : aFrameList) {
|
|
HTMLSummaryElement* summary =
|
|
HTMLSummaryElement::FromContent(child->GetContent());
|
|
|
|
if (child == aFrameList.FirstChild()) {
|
|
if (summary && summary->IsMainSummary()) {
|
|
return true;
|
|
} else if (child->GetContent() == GetContent()) {
|
|
// The child frame's content is the same as our content, which means
|
|
// it's a kind of wrapper frame. Descend into its child list to find
|
|
// main summary.
|
|
if (CheckValidMainSummary(child->PrincipalChildList())) {
|
|
return true;
|
|
}
|
|
}
|
|
} else {
|
|
NS_ASSERTION(!summary || !summary->IsMainSummary(),
|
|
"Rest of the children are either not summary element "
|
|
"or are not the main summary!");
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
void
|
|
DetailsFrame::DestroyFrom(nsIFrame* aDestructRoot)
|
|
{
|
|
DestroyAnonymousContent(mDefaultSummary.forget());
|
|
nsBlockFrame::DestroyFrom(aDestructRoot);
|
|
}
|
|
|
|
nsresult
|
|
DetailsFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
|
|
{
|
|
auto* details = HTMLDetailsElement::FromContent(GetContent());
|
|
if (details->GetFirstSummary()) {
|
|
return NS_OK;
|
|
}
|
|
|
|
// The <details> element lacks any direct <summary> child. Create a default
|
|
// <summary> element as an anonymous content.
|
|
nsNodeInfoManager* nodeInfoManager =
|
|
GetContent()->NodeInfo()->NodeInfoManager();
|
|
|
|
already_AddRefed<NodeInfo> nodeInfo =
|
|
nodeInfoManager->GetNodeInfo(nsGkAtoms::summary, nullptr, kNameSpaceID_XHTML,
|
|
nsIDOMNode::ELEMENT_NODE);
|
|
mDefaultSummary = new HTMLSummaryElement(nodeInfo);
|
|
|
|
nsAutoString defaultSummaryText;
|
|
nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
|
|
"DefaultSummary", defaultSummaryText);
|
|
RefPtr<nsTextNode> description = new nsTextNode(nodeInfoManager);
|
|
description->SetText(defaultSummaryText, false);
|
|
mDefaultSummary->AppendChildTo(description, false);
|
|
|
|
aElements.AppendElement(mDefaultSummary);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
DetailsFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
|
|
uint32_t aFilter)
|
|
{
|
|
if (mDefaultSummary) {
|
|
aElements.AppendElement(mDefaultSummary);
|
|
}
|
|
}
|
|
|
|
bool
|
|
DetailsFrame::HasMainSummaryFrame(nsIFrame* aSummaryFrame)
|
|
{
|
|
nsIFrame* firstChild =
|
|
nsPlaceholderFrame::GetRealFrameFor(mFrames.FirstChild());
|
|
|
|
return aSummaryFrame == firstChild;
|
|
}
|
|
|
|
} // namespace mozilla
|