fune/layout/forms/nsColorControlFrame.cpp
Bobby Holley 8fb4fb3d6c Bug 1393791 - Stop unbinding native-anonymous content off a script runner. r=emilio
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
2017-08-27 15:29:36 -07:00

140 lines
4.3 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 "nsColorControlFrame.h"
#include "nsContentCreatorFunctions.h"
#include "nsContentList.h"
#include "nsContentUtils.h"
#include "nsCSSPseudoElements.h"
#include "nsFormControlFrame.h"
#include "nsGkAtoms.h"
#include "nsIDOMNode.h"
#include "nsIFormControl.h"
#include "mozilla/StyleSetHandle.h"
#include "mozilla/StyleSetHandleInlines.h"
#include "mozilla/dom/HTMLInputElement.h"
#include "nsIDocument.h"
using mozilla::dom::Element;
using mozilla::dom::HTMLInputElement;
using mozilla::dom::CallerType;
nsColorControlFrame::nsColorControlFrame(nsStyleContext* aContext)
: nsHTMLButtonControlFrame(aContext, kClassID)
{
}
nsIFrame*
NS_NewColorControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
{
return new (aPresShell) nsColorControlFrame(aContext);
}
NS_IMPL_FRAMEARENA_HELPERS(nsColorControlFrame)
NS_QUERYFRAME_HEAD(nsColorControlFrame)
NS_QUERYFRAME_ENTRY(nsColorControlFrame)
NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
NS_QUERYFRAME_TAIL_INHERITING(nsHTMLButtonControlFrame)
void nsColorControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
{
nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), false);
DestroyAnonymousContent(mColorContent.forget());
nsHTMLButtonControlFrame::DestroyFrom(aDestructRoot);
}
#ifdef DEBUG_FRAME_DUMP
nsresult
nsColorControlFrame::GetFrameName(nsAString& aResult) const
{
return MakeFrameName(NS_LITERAL_STRING("ColorControl"), aResult);
}
#endif
// Create the color area for the button.
// The frame will be generated by the frame constructor.
nsresult
nsColorControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
{
nsCOMPtr<nsIDocument> doc = mContent->GetComposedDoc();
mColorContent = doc->CreateHTMLElement(nsGkAtoms::div);
mColorContent->SetPseudoElementType(CSSPseudoElementType::mozColorSwatch);
// Mark the element to be native anonymous before setting any attributes.
mColorContent->SetIsNativeAnonymousRoot();
nsresult rv = UpdateColor();
NS_ENSURE_SUCCESS(rv, rv);
if (!aElements.AppendElement(mColorContent)) {
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
void
nsColorControlFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
uint32_t aFilter)
{
if (mColorContent) {
aElements.AppendElement(mColorContent);
}
}
nsresult
nsColorControlFrame::UpdateColor()
{
// Get the color from the "value" property of our content; it will return the
// default color (through the sanitization algorithm) if there is none.
nsAutoString color;
HTMLInputElement* elt = HTMLInputElement::FromContent(mContent);
elt->GetValue(color, CallerType::System);
MOZ_ASSERT(!color.IsEmpty(),
"Content node's GetValue() should return a valid color string "
"(the default color, in case no valid color is set)");
// Set the background-color style property of the swatch element to this color
return mColorContent->SetAttr(kNameSpaceID_None, nsGkAtoms::style,
NS_LITERAL_STRING("background-color:") + color, true);
}
nsresult
nsColorControlFrame::AttributeChanged(int32_t aNameSpaceID,
nsIAtom* aAttribute,
int32_t aModType)
{
NS_ASSERTION(mColorContent, "The color div must exist");
// If the value attribute is set, update the color box, but only if we're
// still a color control, which might not be the case if the type attribute
// was removed/changed.
nsCOMPtr<nsIFormControl> fctrl = do_QueryInterface(GetContent());
if (fctrl->ControlType() == NS_FORM_INPUT_COLOR &&
aNameSpaceID == kNameSpaceID_None && nsGkAtoms::value == aAttribute) {
UpdateColor();
}
return nsHTMLButtonControlFrame::AttributeChanged(aNameSpaceID, aAttribute,
aModType);
}
nsContainerFrame*
nsColorControlFrame::GetContentInsertionFrame()
{
return this;
}
Element*
nsColorControlFrame::GetPseudoElement(CSSPseudoElementType aType)
{
if (aType == CSSPseudoElementType::mozColorSwatch) {
return mColorContent;
}
return nsContainerFrame::GetPseudoElement(aType);
}