michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsGfxButtonControlFrame.h" michael@0: #include "nsIFormControl.h" michael@0: #include "nsGkAtoms.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsStyleSet.h" michael@0: #include "nsContentUtils.h" michael@0: // MouseEvent suppression in PP michael@0: #include "nsContentList.h" michael@0: michael@0: #include "nsIDOMHTMLInputElement.h" michael@0: #include "nsTextNode.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: nsGfxButtonControlFrame::nsGfxButtonControlFrame(nsStyleContext* aContext): michael@0: nsHTMLButtonControlFrame(aContext) michael@0: { michael@0: } michael@0: michael@0: nsIFrame* michael@0: NS_NewGfxButtonControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) michael@0: { michael@0: return new (aPresShell) nsGfxButtonControlFrame(aContext); michael@0: } michael@0: michael@0: NS_IMPL_FRAMEARENA_HELPERS(nsGfxButtonControlFrame) michael@0: michael@0: void nsGfxButtonControlFrame::DestroyFrom(nsIFrame* aDestructRoot) michael@0: { michael@0: nsContentUtils::DestroyAnonymousContent(&mTextContent); michael@0: nsHTMLButtonControlFrame::DestroyFrom(aDestructRoot); michael@0: } michael@0: michael@0: nsIAtom* michael@0: nsGfxButtonControlFrame::GetType() const michael@0: { michael@0: return nsGkAtoms::gfxButtonControlFrame; michael@0: } michael@0: michael@0: #ifdef DEBUG_FRAME_DUMP michael@0: nsresult michael@0: nsGfxButtonControlFrame::GetFrameName(nsAString& aResult) const michael@0: { michael@0: return MakeFrameName(NS_LITERAL_STRING("ButtonControl"), aResult); michael@0: } michael@0: #endif michael@0: michael@0: // Create the text content used as label for the button. michael@0: // The frame will be generated by the frame constructor. michael@0: nsresult michael@0: nsGfxButtonControlFrame::CreateAnonymousContent(nsTArray& aElements) michael@0: { michael@0: nsXPIDLString label; michael@0: GetLabel(label); michael@0: michael@0: // Add a child text content node for the label michael@0: mTextContent = new nsTextNode(mContent->NodeInfo()->NodeInfoManager()); michael@0: michael@0: // set the value of the text node and add it to the child list michael@0: mTextContent->SetText(label, false); michael@0: aElements.AppendElement(mTextContent); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: nsGfxButtonControlFrame::AppendAnonymousContentTo(nsBaseContentList& aElements, michael@0: uint32_t aFilter) michael@0: { michael@0: aElements.MaybeAppendElement(mTextContent); michael@0: } michael@0: michael@0: // Create the text content used as label for the button. michael@0: // The frame will be generated by the frame constructor. michael@0: nsIFrame* michael@0: nsGfxButtonControlFrame::CreateFrameFor(nsIContent* aContent) michael@0: { michael@0: nsIFrame * newFrame = nullptr; michael@0: michael@0: if (aContent == mTextContent) { michael@0: nsIFrame * parentFrame = mFrames.FirstChild(); michael@0: michael@0: nsPresContext* presContext = PresContext(); michael@0: nsRefPtr textStyleContext; michael@0: textStyleContext = presContext->StyleSet()-> michael@0: ResolveStyleForNonElement(mStyleContext); michael@0: michael@0: newFrame = NS_NewTextFrame(presContext->PresShell(), textStyleContext); michael@0: // initialize the text frame michael@0: newFrame->Init(mTextContent, parentFrame, nullptr); michael@0: mTextContent->SetPrimaryFrame(newFrame); michael@0: } michael@0: michael@0: return newFrame; michael@0: } michael@0: michael@0: NS_QUERYFRAME_HEAD(nsGfxButtonControlFrame) michael@0: NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator) michael@0: NS_QUERYFRAME_TAIL_INHERITING(nsHTMLButtonControlFrame) michael@0: michael@0: // Initially we hardcoded the default strings here. michael@0: // Next, we used html.css to store the default label for various types michael@0: // of buttons. (nsGfxButtonControlFrame::DoNavQuirksReflow rev 1.20) michael@0: // However, since html.css is not internationalized, we now grab the default michael@0: // label from a string bundle as is done for all other UI strings. michael@0: // See bug 16999 for further details. michael@0: nsresult michael@0: nsGfxButtonControlFrame::GetDefaultLabel(nsXPIDLString& aString) const michael@0: { michael@0: nsCOMPtr form = do_QueryInterface(mContent); michael@0: NS_ENSURE_TRUE(form, NS_ERROR_UNEXPECTED); michael@0: michael@0: int32_t type = form->GetType(); michael@0: const char *prop; michael@0: if (type == NS_FORM_INPUT_RESET) { michael@0: prop = "Reset"; michael@0: } michael@0: else if (type == NS_FORM_INPUT_SUBMIT) { michael@0: prop = "Submit"; michael@0: } michael@0: else { michael@0: aString.Truncate(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: return nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES, michael@0: prop, aString); michael@0: } michael@0: michael@0: nsresult michael@0: nsGfxButtonControlFrame::GetLabel(nsXPIDLString& aLabel) michael@0: { michael@0: // Get the text from the "value" property on our content if there is michael@0: // one; otherwise set it to a default value (localized). michael@0: nsresult rv; michael@0: nsCOMPtr elt = do_QueryInterface(mContent); michael@0: if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::value) && elt) { michael@0: rv = elt->GetValue(aLabel); michael@0: } else { michael@0: // Generate localized label. michael@0: // We can't make any assumption as to what the default would be michael@0: // because the value is localized for non-english platforms, thus michael@0: // it might not be the string "Reset", "Submit Query", or "Browse..." michael@0: rv = GetDefaultLabel(aLabel); michael@0: } michael@0: michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Compress whitespace out of label if needed. michael@0: if (!StyleText()->WhiteSpaceIsSignificant()) { michael@0: aLabel.CompressWhitespace(); michael@0: } else if (aLabel.Length() > 2 && aLabel.First() == ' ' && michael@0: aLabel.CharAt(aLabel.Length() - 1) == ' ') { michael@0: // This is a bit of a hack. The reason this is here is as follows: we now michael@0: // have default padding on our buttons to make them non-ugly. michael@0: // Unfortunately, IE-windows does not have such padding, so people will michael@0: // stick values like " ok " (with the spaces) in the buttons in an attempt michael@0: // to make them look decent. Unfortunately, if they do this the button michael@0: // looks way too big in Mozilla. Worse yet, if they do this _and_ set a michael@0: // fixed width for the button we run into trouble because our focus-rect michael@0: // border/padding and outer border take up 10px of the horizontal button michael@0: // space or so; the result is that the text is misaligned, even with the michael@0: // recentering we do in nsHTMLButtonControlFrame::Reflow. So to solve michael@0: // this, even if the whitespace is significant, single leading and trailing michael@0: // _spaces_ (and not other whitespace) are removed. The proper solution, michael@0: // of course, is to not have the focus rect painting taking up 6px of michael@0: // horizontal space. We should do that instead (via XBL form controls or michael@0: // changing the renderer) and remove this. michael@0: aLabel.Cut(0, 1); michael@0: aLabel.Truncate(aLabel.Length() - 1); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsGfxButtonControlFrame::AttributeChanged(int32_t aNameSpaceID, michael@0: nsIAtom* aAttribute, michael@0: int32_t aModType) michael@0: { michael@0: nsresult rv = NS_OK; michael@0: michael@0: // If the value attribute is set, update the text of the label michael@0: if (nsGkAtoms::value == aAttribute) { michael@0: if (mTextContent && mContent) { michael@0: nsXPIDLString label; michael@0: rv = GetLabel(label); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: mTextContent->SetText(label, true); michael@0: } else { michael@0: rv = NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: // defer to HTMLButtonControlFrame michael@0: } else { michael@0: rv = nsHTMLButtonControlFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: bool michael@0: nsGfxButtonControlFrame::IsLeaf() const michael@0: { michael@0: return true; michael@0: } michael@0: michael@0: nsIFrame* michael@0: nsGfxButtonControlFrame::GetContentInsertionFrame() michael@0: { michael@0: return this; michael@0: } michael@0: michael@0: nsresult michael@0: nsGfxButtonControlFrame::HandleEvent(nsPresContext* aPresContext, michael@0: WidgetGUIEvent* aEvent, michael@0: nsEventStatus* aEventStatus) michael@0: { michael@0: // Override the HandleEvent to prevent the nsFrame::HandleEvent michael@0: // from being called. The nsFrame::HandleEvent causes the button label michael@0: // to be selected (Drawn with an XOR rectangle over the label) michael@0: michael@0: // do we have user-input style? michael@0: const nsStyleUserInterface* uiStyle = StyleUserInterface(); michael@0: if (uiStyle->mUserInput == NS_STYLE_USER_INPUT_NONE || uiStyle->mUserInput == NS_STYLE_USER_INPUT_DISABLED) michael@0: return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus); michael@0: michael@0: return NS_OK; michael@0: }