InputButtonControlFrame.cpp (6517B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "ButtonControlFrame.h" 8 #include "mozilla/PresShell.h" 9 #include "mozilla/dom/HTMLInputElement.h" 10 #include "nsContentUtils.h" 11 #include "nsIFormControl.h" 12 #include "nsTextNode.h" 13 14 using namespace mozilla; 15 16 namespace mozilla { 17 18 /* A frame for <input type={button,reset,submit} */ 19 class InputButtonControlFrame final : public ButtonControlFrame { 20 public: 21 InputButtonControlFrame(ComputedStyle* aStyle, nsPresContext* aPc) 22 : ButtonControlFrame(aStyle, aPc, kClassID) {} 23 24 NS_DECL_FRAMEARENA_HELPERS(InputButtonControlFrame) 25 26 #ifdef DEBUG_FRAME_DUMP 27 nsresult GetFrameName(nsAString& aResult) const override { 28 return MakeFrameName(u"InputButtonControl"_ns, aResult); 29 } 30 #endif 31 32 void Destroy(DestroyContext&) override; 33 34 // nsIAnonymousContentCreator 35 nsresult CreateAnonymousContent(nsTArray<ContentInfo>&) override; 36 void AppendAnonymousContentTo(nsTArray<nsIContent*>&, 37 uint32_t aFilter) override; 38 39 protected: 40 nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute, 41 AttrModType aModType) override; 42 void GetDefaultLabel(nsAString&) const; 43 void GetLabel(nsAString& aLabel); 44 void UpdateLabel(); 45 46 RefPtr<nsTextNode> mTextContent; 47 }; 48 49 NS_IMPL_FRAMEARENA_HELPERS(InputButtonControlFrame); 50 51 void InputButtonControlFrame::Destroy(DestroyContext& aContext) { 52 aContext.AddAnonymousContent(mTextContent.forget()); 53 ButtonControlFrame::Destroy(aContext); 54 } 55 56 // Create the text content used as label for the button. 57 // The frame will be generated by the frame constructor. 58 nsresult InputButtonControlFrame::CreateAnonymousContent( 59 nsTArray<ContentInfo>& aElements) { 60 nsAutoString label; 61 GetLabel(label); 62 63 // Add a child text content node for the label 64 mTextContent = new (mContent->NodeInfo()->NodeInfoManager()) 65 nsTextNode(mContent->NodeInfo()->NodeInfoManager()); 66 67 // set the value of the text node and add it to the child list 68 mTextContent->SetText(label, false); 69 aElements.AppendElement(mTextContent); 70 return NS_OK; 71 } 72 73 void InputButtonControlFrame::AppendAnonymousContentTo( 74 nsTArray<nsIContent*>& aElements, uint32_t aFilter) { 75 if (mTextContent) { 76 aElements.AppendElement(mTextContent); 77 } 78 } 79 80 // Initially we hardcoded the default strings here. 81 // Next, we used html.css to store the default label for various types 82 // of buttons. (nsGfxButtonControlFrame::DoNavQuirksReflow rev 1.20) 83 // However, since html.css is not internationalized, we now grab the default 84 // label from a string bundle as is done for all other UI strings. 85 // See bug 16999 for further details. 86 void InputButtonControlFrame::GetDefaultLabel(nsAString& aLabel) const { 87 const auto* form = nsIFormControl::FromNode(mContent); 88 MOZ_ASSERT(form); 89 90 auto type = form->ControlType(); 91 nsCString prop; 92 if (type == FormControlType::InputReset) { 93 prop.AssignLiteral("Reset"); 94 } else if (type == FormControlType::InputSubmit) { 95 prop.AssignLiteral("Submit"); 96 } else { 97 aLabel.Truncate(); 98 return; 99 } 100 101 if (NS_FAILED(nsContentUtils::GetMaybeLocalizedString( 102 nsContentUtils::eFORMS_PROPERTIES, prop.get(), mContent->OwnerDoc(), 103 aLabel))) { 104 // Use the non-localized version. 105 CopyUTF8toUTF16(prop, aLabel); 106 } 107 } 108 109 void InputButtonControlFrame::GetLabel(nsAString& aLabel) { 110 // Get the text from the "value" property on our content if there is 111 // one; otherwise set it to a default value (localized). 112 auto* elt = dom::HTMLInputElement::FromNode(mContent); 113 if (elt && elt->HasAttr(nsGkAtoms::value)) { 114 elt->GetValue(aLabel, dom::CallerType::System); 115 } else { 116 // Generate localized label. 117 // We can't make any assumption as to what the default would be 118 // because the value is localized for non-english platforms, thus 119 // it might not be the string "Reset", "Submit Query", or "Browse..." 120 GetDefaultLabel(aLabel); 121 } 122 123 // Compress whitespace out of label if needed. 124 if (!StyleText()->WhiteSpaceIsSignificant()) { 125 aLabel.CompressWhitespace(); 126 } else if (aLabel.Length() > 2 && aLabel.First() == ' ' && 127 aLabel.CharAt(aLabel.Length() - 1) == ' ') { 128 // This is a bit of a hack. The reason this is here is as follows: we now 129 // have default padding on our buttons to make them non-ugly. 130 // Unfortunately, IE-windows does not have such padding, so people will 131 // stick values like " ok " (with the spaces) in the buttons in an attempt 132 // to make them look decent. Unfortunately, if they do this the button 133 // looks way too big in Mozilla. Worse yet, if they do this _and_ set a 134 // fixed width for the button we run into trouble because our focus-rect 135 // border/padding and outer border take up 10px of the horizontal button 136 // space or so; the result is that the text is misaligned. So to solve 137 // this, even if the whitespace is significant, single leading and trailing 138 // _spaces_ (and not other whitespace) are removed. The proper solution, 139 // of course, is to not have the focus rect painting taking up 6px of 140 // horizontal space. We should do that instead (changing the renderer) and 141 // remove this. 142 // 143 // TODO(emilio): We should be able to remove this now, we no longer have 144 // inner focus rects. 145 aLabel.Cut(0, 1); 146 aLabel.Truncate(aLabel.Length() - 1); 147 } 148 } 149 150 void InputButtonControlFrame::UpdateLabel() { 151 if (!mTextContent) { 152 return; 153 } 154 nsAutoString label; 155 GetLabel(label); 156 mTextContent->SetText(label, true); 157 } 158 159 nsresult InputButtonControlFrame::AttributeChanged(int32_t aNameSpaceID, 160 nsAtom* aAttribute, 161 AttrModType aModType) { 162 // If the value attribute is set, update the text of the label 163 if (nsGkAtoms::value == aAttribute) { 164 UpdateLabel(); 165 } 166 return nsBlockFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType); 167 } 168 169 } // namespace mozilla 170 171 nsIFrame* NS_NewInputButtonControlFrame(PresShell* aPresShell, 172 ComputedStyle* aStyle) { 173 return new (aPresShell) 174 InputButtonControlFrame(aStyle, aPresShell->GetPresContext()); 175 }