/src/mozilla-central/layout/forms/nsComboboxControlFrame.h
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 | | #ifndef nsComboboxControlFrame_h___ |
8 | | #define nsComboboxControlFrame_h___ |
9 | | |
10 | | #ifdef DEBUG_evaughan |
11 | | //#define DEBUG_rods |
12 | | #endif |
13 | | |
14 | | #ifdef DEBUG_rods |
15 | | //#define DO_REFLOW_DEBUG |
16 | | //#define DO_REFLOW_COUNTER |
17 | | //#define DO_UNCONSTRAINED_CHECK |
18 | | //#define DO_PIXELS |
19 | | //#define DO_NEW_REFLOW |
20 | | #endif |
21 | | |
22 | | //Mark used to indicate when onchange has been fired for current combobox item |
23 | 0 | #define NS_SKIP_NOTIFY_INDEX -2 |
24 | | |
25 | | #include "mozilla/Attributes.h" |
26 | | #include "nsBlockFrame.h" |
27 | | #include "nsIFormControlFrame.h" |
28 | | #include "nsIComboboxControlFrame.h" |
29 | | #include "nsIAnonymousContentCreator.h" |
30 | | #include "nsISelectControlFrame.h" |
31 | | #include "nsIRollupListener.h" |
32 | | #include "nsIStatefulFrame.h" |
33 | | #include "nsThreadUtils.h" |
34 | | |
35 | | class nsIListControlFrame; |
36 | | class nsComboboxDisplayFrame; |
37 | | class nsIDOMEventListener; |
38 | | class nsIScrollableFrame; |
39 | | class nsTextNode; |
40 | | |
41 | | namespace mozilla { |
42 | | namespace gfx { |
43 | | class DrawTarget; |
44 | | } // namespace gfx |
45 | | } // namespace mozilla |
46 | | |
47 | | class nsComboboxControlFrame final : public nsBlockFrame, |
48 | | public nsIFormControlFrame, |
49 | | public nsIComboboxControlFrame, |
50 | | public nsIAnonymousContentCreator, |
51 | | public nsISelectControlFrame, |
52 | | public nsIRollupListener, |
53 | | public nsIStatefulFrame |
54 | | { |
55 | | typedef mozilla::gfx::DrawTarget DrawTarget; |
56 | | |
57 | | public: |
58 | | friend nsComboboxControlFrame* NS_NewComboboxControlFrame(nsIPresShell* aPresShell, |
59 | | ComputedStyle* aStyle, |
60 | | nsFrameState aFlags); |
61 | | friend class nsComboboxDisplayFrame; |
62 | | |
63 | | explicit nsComboboxControlFrame(ComputedStyle* aStyle); |
64 | | ~nsComboboxControlFrame(); |
65 | | |
66 | | NS_DECL_QUERYFRAME |
67 | | NS_DECL_FRAMEARENA_HELPERS(nsComboboxControlFrame) |
68 | | |
69 | | // nsIAnonymousContentCreator |
70 | | virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override; |
71 | | virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements, |
72 | | uint32_t aFilter) override; |
73 | | |
74 | | nsIContent* GetDisplayNode() const; |
75 | | nsIFrame* CreateFrameForDisplayNode(); |
76 | | |
77 | | #ifdef ACCESSIBILITY |
78 | | virtual mozilla::a11y::AccType AccessibleType() override; |
79 | | #endif |
80 | | |
81 | | virtual nscoord GetMinISize(gfxContext *aRenderingContext) override; |
82 | | |
83 | | virtual nscoord GetPrefISize(gfxContext *aRenderingContext) override; |
84 | | |
85 | | virtual void Reflow(nsPresContext* aCX, |
86 | | ReflowOutput& aDesiredSize, |
87 | | const ReflowInput& aReflowInput, |
88 | | nsReflowStatus& aStatus) override; |
89 | | |
90 | | virtual nsresult HandleEvent(nsPresContext* aPresContext, |
91 | | mozilla::WidgetGUIEvent* aEvent, |
92 | | nsEventStatus* aEventStatus) override; |
93 | | |
94 | | virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, |
95 | | const nsDisplayListSet& aLists) override; |
96 | | |
97 | | void PaintFocus(DrawTarget& aDrawTarget, nsPoint aPt); |
98 | | |
99 | | virtual bool IsFrameOfType(uint32_t aFlags) const override |
100 | 0 | { |
101 | 0 | return nsBlockFrame::IsFrameOfType(aFlags & |
102 | 0 | ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock)); |
103 | 0 | } |
104 | | |
105 | 0 | virtual nsIScrollableFrame* GetScrollTargetFrame() override { |
106 | 0 | return do_QueryFrame(mDropdownFrame); |
107 | 0 | } |
108 | | |
109 | | #ifdef DEBUG_FRAME_DUMP |
110 | | virtual nsresult GetFrameName(nsAString& aResult) const override; |
111 | | #endif |
112 | | virtual void DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData) override; |
113 | | virtual void SetInitialChildList(ChildListID aListID, |
114 | | nsFrameList& aChildList) override; |
115 | | virtual const nsFrameList& GetChildList(ChildListID aListID) const override; |
116 | | virtual void GetChildLists(nsTArray<ChildList>* aLists) const override; |
117 | | |
118 | | virtual nsContainerFrame* GetContentInsertionFrame() override; |
119 | | |
120 | | // Return the dropdown and display frame. |
121 | | void AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult) override; |
122 | | |
123 | | // nsIFormControlFrame |
124 | | virtual nsresult SetFormProperty(nsAtom* aName, const nsAString& aValue) override; |
125 | | /** |
126 | | * Inform the control that it got (or lost) focus. |
127 | | * If it lost focus, the dropdown menu will be rolled up if needed, |
128 | | * and FireOnChange() will be called. |
129 | | * @param aOn true if got focus, false if lost focus. |
130 | | * @param aRepaint if true then force repaint (NOTE: we always force repaint currently) |
131 | | * @note This method might destroy |this|. |
132 | | */ |
133 | | virtual void SetFocus(bool aOn, bool aRepaint) override; |
134 | | |
135 | | //nsIComboboxControlFrame |
136 | 0 | virtual bool IsDroppedDown() override { return mDroppedDown; } |
137 | | /** |
138 | | * @note This method might destroy |this|. |
139 | | */ |
140 | | virtual void ShowDropDown(bool aDoDropDown) override; |
141 | | virtual nsIFrame* GetDropDown() override; |
142 | | virtual void SetDropDown(nsIFrame* aDropDownFrame) override; |
143 | | /** |
144 | | * @note This method might destroy |this|. |
145 | | */ |
146 | | virtual void RollupFromList() override; |
147 | | |
148 | | /** |
149 | | * Return the available space before and after this frame for |
150 | | * placing the drop-down list, and the current 2D translation. |
151 | | * Note that either or both can be less than or equal to zero, |
152 | | * if both are then the drop-down should be closed. |
153 | | */ |
154 | | void GetAvailableDropdownSpace(mozilla::WritingMode aWM, |
155 | | nscoord* aBefore, |
156 | | nscoord* aAfter, |
157 | | mozilla::LogicalPoint* aTranslation); |
158 | | virtual int32_t GetIndexOfDisplayArea() override; |
159 | | /** |
160 | | * @note This method might destroy |this|. |
161 | | */ |
162 | | NS_IMETHOD RedisplaySelectedText() override; |
163 | | virtual int32_t UpdateRecentIndex(int32_t aIndex) override; |
164 | | virtual void OnContentReset() override; |
165 | | |
166 | | |
167 | | bool IsOpenInParentProcess() override |
168 | 0 | { |
169 | 0 | return mIsOpenInParentProcess; |
170 | 0 | } |
171 | | |
172 | | void SetOpenInParentProcess(bool aVal) override |
173 | 0 | { |
174 | 0 | mIsOpenInParentProcess = aVal; |
175 | 0 | } |
176 | | |
177 | | // nsISelectControlFrame |
178 | | NS_IMETHOD AddOption(int32_t index) override; |
179 | | NS_IMETHOD RemoveOption(int32_t index) override; |
180 | | NS_IMETHOD DoneAddingChildren(bool aIsDone) override; |
181 | | NS_IMETHOD OnOptionSelected(int32_t aIndex, bool aSelected) override; |
182 | | NS_IMETHOD OnSetSelectedIndex(int32_t aOldIndex, int32_t aNewIndex) override; |
183 | | |
184 | | //nsIRollupListener |
185 | | /** |
186 | | * Hide the dropdown menu and stop capturing mouse events. |
187 | | * @note This method might destroy |this|. |
188 | | */ |
189 | | virtual bool Rollup(uint32_t aCount, bool aFlush, |
190 | | const nsIntPoint* pos, nsIContent** aLastRolledUp) override; |
191 | | virtual void NotifyGeometryChange() override; |
192 | | |
193 | | /** |
194 | | * A combobox should roll up if a mousewheel event happens outside of |
195 | | * the popup area. |
196 | | */ |
197 | | virtual bool ShouldRollupOnMouseWheelEvent() override |
198 | 0 | { return true; } |
199 | | |
200 | | virtual bool ShouldConsumeOnMouseWheelEvent() override |
201 | 0 | { return false; } |
202 | | |
203 | | /** |
204 | | * A combobox should not roll up if activated by a mouse activate message |
205 | | * (eg. X-mouse). |
206 | | */ |
207 | | virtual bool ShouldRollupOnMouseActivate() override |
208 | 0 | { return false; } |
209 | | |
210 | | virtual uint32_t GetSubmenuWidgetChain(nsTArray<nsIWidget*> *aWidgetChain) override |
211 | 0 | { return 0; } |
212 | | |
213 | | virtual nsIWidget* GetRollupWidget() override; |
214 | | |
215 | | //nsIStatefulFrame |
216 | | mozilla::UniquePtr<mozilla::PresState> SaveState() override; |
217 | | NS_IMETHOD RestoreState(mozilla::PresState* aState) override; |
218 | | NS_IMETHOD GenerateStateKey(nsIContent* aContent, |
219 | | nsIDocument* aDocument, |
220 | | nsACString& aKey) override; |
221 | | |
222 | | static bool ToolkitHasNativePopup(); |
223 | | |
224 | | protected: |
225 | | friend class RedisplayTextEvent; |
226 | | friend class nsAsyncResize; |
227 | | friend class nsResizeDropdownAtFinalPosition; |
228 | | |
229 | | // Utilities |
230 | | void ReflowDropdown(nsPresContext* aPresContext, |
231 | | const ReflowInput& aReflowInput); |
232 | | |
233 | | // Return true if we should render a dropdown button. |
234 | | bool HasDropDownButton() const; |
235 | | |
236 | | enum DropDownPositionState { |
237 | | // can't show the dropdown at its current position |
238 | | eDropDownPositionSuppressed, |
239 | | // a resize reflow is pending, don't show it yet |
240 | | eDropDownPositionPendingResize, |
241 | | // the dropdown has its final size and position and can be displayed here |
242 | | eDropDownPositionFinal |
243 | | }; |
244 | | DropDownPositionState AbsolutelyPositionDropDown(); |
245 | | |
246 | | // Helper for GetMinISize/GetPrefISize |
247 | | nscoord GetIntrinsicISize(gfxContext* aRenderingContext, |
248 | | nsLayoutUtils::IntrinsicISizeType aType); |
249 | | |
250 | | class RedisplayTextEvent : public mozilla::Runnable { |
251 | | public: |
252 | | NS_DECL_NSIRUNNABLE |
253 | | explicit RedisplayTextEvent(nsComboboxControlFrame* c) |
254 | | : mozilla::Runnable("nsComboboxControlFrame::RedisplayTextEvent") |
255 | | , mControlFrame(c) |
256 | 0 | { |
257 | 0 | } |
258 | 0 | void Revoke() { mControlFrame = nullptr; } |
259 | | private: |
260 | | nsComboboxControlFrame *mControlFrame; |
261 | | }; |
262 | | |
263 | | /** |
264 | | * Show or hide the dropdown list. |
265 | | * @note This method might destroy |this|. |
266 | | */ |
267 | | void ShowPopup(bool aShowPopup); |
268 | | |
269 | | /** |
270 | | * Show or hide the dropdown list. |
271 | | * @param aShowList true to show, false to hide the dropdown. |
272 | | * @note This method might destroy |this|. |
273 | | * @return false if this frame is destroyed, true if still alive. |
274 | | */ |
275 | | bool ShowList(bool aShowList); |
276 | | void CheckFireOnChange(); |
277 | | void FireValueChangeEvent(); |
278 | | nsresult RedisplayText(); |
279 | | void HandleRedisplayTextEvent(); |
280 | | void ActuallyDisplayText(bool aNotify); |
281 | | |
282 | | private: |
283 | | // If our total transform to the root frame of the root document is only a 2d |
284 | | // translation then return that translation, otherwise returns (0,0). |
285 | | nsPoint GetCSSTransformTranslation(); |
286 | | |
287 | | protected: |
288 | | nsFrameList mPopupFrames; // additional named child list |
289 | | RefPtr<nsTextNode> mDisplayContent; // Anonymous content used to display the current selection |
290 | | RefPtr<Element> mButtonContent; // Anonymous content for the button |
291 | | nsContainerFrame* mDisplayFrame; // frame to display selection |
292 | | nsIFrame* mButtonFrame; // button frame |
293 | | nsIFrame* mDropdownFrame; // dropdown list frame |
294 | | nsIListControlFrame * mListControlFrame; // ListControl Interface for the dropdown frame |
295 | | |
296 | | // The inline size of our display area. Used by that frame's reflow |
297 | | // to size to the full inline size except the drop-marker. |
298 | | nscoord mDisplayISize; |
299 | | |
300 | | nsRevocableEventPtr<RedisplayTextEvent> mRedisplayTextEvent; |
301 | | |
302 | | int32_t mRecentSelectedIndex; |
303 | | int32_t mDisplayedIndex; |
304 | | nsString mDisplayedOptionTextOrPreview; |
305 | | |
306 | | // make someone to listen to the button. If its programmatically pressed by someone like Accessibility |
307 | | // then open or close the combo box. |
308 | | nsCOMPtr<nsIDOMEventListener> mButtonListener; |
309 | | |
310 | | // The last y-positions used for estimating available space before and |
311 | | // after for the dropdown list in GetAvailableDropdownSpace. These are |
312 | | // reset to nscoord_MIN in AbsolutelyPositionDropDown when placing the |
313 | | // dropdown at its actual position. The GetAvailableDropdownSpace call |
314 | | // from nsListControlFrame::ReflowAsDropdown use the last position. |
315 | | nscoord mLastDropDownBeforeScreenBCoord; |
316 | | nscoord mLastDropDownAfterScreenBCoord; |
317 | | // Current state of the dropdown list, true is dropped down. |
318 | | bool mDroppedDown; |
319 | | // See comment in HandleRedisplayTextEvent(). |
320 | | bool mInRedisplayText; |
321 | | // Acting on ShowDropDown(true) is delayed until we're focused. |
322 | | bool mDelayedShowDropDown; |
323 | | |
324 | | bool mIsOpenInParentProcess; |
325 | | |
326 | | // static class data member for Bug 32920 |
327 | | // only one control can be focused at a time |
328 | | static nsComboboxControlFrame* sFocused; |
329 | | |
330 | | #ifdef DO_REFLOW_COUNTER |
331 | | int32_t mReflowId; |
332 | | #endif |
333 | | }; |
334 | | |
335 | | #endif |