/src/mozilla-central/layout/forms/nsCheckboxRadioFrame.cpp
Line | Count | Source (jump to first uncovered line) |
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 "nsCheckboxRadioFrame.h" |
8 | | |
9 | | #include "nsGkAtoms.h" |
10 | | #include "nsLayoutUtils.h" |
11 | | #include "mozilla/dom/HTMLInputElement.h" |
12 | | #include "mozilla/EventStateManager.h" |
13 | | #include "mozilla/LookAndFeel.h" |
14 | | #include "nsDeviceContext.h" |
15 | | #include "nsIContent.h" |
16 | | #include "nsStyleConsts.h" |
17 | | |
18 | | using namespace mozilla; |
19 | | using mozilla::dom::HTMLInputElement; |
20 | | |
21 | | //#define FCF_NOISY |
22 | | |
23 | | nsCheckboxRadioFrame* |
24 | | NS_NewCheckboxRadioFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle) |
25 | 0 | { |
26 | 0 | return new (aPresShell) nsCheckboxRadioFrame(aStyle); |
27 | 0 | } |
28 | | |
29 | | nsCheckboxRadioFrame::nsCheckboxRadioFrame(ComputedStyle* aStyle) |
30 | | : nsAtomicContainerFrame(aStyle, kClassID) |
31 | 0 | { |
32 | 0 | } |
33 | | |
34 | | nsCheckboxRadioFrame::~nsCheckboxRadioFrame() |
35 | 0 | { |
36 | 0 | } |
37 | | |
38 | | void |
39 | | nsCheckboxRadioFrame::DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData) |
40 | 0 | { |
41 | 0 | // Unregister the access key registered in reflow |
42 | 0 | nsCheckboxRadioFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), false); |
43 | 0 | nsAtomicContainerFrame::DestroyFrom(aDestructRoot, aPostDestroyData); |
44 | 0 | } |
45 | | |
46 | | NS_IMPL_FRAMEARENA_HELPERS(nsCheckboxRadioFrame) |
47 | | |
48 | 0 | NS_QUERYFRAME_HEAD(nsCheckboxRadioFrame) |
49 | 0 | NS_QUERYFRAME_ENTRY(nsIFormControlFrame) |
50 | 0 | NS_QUERYFRAME_TAIL_INHERITING(nsAtomicContainerFrame) |
51 | | |
52 | | /* virtual */ nscoord |
53 | | nsCheckboxRadioFrame::GetMinISize(gfxContext *aRenderingContext) |
54 | 0 | { |
55 | 0 | nscoord result; |
56 | 0 | DISPLAY_MIN_INLINE_SIZE(this, result); |
57 | 0 | result = StyleDisplay()->HasAppearance() ? DefaultSize() : 0; |
58 | 0 | return result; |
59 | 0 | } |
60 | | |
61 | | /* virtual */ nscoord |
62 | | nsCheckboxRadioFrame::GetPrefISize(gfxContext* aRenderingContext) |
63 | 0 | { |
64 | 0 | nscoord result; |
65 | 0 | DISPLAY_PREF_INLINE_SIZE(this, result); |
66 | 0 | result = StyleDisplay()->HasAppearance() ? DefaultSize() : 0; |
67 | 0 | return result; |
68 | 0 | } |
69 | | |
70 | | /* virtual */ |
71 | | LogicalSize |
72 | | nsCheckboxRadioFrame::ComputeAutoSize(gfxContext* aRC, |
73 | | WritingMode aWM, |
74 | | const LogicalSize& aCBSize, |
75 | | nscoord aAvailableISize, |
76 | | const LogicalSize& aMargin, |
77 | | const LogicalSize& aBorder, |
78 | | const LogicalSize& aPadding, |
79 | | ComputeSizeFlags aFlags) |
80 | 0 | { |
81 | 0 | LogicalSize size(aWM, 0, 0); |
82 | 0 | if (!StyleDisplay()->HasAppearance()) { |
83 | 0 | return size; |
84 | 0 | } |
85 | 0 | |
86 | 0 | // Note: this call always set the BSize to NS_UNCONSTRAINEDSIZE. |
87 | 0 | size = nsAtomicContainerFrame::ComputeAutoSize(aRC, aWM, aCBSize, |
88 | 0 | aAvailableISize, aMargin, |
89 | 0 | aBorder, aPadding, aFlags); |
90 | 0 | size.BSize(aWM) = DefaultSize(); |
91 | 0 | return size; |
92 | 0 | } |
93 | | |
94 | | nscoord |
95 | | nsCheckboxRadioFrame::GetLogicalBaseline(WritingMode aWritingMode) const |
96 | 0 | { |
97 | 0 | NS_ASSERTION(!NS_SUBTREE_DIRTY(this), |
98 | 0 | "frame must not be dirty"); |
99 | 0 |
|
100 | 0 | // For appearance:none we use a standard CSS baseline, i.e. synthesized from |
101 | 0 | // our margin-box. |
102 | 0 | if (!StyleDisplay()->HasAppearance()) { |
103 | 0 | return nsAtomicContainerFrame::GetLogicalBaseline(aWritingMode); |
104 | 0 | } |
105 | 0 | |
106 | 0 | // This is for compatibility with Chrome, Safari and Edge (Dec 2016). |
107 | 0 | // Treat radio buttons and checkboxes as having an intrinsic baseline |
108 | 0 | // at the block-end of the control (use the block-end content edge rather |
109 | 0 | // than the margin edge). |
110 | 0 | // For "inverted" lines (typically in writing-mode:vertical-lr), use the |
111 | 0 | // block-start end instead. |
112 | 0 | return aWritingMode.IsLineInverted() |
113 | 0 | ? GetLogicalUsedBorderAndPadding(aWritingMode).BStart(aWritingMode) |
114 | 0 | : BSize(aWritingMode) - |
115 | 0 | GetLogicalUsedBorderAndPadding(aWritingMode).BEnd(aWritingMode); |
116 | 0 | } |
117 | | |
118 | | void |
119 | | nsCheckboxRadioFrame::Reflow(nsPresContext* aPresContext, |
120 | | ReflowOutput& aDesiredSize, |
121 | | const ReflowInput& aReflowInput, |
122 | | nsReflowStatus& aStatus) |
123 | 0 | { |
124 | 0 | MarkInReflow(); |
125 | 0 | DO_GLOBAL_REFLOW_COUNT("nsCheckboxRadioFrame"); |
126 | 0 | DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus); |
127 | 0 | MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!"); |
128 | 0 | NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, |
129 | 0 | ("enter nsCheckboxRadioFrame::Reflow: aMaxSize=%d,%d", |
130 | 0 | aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight())); |
131 | 0 |
|
132 | 0 | if (mState & NS_FRAME_FIRST_REFLOW) { |
133 | 0 | RegUnRegAccessKey(static_cast<nsIFrame*>(this), true); |
134 | 0 | } |
135 | 0 |
|
136 | 0 | aDesiredSize.SetSize(aReflowInput.GetWritingMode(), |
137 | 0 | aReflowInput.ComputedSizeWithBorderPadding()); |
138 | 0 |
|
139 | 0 | if (nsLayoutUtils::FontSizeInflationEnabled(aPresContext)) { |
140 | 0 | float inflation = nsLayoutUtils::FontSizeInflationFor(this); |
141 | 0 | aDesiredSize.Width() *= inflation; |
142 | 0 | aDesiredSize.Height() *= inflation; |
143 | 0 | } |
144 | 0 |
|
145 | 0 | NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, |
146 | 0 | ("exit nsCheckboxRadioFrame::Reflow: size=%d,%d", |
147 | 0 | aDesiredSize.Width(), aDesiredSize.Height())); |
148 | 0 | NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize); |
149 | 0 |
|
150 | 0 | aDesiredSize.SetOverflowAreasToDesiredBounds(); |
151 | 0 | FinishAndStoreOverflow(&aDesiredSize); |
152 | 0 | } |
153 | | |
154 | | nsresult |
155 | | nsCheckboxRadioFrame::RegUnRegAccessKey(nsIFrame* aFrame, bool aDoReg) |
156 | 0 | { |
157 | 0 | NS_ENSURE_ARG_POINTER(aFrame); |
158 | 0 |
|
159 | 0 | nsPresContext* presContext = aFrame->PresContext(); |
160 | 0 |
|
161 | 0 | NS_ASSERTION(presContext, "aPresContext is NULL in RegUnRegAccessKey!"); |
162 | 0 |
|
163 | 0 | nsAutoString accessKey; |
164 | 0 |
|
165 | 0 | Element* content = aFrame->GetContent()->AsElement(); |
166 | 0 | content->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, accessKey); |
167 | 0 | if (!accessKey.IsEmpty()) { |
168 | 0 | EventStateManager* stateManager = presContext->EventStateManager(); |
169 | 0 | if (aDoReg) { |
170 | 0 | stateManager->RegisterAccessKey(content, (uint32_t)accessKey.First()); |
171 | 0 | } else { |
172 | 0 | stateManager->UnregisterAccessKey(content, (uint32_t)accessKey.First()); |
173 | 0 | } |
174 | 0 | return NS_OK; |
175 | 0 | } |
176 | 0 | return NS_ERROR_FAILURE; |
177 | 0 | } |
178 | | |
179 | | void |
180 | | nsCheckboxRadioFrame::SetFocus(bool aOn, bool aRepaint) |
181 | 0 | { |
182 | 0 | } |
183 | | |
184 | | nsresult |
185 | | nsCheckboxRadioFrame::HandleEvent(nsPresContext* aPresContext, |
186 | | WidgetGUIEvent* aEvent, |
187 | | nsEventStatus* aEventStatus) |
188 | 0 | { |
189 | 0 | // Check for disabled content so that selection works properly (?). |
190 | 0 | if (IsContentDisabled()) { |
191 | 0 | return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus); |
192 | 0 | } |
193 | 0 | return NS_OK; |
194 | 0 | } |
195 | | |
196 | | void |
197 | | nsCheckboxRadioFrame::GetCurrentCheckState(bool* aState) |
198 | 0 | { |
199 | 0 | HTMLInputElement* inputElement = HTMLInputElement::FromNode(mContent); |
200 | 0 | if (inputElement) { |
201 | 0 | *aState = inputElement->Checked(); |
202 | 0 | } |
203 | 0 | } |
204 | | |
205 | | nsresult |
206 | | nsCheckboxRadioFrame::SetFormProperty(nsAtom* aName, const nsAString& aValue) |
207 | 0 | { |
208 | 0 | return NS_OK; |
209 | 0 | } |
210 | | |
211 | | // static |
212 | | nsRect |
213 | | nsCheckboxRadioFrame::GetUsableScreenRect(nsPresContext* aPresContext) |
214 | 0 | { |
215 | 0 | nsRect screen; |
216 | 0 |
|
217 | 0 | nsDeviceContext *context = aPresContext->DeviceContext(); |
218 | 0 | int32_t dropdownCanOverlapOSBar = |
219 | 0 | LookAndFeel::GetInt(LookAndFeel::eIntID_MenusCanOverlapOSBar, 0); |
220 | 0 | if ( dropdownCanOverlapOSBar ) |
221 | 0 | context->GetRect(screen); |
222 | 0 | else |
223 | 0 | context->GetClientRect(screen); |
224 | 0 |
|
225 | 0 | return screen; |
226 | 0 | } |