/* -*- 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 "nsColorControlFrame.h" #include "nsContentCreatorFunctions.h" #include "nsContentUtils.h" #include "nsCSSPseudoElements.h" #include "nsCheckboxRadioFrame.h" #include "nsGkAtoms.h" #include "nsIFormControl.h" #include "mozilla/PresShell.h" #include "mozilla/dom/HTMLInputElement.h" #include "mozilla/dom/Document.h" using namespace mozilla; using mozilla::dom::CallerType; using mozilla::dom::Document; using mozilla::dom::Element; using mozilla::dom::HTMLInputElement; nsColorControlFrame::nsColorControlFrame(ComputedStyle* aStyle, nsPresContext* aPresContext) : nsHTMLButtonControlFrame(aStyle, aPresContext, kClassID) {} nsIFrame* NS_NewColorControlFrame(PresShell* aPresShell, ComputedStyle* aStyle) { return new (aPresShell) nsColorControlFrame(aStyle, aPresShell->GetPresContext()); } 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, PostDestroyData& aPostDestroyData) { nsCheckboxRadioFrame::RegUnRegAccessKey(static_cast(this), false); aPostDestroyData.AddAnonymousContent(mColorContent.forget()); nsHTMLButtonControlFrame::DestroyFrom(aDestructRoot, aPostDestroyData); } #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& aElements) { RefPtr doc = mContent->GetComposedDoc(); mColorContent = doc->CreateHTMLElement(nsGkAtoms::div); mColorContent->SetPseudoElementType(PseudoStyleType::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& 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 the value is empty. nsAutoString color; HTMLInputElement* elt = HTMLInputElement::FromNode(mContent); elt->GetValue(color, CallerType::System); if (color.IsEmpty()) { // OK, there is one case the color string might be empty -- if our content // is still being created, i.e. if it has mDoneCreating==false. In that // case, we simply do nothing, because we'll be called again with a complete // content node before we ever reflow or paint. Specifically: we can expect // that HTMLInputElement::DoneCreatingElement() will set mDoneCreating to // true (which enables sanitization) and then it'll call SetValueInternal(), // which produces a nonempty color (via sanitization), and then it'll call // this function here, and we'll get the nonempty default color. MOZ_ASSERT(HasAnyStateBits(NS_FRAME_FIRST_REFLOW), "Content node's GetValue() should return a valid color string " "by the time we've been reflowed (the default color, in case " "no valid color is set)"); return NS_OK; } // Set the background-color CSS property of the swatch element to this color. return mColorContent->SetAttr(kNameSpaceID_None, nsGkAtoms::style, NS_LITERAL_STRING("background-color:") + color, /* aNotify */ true); } nsresult nsColorControlFrame::AttributeChanged(int32_t aNameSpaceID, nsAtom* 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 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; }