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