Line data Source code
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 :
20 0 : nsFormControlFrame::nsFormControlFrame(nsStyleContext* aContext,
21 0 : nsIFrame::ClassID aID)
22 0 : : nsAtomicContainerFrame(aContext, aID)
23 : {
24 0 : }
25 :
26 0 : nsFormControlFrame::~nsFormControlFrame()
27 : {
28 0 : }
29 :
30 : void
31 0 : nsFormControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
32 : {
33 : // Unregister the access key registered in reflow
34 0 : nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), false);
35 0 : nsAtomicContainerFrame::DestroyFrom(aDestructRoot);
36 0 : }
37 :
38 0 : NS_QUERYFRAME_HEAD(nsFormControlFrame)
39 0 : NS_QUERYFRAME_ENTRY(nsIFormControlFrame)
40 0 : NS_QUERYFRAME_TAIL_INHERITING(nsAtomicContainerFrame)
41 :
42 : /* virtual */ nscoord
43 0 : nsFormControlFrame::GetMinISize(gfxContext *aRenderingContext)
44 : {
45 : nscoord result;
46 0 : DISPLAY_MIN_WIDTH(this, result);
47 : #if !defined(MOZ_WIDGET_ANDROID)
48 0 : result = StyleDisplay()->mAppearance == NS_THEME_NONE ? 0 : DefaultSize();
49 : #else
50 : result = DefaultSize();
51 : #endif
52 0 : return result;
53 : }
54 :
55 : /* virtual */ nscoord
56 0 : nsFormControlFrame::GetPrefISize(gfxContext *aRenderingContext)
57 : {
58 : nscoord result;
59 0 : DISPLAY_PREF_WIDTH(this, result);
60 : #if !defined(MOZ_WIDGET_ANDROID)
61 0 : result = StyleDisplay()->mAppearance == NS_THEME_NONE ? 0 : DefaultSize();
62 : #else
63 : result = DefaultSize();
64 : #endif
65 0 : return result;
66 : }
67 :
68 : /* virtual */
69 : LogicalSize
70 0 : nsFormControlFrame::ComputeAutoSize(gfxContext* aRC,
71 : WritingMode aWM,
72 : const LogicalSize& aCBSize,
73 : nscoord aAvailableISize,
74 : const LogicalSize& aMargin,
75 : const LogicalSize& aBorder,
76 : const LogicalSize& aPadding,
77 : ComputeSizeFlags aFlags)
78 : {
79 0 : LogicalSize size(aWM, 0, 0);
80 : #if !defined(MOZ_WIDGET_ANDROID)
81 0 : if (StyleDisplay()->mAppearance == NS_THEME_NONE) {
82 0 : return size;
83 : }
84 : #endif
85 : // Note: this call always set the BSize to NS_UNCONSTRAINEDSIZE.
86 : size = nsAtomicContainerFrame::ComputeAutoSize(aRC, aWM, aCBSize,
87 : aAvailableISize, aMargin,
88 0 : aBorder, aPadding, aFlags);
89 0 : size.BSize(aWM) = DefaultSize();
90 0 : return size;
91 : }
92 :
93 : nscoord
94 0 : nsFormControlFrame::GetLogicalBaseline(WritingMode aWritingMode) const
95 : {
96 0 : NS_ASSERTION(!NS_SUBTREE_DIRTY(this),
97 : "frame must not be dirty");
98 :
99 : // NOTE: on Android we use appearance:none by default for checkbox/radio,
100 : // so the different layout for appearance:none we have on other platforms
101 : // doesn't work there. *shrug*
102 : #if !defined(MOZ_WIDGET_ANDROID)
103 : // For appearance:none we use a standard CSS baseline, i.e. synthesized from
104 : // our margin-box.
105 0 : if (StyleDisplay()->mAppearance == NS_THEME_NONE) {
106 0 : return nsAtomicContainerFrame::GetLogicalBaseline(aWritingMode);
107 : }
108 : #endif
109 :
110 : // This is for compatibility with Chrome, Safari and Edge (Dec 2016).
111 : // Treat radio buttons and checkboxes as having an intrinsic baseline
112 : // at the block-end of the control (use the block-end content edge rather
113 : // than the margin edge).
114 : // For "inverted" lines (typically in writing-mode:vertical-lr), use the
115 : // block-start end instead.
116 0 : return aWritingMode.IsLineInverted()
117 0 : ? GetLogicalUsedBorderAndPadding(aWritingMode).BStart(aWritingMode)
118 0 : : BSize(aWritingMode) -
119 0 : GetLogicalUsedBorderAndPadding(aWritingMode).BEnd(aWritingMode);
120 : }
121 :
122 : void
123 0 : nsFormControlFrame::Reflow(nsPresContext* aPresContext,
124 : ReflowOutput& aDesiredSize,
125 : const ReflowInput& aReflowInput,
126 : nsReflowStatus& aStatus)
127 : {
128 0 : MarkInReflow();
129 0 : DO_GLOBAL_REFLOW_COUNT("nsFormControlFrame");
130 0 : DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
131 0 : NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
132 : ("enter nsFormControlFrame::Reflow: aMaxSize=%d,%d",
133 : aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight()));
134 :
135 0 : if (mState & NS_FRAME_FIRST_REFLOW) {
136 0 : RegUnRegAccessKey(static_cast<nsIFrame*>(this), true);
137 : }
138 :
139 0 : aStatus.Reset();
140 0 : aDesiredSize.SetSize(aReflowInput.GetWritingMode(),
141 0 : aReflowInput.ComputedSizeWithBorderPadding());
142 :
143 0 : if (nsLayoutUtils::FontSizeInflationEnabled(aPresContext)) {
144 0 : float inflation = nsLayoutUtils::FontSizeInflationFor(this);
145 0 : aDesiredSize.Width() *= inflation;
146 0 : aDesiredSize.Height() *= inflation;
147 : }
148 :
149 0 : NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
150 : ("exit nsFormControlFrame::Reflow: size=%d,%d",
151 : aDesiredSize.Width(), aDesiredSize.Height()));
152 0 : NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
153 :
154 0 : aDesiredSize.SetOverflowAreasToDesiredBounds();
155 0 : FinishAndStoreOverflow(&aDesiredSize);
156 0 : }
157 :
158 : nsresult
159 6 : nsFormControlFrame::RegUnRegAccessKey(nsIFrame * aFrame, bool aDoReg)
160 : {
161 6 : NS_ENSURE_ARG_POINTER(aFrame);
162 :
163 6 : nsPresContext* presContext = aFrame->PresContext();
164 :
165 6 : NS_ASSERTION(presContext, "aPresContext is NULL in RegUnRegAccessKey!");
166 :
167 12 : nsAutoString accessKey;
168 :
169 6 : nsIContent* content = aFrame->GetContent();
170 6 : content->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, accessKey);
171 6 : if (!accessKey.IsEmpty()) {
172 0 : EventStateManager* stateManager = presContext->EventStateManager();
173 0 : if (aDoReg) {
174 0 : stateManager->RegisterAccessKey(content, (uint32_t)accessKey.First());
175 : } else {
176 0 : stateManager->UnregisterAccessKey(content, (uint32_t)accessKey.First());
177 : }
178 0 : return NS_OK;
179 : }
180 6 : return NS_ERROR_FAILURE;
181 : }
182 :
183 : void
184 0 : nsFormControlFrame::SetFocus(bool aOn, bool aRepaint)
185 : {
186 0 : }
187 :
188 : nsresult
189 0 : nsFormControlFrame::HandleEvent(nsPresContext* aPresContext,
190 : WidgetGUIEvent* aEvent,
191 : nsEventStatus* aEventStatus)
192 : {
193 : // Check for user-input:none style
194 0 : const nsStyleUserInterface* uiStyle = StyleUserInterface();
195 0 : if (uiStyle->mUserInput == StyleUserInput::None ||
196 0 : uiStyle->mUserInput == StyleUserInput::Disabled) {
197 0 : return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
198 : }
199 0 : return NS_OK;
200 : }
201 :
202 : void
203 0 : nsFormControlFrame::GetCurrentCheckState(bool *aState)
204 : {
205 0 : nsCOMPtr<nsIDOMHTMLInputElement> inputElement = do_QueryInterface(mContent);
206 0 : if (inputElement) {
207 0 : inputElement->GetChecked(aState);
208 : }
209 0 : }
210 :
211 : nsresult
212 0 : nsFormControlFrame::SetFormProperty(nsIAtom* aName, const nsAString& aValue)
213 : {
214 0 : return NS_OK;
215 : }
216 :
217 : // static
218 : nsRect
219 0 : nsFormControlFrame::GetUsableScreenRect(nsPresContext* aPresContext)
220 : {
221 0 : nsRect screen;
222 :
223 0 : nsDeviceContext *context = aPresContext->DeviceContext();
224 : int32_t dropdownCanOverlapOSBar =
225 0 : LookAndFeel::GetInt(LookAndFeel::eIntID_MenusCanOverlapOSBar, 0);
226 0 : if ( dropdownCanOverlapOSBar )
227 0 : context->GetRect(screen);
228 : else
229 0 : context->GetClientRect(screen);
230 :
231 0 : return screen;
232 : }
|