forked from mirrors/gecko-dev
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
140 lines
4.3 KiB
C++
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);
|
|
}
|