Bug 1753131 - Dispatch devicechange events even without an actively capturing MediaSt...
[gecko.git] / layout / forms / nsListControlFrame.h
blob246b81260a3cf4fdfee1429f9901511c220d763f
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 #ifndef nsListControlFrame_h___
7 #define nsListControlFrame_h___
9 #ifdef DEBUG_evaughan
10 //#define DEBUG_rods
11 #endif
13 #ifdef DEBUG_rods
14 //#define DO_REFLOW_DEBUG
15 //#define DO_REFLOW_COUNTER
16 //#define DO_UNCONSTRAINED_CHECK
17 //#define DO_PIXELS
18 #endif
20 #include "mozilla/Attributes.h"
21 #include "mozilla/StaticPtr.h"
22 #include "nsGfxScrollFrame.h"
23 #include "nsIFormControlFrame.h"
24 #include "nsISelectControlFrame.h"
25 #include "nsSelectsAreaFrame.h"
27 class nsComboboxControlFrame;
28 class nsPresContext;
30 namespace mozilla {
31 class PresShell;
32 class HTMLSelectEventListener;
34 namespace dom {
35 class Event;
36 class HTMLOptionElement;
37 class HTMLSelectElement;
38 class HTMLOptionsCollection;
39 } // namespace dom
40 } // namespace mozilla
42 /**
43 * Frame-based listbox.
46 class nsListControlFrame final : public nsHTMLScrollFrame,
47 public nsIFormControlFrame,
48 public nsISelectControlFrame {
49 public:
50 typedef mozilla::dom::HTMLOptionElement HTMLOptionElement;
52 friend nsListControlFrame* NS_NewListControlFrame(
53 mozilla::PresShell* aPresShell, ComputedStyle* aStyle);
55 NS_DECL_QUERYFRAME
56 NS_DECL_FRAMEARENA_HELPERS(nsListControlFrame)
58 // nsIFrame
59 nsresult HandleEvent(nsPresContext* aPresContext,
60 mozilla::WidgetGUIEvent* aEvent,
61 nsEventStatus* aEventStatus) final;
63 void SetInitialChildList(ChildListID aListID, nsFrameList& aChildList) final;
65 nscoord GetPrefISize(gfxContext* aRenderingContext) final;
66 nscoord GetMinISize(gfxContext* aRenderingContext) final;
68 void Reflow(nsPresContext* aCX, ReflowOutput& aDesiredSize,
69 const ReflowInput& aReflowInput, nsReflowStatus& aStatus) final;
71 void Init(nsIContent* aContent, nsContainerFrame* aParent,
72 nsIFrame* aPrevInFlow) final;
74 MOZ_CAN_RUN_SCRIPT_BOUNDARY
75 void DidReflow(nsPresContext* aPresContext,
76 const ReflowInput* aReflowInput) final;
77 void DestroyFrom(nsIFrame* aDestructRoot,
78 PostDestroyData& aPostDestroyData) final;
80 void BuildDisplayList(nsDisplayListBuilder* aBuilder,
81 const nsDisplayListSet& aLists) final;
83 nsContainerFrame* GetContentInsertionFrame() final;
85 int32_t GetEndSelectionIndex() const { return mEndSelectionIndex; }
87 mozilla::dom::HTMLOptionElement* GetCurrentOption() const;
89 bool IsFrameOfType(uint32_t aFlags) const final {
90 return nsHTMLScrollFrame::IsFrameOfType(
91 aFlags & ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
94 #ifdef DEBUG_FRAME_DUMP
95 nsresult GetFrameName(nsAString& aResult) const final;
96 #endif
98 // nsIFormControlFrame
99 nsresult SetFormProperty(nsAtom* aName, const nsAString& aValue) final;
100 MOZ_CAN_RUN_SCRIPT_BOUNDARY
101 void SetFocus(bool aOn = true, bool aRepaint = false) final;
103 mozilla::ScrollStyles GetScrollStyles() const final;
104 bool ShouldPropagateComputedBSizeToScrolledContent() const final;
106 // for accessibility purposes
107 #ifdef ACCESSIBILITY
108 mozilla::a11y::AccType AccessibleType() final;
109 #endif
111 int32_t GetSelectedIndex();
114 * Gets the text of the currently selected item.
115 * If the there are zero items then an empty string is returned
116 * If there is nothing selected, then the 0th item's text is returned.
118 void GetOptionText(uint32_t aIndex, nsAString& aStr);
120 void CaptureMouseEvents(bool aGrabMouseEvents);
121 nscoord GetBSizeOfARow();
122 uint32_t GetNumberOfOptions();
124 MOZ_CAN_RUN_SCRIPT_BOUNDARY void OnContentReset();
126 // nsISelectControlFrame
127 NS_IMETHOD AddOption(int32_t index) final;
128 NS_IMETHOD RemoveOption(int32_t index) final;
129 MOZ_CAN_RUN_SCRIPT_BOUNDARY
130 NS_IMETHOD DoneAddingChildren(bool aIsDone) final;
133 * Gets the content (an option) by index and then set it as
134 * being selected or not selected.
136 MOZ_CAN_RUN_SCRIPT_BOUNDARY
137 NS_IMETHOD OnOptionSelected(int32_t aIndex, bool aSelected) final;
138 MOZ_CAN_RUN_SCRIPT_BOUNDARY
139 NS_IMETHOD_(void)
140 OnSetSelectedIndex(int32_t aOldIndex, int32_t aNewIndex) final;
143 * Mouse event listeners.
144 * @note These methods might destroy the frame, pres shell and other objects.
146 MOZ_CAN_RUN_SCRIPT
147 nsresult HandleLeftButtonMouseDown(mozilla::dom::Event* aMouseEvent);
148 MOZ_CAN_RUN_SCRIPT
149 nsresult HandleLeftButtonMouseUp(mozilla::dom::Event* aMouseEvent);
150 MOZ_CAN_RUN_SCRIPT
151 nsresult DragMove(mozilla::dom::Event* aMouseEvent);
152 MOZ_CAN_RUN_SCRIPT
154 MOZ_CAN_RUN_SCRIPT
155 bool PerformSelection(int32_t aClickedIndex, bool aIsShift, bool aIsControl);
156 MOZ_CAN_RUN_SCRIPT
157 void UpdateSelectionAfterKeyEvent(int32_t aNewIndex, uint32_t aCharCode,
158 bool aIsShift, bool aIsControlOrMeta,
159 bool aIsControlSelectMode);
162 * Returns the options collection for mContent, if any.
164 mozilla::dom::HTMLOptionsCollection* GetOptions() const;
166 * Returns the HTMLOptionElement for a given index in mContent's collection.
168 HTMLOptionElement* GetOption(uint32_t aIndex) const;
170 // Helper
171 bool IsFocused() { return this == mFocused; }
174 * Function to paint the focus rect when our nsSelectsAreaFrame is painting.
175 * @param aPt the offset of this frame, relative to the rendering reference
176 * frame
178 void PaintFocus(mozilla::gfx::DrawTarget* aDrawTarget, nsPoint aPt);
181 * If this frame IsFocused(), invalidates an area that includes anything
182 * that PaintFocus will or could have painted --- basically the whole
183 * GetOptionsContainer, plus some extra stuff if there are no options. This
184 * must be called every time mEndSelectionIndex changes.
186 void InvalidateFocus();
189 * Function to calculate the block size of a row, for use with the
190 * "size" attribute.
191 * Can't be const because GetNumberOfOptions() isn't const.
193 nscoord CalcBSizeOfARow();
196 * Function to ask whether we're currently in what might be the
197 * first pass of a two-pass reflow.
199 bool MightNeedSecondPass() const { return mMightNeedSecondPass; }
201 void SetSuppressScrollbarUpdate(bool aSuppress) {
202 nsHTMLScrollFrame::SetSuppressScrollbarUpdate(aSuppress);
206 * Return the number of displayed rows in the list.
208 uint32_t GetNumDisplayRows() const { return mNumDisplayRows; }
210 #ifdef ACCESSIBILITY
212 * Post a custom DOM event for the change, so that accessibility can
213 * fire a native focus event for accessibility
214 * (Some 3rd party products need to track our focus)
216 void FireMenuItemActiveEvent(
217 nsIContent* aPreviousOption); // Inform assistive tech what got focused
218 #endif
220 protected:
222 * Updates the selected text in a combobox and then calls FireOnChange().
223 * @note This method might destroy the frame, pres shell and other objects.
224 * Returns false if calling it destroyed |this|.
226 MOZ_CAN_RUN_SCRIPT
227 bool UpdateSelection();
230 * Returns whether mContent supports multiple selection.
232 bool GetMultiple() const {
233 return mContent->AsElement()->HasAttr(kNameSpaceID_None,
234 nsGkAtoms::multiple);
237 mozilla::dom::HTMLSelectElement& Select() const;
240 * @return true if the <option> at aIndex is selectable by the user.
242 bool IsOptionInteractivelySelectable(int32_t aIndex) const;
244 * @return true if aOption in aSelect is selectable by the user.
246 static bool IsOptionInteractivelySelectable(
247 mozilla::dom::HTMLSelectElement* aSelect,
248 mozilla::dom::HTMLOptionElement* aOption);
250 MOZ_CAN_RUN_SCRIPT void ScrollToFrame(HTMLOptionElement& aOptElement);
252 MOZ_CAN_RUN_SCRIPT void ScrollToIndex(int32_t anIndex);
255 * Resets the select back to it's original default values;
256 * those values as determined by the original HTML
258 MOZ_CAN_RUN_SCRIPT void ResetList(bool aAllowScrolling);
260 explicit nsListControlFrame(ComputedStyle* aStyle,
261 nsPresContext* aPresContext);
262 virtual ~nsListControlFrame();
265 * Sets the mSelectedIndex and mOldSelectedIndex from figuring out what
266 * item was selected using content
267 * @param aPoint the event point, in listcontrolframe coordinates
268 * @return NS_OK if it successfully found the selection
270 nsresult GetIndexFromDOMEvent(mozilla::dom::Event* aMouseEvent,
271 int32_t& aCurIndex);
273 bool CheckIfAllFramesHere();
275 // guess at a row block size based on our own style.
276 nscoord CalcFallbackRowBSize(float aFontSizeInflation);
278 // CalcIntrinsicBSize computes our intrinsic block size (taking the
279 // "size" attribute into account). This should only be called in
280 // non-dropdown mode.
281 nscoord CalcIntrinsicBSize(nscoord aBSizeOfARow, int32_t aNumberOfOptions);
283 // Dropped down stuff
284 void SetComboboxItem(int32_t aIndex);
286 // Selection
287 bool SetOptionsSelectedFromFrame(int32_t aStartIndex, int32_t aEndIndex,
288 bool aValue, bool aClearAll);
289 bool ToggleOptionSelectedFromFrame(int32_t aIndex);
291 MOZ_CAN_RUN_SCRIPT
292 bool SingleSelection(int32_t aClickedIndex, bool aDoToggle);
293 bool ExtendedSelection(int32_t aStartIndex, int32_t aEndIndex,
294 bool aClearAll);
295 MOZ_CAN_RUN_SCRIPT
296 bool HandleListSelection(mozilla::dom::Event* aDOMEvent,
297 int32_t selectedIndex);
298 void InitSelectionRange(int32_t aClickedIndex);
300 public:
301 nsSelectsAreaFrame* GetOptionsContainer() const {
302 return static_cast<nsSelectsAreaFrame*>(GetScrolledFrame());
305 static constexpr int32_t kNothingSelected = -1;
307 protected:
308 nscoord BSizeOfARow() { return GetOptionsContainer()->BSizeOfARow(); }
311 * @return how many displayable options/optgroups this frame has.
313 uint32_t GetNumberOfRows();
315 // Data Members
316 int32_t mStartSelectionIndex;
317 int32_t mEndSelectionIndex;
319 uint32_t mNumDisplayRows;
320 bool mChangesSinceDragStart : 1;
322 // Has the user selected a visible item since we showed the dropdown?
323 bool mItemSelectionStarted : 1;
325 bool mIsAllContentHere : 1;
326 bool mIsAllFramesHere : 1;
327 bool mHasBeenInitialized : 1;
328 bool mNeedToReset : 1;
329 bool mPostChildrenLoadedReset : 1;
331 // True if we're in the middle of a reflow and might need a second
332 // pass. This only happens for auto heights.
333 bool mMightNeedSecondPass : 1;
336 * Set to aPresContext->HasPendingInterrupt() at the start of Reflow.
337 * Set to false at the end of DidReflow.
339 bool mHasPendingInterruptAtStartOfReflow : 1;
341 // True if the selection can be set to nothing or disabled options.
342 bool mForceSelection : 1;
344 // The last computed block size we reflowed at if we're a combobox
345 // dropdown.
346 // XXXbz should we be using a subclass here? Or just not worry
347 // about the extra member on listboxes?
348 nscoord mLastDropdownComputedBSize;
350 // At the time of our last dropdown, the backstop color to draw in case we
351 // are translucent.
352 nscolor mLastDropdownBackstopColor;
354 RefPtr<mozilla::HTMLSelectEventListener> mEventListener;
356 static nsListControlFrame* mFocused;
358 #ifdef DO_REFLOW_COUNTER
359 int32_t mReflowId;
360 #endif
363 #endif /* nsListControlFrame_h___ */