nsListControlFrame.h (9632B)
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___ 8 9 #include "mozilla/Attributes.h" 10 #include "mozilla/ScrollContainerFrame.h" 11 #include "mozilla/StaticPtr.h" 12 #include "nsISelectControlFrame.h" 13 14 class nsComboboxControlFrame; 15 class nsPresContext; 16 17 namespace mozilla { 18 class PresShell; 19 class HTMLSelectEventListener; 20 21 namespace dom { 22 class Event; 23 class HTMLOptionElement; 24 class HTMLSelectElement; 25 class HTMLOptionsCollection; 26 } // namespace dom 27 } // namespace mozilla 28 29 /** 30 * Frame-based listbox. 31 */ 32 33 class nsListControlFrame final : public mozilla::ScrollContainerFrame, 34 public nsISelectControlFrame { 35 public: 36 using HTMLOptionElement = mozilla::dom::HTMLOptionElement; 37 38 friend nsListControlFrame* NS_NewListControlFrame( 39 mozilla::PresShell* aPresShell, ComputedStyle* aStyle); 40 41 NS_DECL_QUERYFRAME 42 NS_DECL_FRAMEARENA_HELPERS(nsListControlFrame) 43 44 Maybe<nscoord> GetNaturalBaselineBOffset( 45 mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup, 46 BaselineExportContext) const override; 47 48 // nsIFrame 49 nsresult HandleEvent(nsPresContext* aPresContext, 50 mozilla::WidgetGUIEvent* aEvent, 51 nsEventStatus* aEventStatus) final; 52 53 void SetInitialChildList(ChildListID aListID, nsFrameList&& aChildList) final; 54 55 nscoord IntrinsicISize(const mozilla::IntrinsicSizeInput& aInput, 56 mozilla::IntrinsicISizeType aType) final; 57 58 void Reflow(nsPresContext* aCX, ReflowOutput& aDesiredSize, 59 const ReflowInput& aReflowInput, nsReflowStatus& aStatus) final; 60 61 void Init(nsIContent* aContent, nsContainerFrame* aParent, 62 nsIFrame* aPrevInFlow) final; 63 64 bool ReflowFinished() final; 65 void Destroy(DestroyContext&) override; 66 67 int32_t GetEndSelectionIndex() const { return mEndSelectionIndex; } 68 69 mozilla::dom::HTMLOptionElement* GetCurrentOption() const; 70 71 #ifdef DEBUG_FRAME_DUMP 72 nsresult GetFrameName(nsAString& aResult) const final; 73 #endif 74 75 void ElementStateChanged(mozilla::dom::ElementState aStates) final; 76 bool ShouldPropagateComputedBSizeToScrolledContent() const final; 77 78 // for accessibility purposes 79 #ifdef ACCESSIBILITY 80 mozilla::a11y::AccType AccessibleType() final; 81 #endif 82 83 int32_t GetSelectedIndex(); 84 85 /** 86 * Gets the text of the currently selected item. 87 * If the there are zero items then an empty string is returned 88 * If there is nothing selected, then the 0th item's text is returned. 89 */ 90 void GetOptionText(uint32_t aIndex, nsAString& aStr); 91 92 void CaptureMouseEvents(bool aGrabMouseEvents); 93 nscoord GetBSizeOfARow(); 94 uint32_t GetNumberOfOptions(); 95 96 MOZ_CAN_RUN_SCRIPT_BOUNDARY void OnContentReset(); 97 98 // nsISelectControlFrame 99 NS_IMETHOD AddOption(int32_t index) final; 100 NS_IMETHOD RemoveOption(int32_t index) final; 101 MOZ_CAN_RUN_SCRIPT_BOUNDARY 102 NS_IMETHOD DoneAddingChildren(bool aIsDone) final; 103 104 /** 105 * Gets the content (an option) by index and then set it as 106 * being selected or not selected. 107 */ 108 MOZ_CAN_RUN_SCRIPT_BOUNDARY 109 NS_IMETHOD OnOptionSelected(int32_t aIndex, bool aSelected) final; 110 MOZ_CAN_RUN_SCRIPT_BOUNDARY 111 NS_IMETHOD_(void) 112 OnSetSelectedIndex(int32_t aOldIndex, int32_t aNewIndex) final; 113 114 /** 115 * Mouse event listeners. 116 * @note These methods might destroy the frame, pres shell and other objects. 117 */ 118 MOZ_CAN_RUN_SCRIPT 119 nsresult HandleLeftButtonMouseDown(mozilla::dom::Event* aMouseEvent); 120 MOZ_CAN_RUN_SCRIPT 121 nsresult HandleLeftButtonMouseUp(mozilla::dom::Event* aMouseEvent); 122 MOZ_CAN_RUN_SCRIPT 123 nsresult DragMove(mozilla::dom::Event* aMouseEvent); 124 MOZ_CAN_RUN_SCRIPT 125 126 MOZ_CAN_RUN_SCRIPT 127 bool PerformSelection(int32_t aClickedIndex, bool aIsShift, bool aIsControl); 128 MOZ_CAN_RUN_SCRIPT 129 void UpdateSelectionAfterKeyEvent(int32_t aNewIndex, uint32_t aCharCode, 130 bool aIsShift, bool aIsControlOrMeta, 131 bool aIsControlSelectMode); 132 133 /** 134 * Returns the options collection for mContent, if any. 135 */ 136 mozilla::dom::HTMLOptionsCollection* GetOptions() const; 137 /** 138 * Returns the HTMLOptionElement for a given index in mContent's collection. 139 */ 140 HTMLOptionElement* GetOption(uint32_t aIndex) const; 141 142 // Helper 143 bool IsFocused() const; 144 145 /** 146 * Function to paint the focus rect when our nsSelectsAreaFrame is painting. 147 * @param aPt the offset of this frame, relative to the rendering reference 148 * frame 149 */ 150 void PaintFocus(mozilla::gfx::DrawTarget* aDrawTarget, nsPoint aPt); 151 152 /** 153 * If this frame IsFocused(), invalidates an area that includes anything 154 * that PaintFocus will or could have painted --- basically the whole 155 * GetOptionsContainer, plus some extra stuff if there are no options. This 156 * must be called every time mEndSelectionIndex changes. 157 */ 158 void InvalidateFocus(); 159 160 /** 161 * Function to calculate the block size of a row, for use with the 162 * "size" attribute. 163 * Can't be const because GetNumberOfOptions() isn't const. 164 */ 165 nscoord CalcBSizeOfARow(); 166 167 /** 168 * Function to ask whether we're currently in what might be the 169 * first pass of a two-pass reflow. 170 */ 171 bool MightNeedSecondPass() const { return mMightNeedSecondPass; } 172 173 /** 174 * Return the number of displayed rows in the list. 175 */ 176 uint32_t GetNumDisplayRows() const { return mNumDisplayRows; } 177 178 #ifdef ACCESSIBILITY 179 /** 180 * Post a custom DOM event for the change, so that accessibility can 181 * fire a native focus event for accessibility 182 * (Some 3rd party products need to track our focus) 183 */ 184 void FireMenuItemActiveEvent( 185 nsIContent* aPreviousOption); // Inform assistive tech what got focused 186 #endif 187 188 protected: 189 /** 190 * Updates the selected text in a combobox and then calls FireOnChange(). 191 * @note This method might destroy the frame, pres shell and other objects. 192 * Returns false if calling it destroyed |this|. 193 */ 194 MOZ_CAN_RUN_SCRIPT 195 bool UpdateSelection(); 196 197 /** 198 * Returns whether mContent supports multiple selection. 199 */ 200 bool GetMultiple() const; 201 202 mozilla::dom::HTMLSelectElement& Select() const; 203 204 /** 205 * @return true if the <option> at aIndex is selectable by the user. 206 */ 207 bool IsOptionInteractivelySelectable(int32_t aIndex) const; 208 /** 209 * @return true if aOption in aSelect is selectable by the user. 210 */ 211 static bool IsOptionInteractivelySelectable( 212 mozilla::dom::HTMLSelectElement* aSelect, 213 mozilla::dom::HTMLOptionElement* aOption); 214 215 MOZ_CAN_RUN_SCRIPT void ScrollToFrame(HTMLOptionElement& aOptElement); 216 217 MOZ_CAN_RUN_SCRIPT void ScrollToIndex(int32_t anIndex); 218 219 public: 220 /** 221 * Resets the select back to it's original default values; 222 * those values as determined by the original HTML 223 */ 224 MOZ_CAN_RUN_SCRIPT void ResetList(bool aAllowScrolling); 225 226 protected: 227 explicit nsListControlFrame(ComputedStyle* aStyle, 228 nsPresContext* aPresContext); 229 virtual ~nsListControlFrame(); 230 231 /** 232 * Sets the mSelectedIndex and mOldSelectedIndex from figuring out what 233 * item was selected using content 234 * @param aPoint the event point, in listcontrolframe coordinates 235 * @return NS_OK if it successfully found the selection 236 */ 237 nsresult GetIndexFromDOMEvent(mozilla::dom::Event* aMouseEvent, 238 int32_t& aCurIndex); 239 240 bool CheckIfAllFramesHere(); 241 242 // guess at a row block size based on our own style. 243 nscoord CalcFallbackRowBSize(float aFontSizeInflation); 244 245 // CalcIntrinsicBSize computes our intrinsic block size (taking the 246 // "size" attribute into account). This should only be called in 247 // non-dropdown mode. 248 nscoord CalcIntrinsicBSize(nscoord aBSizeOfARow, int32_t aNumberOfOptions); 249 250 // Dropped down stuff 251 void SetComboboxItem(int32_t aIndex); 252 253 // Selection 254 bool SetOptionsSelectedFromFrame(int32_t aStartIndex, int32_t aEndIndex, 255 bool aValue, bool aClearAll); 256 bool ToggleOptionSelectedFromFrame(int32_t aIndex); 257 258 MOZ_CAN_RUN_SCRIPT 259 bool SingleSelection(int32_t aClickedIndex, bool aDoToggle); 260 bool ExtendedSelection(int32_t aStartIndex, int32_t aEndIndex, 261 bool aClearAll); 262 MOZ_CAN_RUN_SCRIPT 263 bool HandleListSelection(mozilla::dom::Event* aDOMEvent, 264 int32_t selectedIndex); 265 void InitSelectionRange(int32_t aClickedIndex); 266 267 public: 268 static constexpr int32_t kNothingSelected = -1; 269 270 protected: 271 nscoord BSizeOfARow() const { return mBSizeOfARow; } 272 273 /** 274 * @return how many displayable options/optgroups this frame has. 275 */ 276 uint32_t GetNumberOfRows(); 277 278 // Data Members 279 int32_t mStartSelectionIndex = 0; 280 int32_t mEndSelectionIndex = 0; 281 282 uint32_t mNumDisplayRows = 0; 283 nscoord mBSizeOfARow = -1; 284 bool mChangesSinceDragStart : 1; 285 286 bool mIsAllContentHere : 1; 287 bool mIsAllFramesHere : 1; 288 bool mHasBeenInitialized : 1; 289 bool mNeedToReset : 1; 290 bool mPostChildrenLoadedReset : 1; 291 292 // True if we're in the middle of a reflow and might need a second 293 // pass. This only happens for auto heights. 294 bool mMightNeedSecondPass : 1; 295 296 // True if our reflow got interrupted. 297 bool mReflowWasInterrupted : 1; 298 299 RefPtr<mozilla::HTMLSelectEventListener> mEventListener; 300 }; 301 302 #endif /* nsListControlFrame_h___ */