1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "nsFormControlFrame.h"
7
8 #include "nsGkAtoms.h"
9 #include "nsLayoutUtils.h"
10 #include "nsIDOMHTMLInputElement.h"
11 #include "mozilla/EventStateManager.h"
12 #include "mozilla/LookAndFeel.h"
13 #include "nsDeviceContext.h"
14 #include "nsIContent.h"
15
16 using namespace mozilla;
17
18 //#define FCF_NOISY
19
nsFormControlFrame(nsStyleContext * aContext)20 nsFormControlFrame::nsFormControlFrame(nsStyleContext* aContext)
21 : nsAtomicContainerFrame(aContext)
22 {
23 }
24
~nsFormControlFrame()25 nsFormControlFrame::~nsFormControlFrame()
26 {
27 }
28
29 nsIAtom*
GetType() const30 nsFormControlFrame::GetType() const
31 {
32 return nsGkAtoms::formControlFrame;
33 }
34
35 void
DestroyFrom(nsIFrame * aDestructRoot)36 nsFormControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
37 {
38 // Unregister the access key registered in reflow
39 nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), false);
40 nsAtomicContainerFrame::DestroyFrom(aDestructRoot);
41 }
42
43 NS_QUERYFRAME_HEAD(nsFormControlFrame)
NS_QUERYFRAME_ENTRY(nsIFormControlFrame)44 NS_QUERYFRAME_ENTRY(nsIFormControlFrame)
45 NS_QUERYFRAME_TAIL_INHERITING(nsAtomicContainerFrame)
46
47 /* virtual */ nscoord
48 nsFormControlFrame::GetMinISize(nsRenderingContext *aRenderingContext)
49 {
50 nscoord result;
51 DISPLAY_MIN_WIDTH(this, result);
52 result = GetIntrinsicISize();
53 return result;
54 }
55
56 /* virtual */ nscoord
GetPrefISize(nsRenderingContext * aRenderingContext)57 nsFormControlFrame::GetPrefISize(nsRenderingContext *aRenderingContext)
58 {
59 nscoord result;
60 DISPLAY_PREF_WIDTH(this, result);
61 result = GetIntrinsicISize();
62 return result;
63 }
64
65 /* virtual */
66 LogicalSize
ComputeAutoSize(nsRenderingContext * aRenderingContext,WritingMode aWM,const LogicalSize & aCBSize,nscoord aAvailableISize,const LogicalSize & aMargin,const LogicalSize & aBorder,const LogicalSize & aPadding,ComputeSizeFlags aFlags)67 nsFormControlFrame::ComputeAutoSize(nsRenderingContext* aRenderingContext,
68 WritingMode aWM,
69 const LogicalSize& aCBSize,
70 nscoord aAvailableISize,
71 const LogicalSize& aMargin,
72 const LogicalSize& aBorder,
73 const LogicalSize& aPadding,
74 ComputeSizeFlags aFlags)
75 {
76 const WritingMode wm = GetWritingMode();
77 LogicalSize result(wm, GetIntrinsicISize(), GetIntrinsicBSize());
78 return result.ConvertTo(aWM, wm);
79 }
80
81 nscoord
GetIntrinsicISize()82 nsFormControlFrame::GetIntrinsicISize()
83 {
84 // Provide a reasonable default for sites that use an "auto" height.
85 // Note that if you change this, you should change the values in forms.css
86 // as well. This is the 13px default width minus the 2px default border.
87 return nsPresContext::CSSPixelsToAppUnits(13 - 2 * 2);
88 }
89
90 nscoord
GetIntrinsicBSize()91 nsFormControlFrame::GetIntrinsicBSize()
92 {
93 // Provide a reasonable default for sites that use an "auto" height.
94 // Note that if you change this, you should change the values in forms.css
95 // as well. This is the 13px default width minus the 2px default border.
96 return nsPresContext::CSSPixelsToAppUnits(13 - 2 * 2);
97 }
98
99 nscoord
GetLogicalBaseline(WritingMode aWritingMode) const100 nsFormControlFrame::GetLogicalBaseline(WritingMode aWritingMode) const
101 {
102 NS_ASSERTION(!NS_SUBTREE_DIRTY(this),
103 "frame must not be dirty");
104 // Treat radio buttons and checkboxes as having an intrinsic baseline
105 // at the block-end of the control (use the block-end content edge rather
106 // than the margin edge).
107 // For "inverted" lines (typically in writing-mode:vertical-lr), use the
108 // block-start end instead.
109 return aWritingMode.IsLineInverted()
110 ? GetLogicalUsedBorderAndPadding(aWritingMode).BStart(aWritingMode)
111 : BSize(aWritingMode) -
112 GetLogicalUsedBorderAndPadding(aWritingMode).BEnd(aWritingMode);
113 }
114
115 void
Reflow(nsPresContext * aPresContext,ReflowOutput & aDesiredSize,const ReflowInput & aReflowInput,nsReflowStatus & aStatus)116 nsFormControlFrame::Reflow(nsPresContext* aPresContext,
117 ReflowOutput& aDesiredSize,
118 const ReflowInput& aReflowInput,
119 nsReflowStatus& aStatus)
120 {
121 MarkInReflow();
122 DO_GLOBAL_REFLOW_COUNT("nsFormControlFrame");
123 DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
124 NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
125 ("enter nsFormControlFrame::Reflow: aMaxSize=%d,%d",
126 aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight()));
127
128 if (mState & NS_FRAME_FIRST_REFLOW) {
129 RegUnRegAccessKey(static_cast<nsIFrame*>(this), true);
130 }
131
132 aStatus = NS_FRAME_COMPLETE;
133 aDesiredSize.SetSize(aReflowInput.GetWritingMode(),
134 aReflowInput.ComputedSizeWithBorderPadding());
135
136 if (nsLayoutUtils::FontSizeInflationEnabled(aPresContext)) {
137 float inflation = nsLayoutUtils::FontSizeInflationFor(this);
138 aDesiredSize.Width() *= inflation;
139 aDesiredSize.Height() *= inflation;
140 }
141
142 NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
143 ("exit nsFormControlFrame::Reflow: size=%d,%d",
144 aDesiredSize.Width(), aDesiredSize.Height()));
145 NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
146
147 aDesiredSize.SetOverflowAreasToDesiredBounds();
148 FinishAndStoreOverflow(&aDesiredSize);
149 }
150
151 nsresult
RegUnRegAccessKey(nsIFrame * aFrame,bool aDoReg)152 nsFormControlFrame::RegUnRegAccessKey(nsIFrame * aFrame, bool aDoReg)
153 {
154 NS_ENSURE_ARG_POINTER(aFrame);
155
156 nsPresContext* presContext = aFrame->PresContext();
157
158 NS_ASSERTION(presContext, "aPresContext is NULL in RegUnRegAccessKey!");
159
160 nsAutoString accessKey;
161
162 nsIContent* content = aFrame->GetContent();
163 content->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, accessKey);
164 if (!accessKey.IsEmpty()) {
165 EventStateManager* stateManager = presContext->EventStateManager();
166 if (aDoReg) {
167 stateManager->RegisterAccessKey(content, (uint32_t)accessKey.First());
168 } else {
169 stateManager->UnregisterAccessKey(content, (uint32_t)accessKey.First());
170 }
171 return NS_OK;
172 }
173 return NS_ERROR_FAILURE;
174 }
175
176 void
SetFocus(bool aOn,bool aRepaint)177 nsFormControlFrame::SetFocus(bool aOn, bool aRepaint)
178 {
179 }
180
181 nsresult
HandleEvent(nsPresContext * aPresContext,WidgetGUIEvent * aEvent,nsEventStatus * aEventStatus)182 nsFormControlFrame::HandleEvent(nsPresContext* aPresContext,
183 WidgetGUIEvent* aEvent,
184 nsEventStatus* aEventStatus)
185 {
186 // Check for user-input:none style
187 const nsStyleUserInterface* uiStyle = StyleUserInterface();
188 if (uiStyle->mUserInput == StyleUserInput::None ||
189 uiStyle->mUserInput == StyleUserInput::Disabled) {
190 return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
191 }
192 return NS_OK;
193 }
194
195 void
GetCurrentCheckState(bool * aState)196 nsFormControlFrame::GetCurrentCheckState(bool *aState)
197 {
198 nsCOMPtr<nsIDOMHTMLInputElement> inputElement = do_QueryInterface(mContent);
199 if (inputElement) {
200 inputElement->GetChecked(aState);
201 }
202 }
203
204 nsresult
SetFormProperty(nsIAtom * aName,const nsAString & aValue)205 nsFormControlFrame::SetFormProperty(nsIAtom* aName, const nsAString& aValue)
206 {
207 return NS_OK;
208 }
209
210 // static
211 nsRect
GetUsableScreenRect(nsPresContext * aPresContext)212 nsFormControlFrame::GetUsableScreenRect(nsPresContext* aPresContext)
213 {
214 nsRect screen;
215
216 nsDeviceContext *context = aPresContext->DeviceContext();
217 int32_t dropdownCanOverlapOSBar =
218 LookAndFeel::GetInt(LookAndFeel::eIntID_MenusCanOverlapOSBar, 0);
219 if ( dropdownCanOverlapOSBar )
220 context->GetRect(screen);
221 else
222 context->GetClientRect(screen);
223
224 return screen;
225 }
226