nsListControlFrame.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  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. #ifndef nsListControlFrame_h___
  6. #define nsListControlFrame_h___
  7. #ifdef DEBUG_evaughan
  8. //#define DEBUG_rods
  9. #endif
  10. #ifdef DEBUG_rods
  11. //#define DO_REFLOW_DEBUG
  12. //#define DO_REFLOW_COUNTER
  13. //#define DO_UNCONSTRAINED_CHECK
  14. //#define DO_PIXELS
  15. #endif
  16. #include "mozilla/Attributes.h"
  17. #include "nsGfxScrollFrame.h"
  18. #include "nsIFormControlFrame.h"
  19. #include "nsIListControlFrame.h"
  20. #include "nsISelectControlFrame.h"
  21. #include "nsSelectsAreaFrame.h"
  22. // X.h defines KeyPress
  23. #ifdef KeyPress
  24. #undef KeyPress
  25. #endif
  26. class nsIComboboxControlFrame;
  27. class nsPresContext;
  28. class nsListEventListener;
  29. namespace mozilla {
  30. namespace dom {
  31. class HTMLOptionElement;
  32. class HTMLOptionsCollection;
  33. } // namespace dom
  34. } // namespace mozilla
  35. /**
  36. * Frame-based listbox.
  37. */
  38. class nsListControlFrame final : public nsHTMLScrollFrame,
  39. public nsIFormControlFrame,
  40. public nsIListControlFrame,
  41. public nsISelectControlFrame
  42. {
  43. public:
  44. friend nsContainerFrame* NS_NewListControlFrame(nsIPresShell* aPresShell,
  45. nsStyleContext* aContext);
  46. NS_DECL_QUERYFRAME
  47. NS_DECL_FRAMEARENA_HELPERS
  48. // nsIFrame
  49. virtual nsresult HandleEvent(nsPresContext* aPresContext,
  50. mozilla::WidgetGUIEvent* aEvent,
  51. nsEventStatus* aEventStatus) override;
  52. virtual void SetInitialChildList(ChildListID aListID,
  53. nsFrameList& aChildList) override;
  54. virtual nscoord GetPrefISize(nsRenderingContext *aRenderingContext) override;
  55. virtual nscoord GetMinISize(nsRenderingContext *aRenderingContext) override;
  56. virtual void Reflow(nsPresContext* aCX,
  57. ReflowOutput& aDesiredSize,
  58. const ReflowInput& aReflowInput,
  59. nsReflowStatus& aStatus) override;
  60. virtual void Init(nsIContent* aContent,
  61. nsContainerFrame* aParent,
  62. nsIFrame* aPrevInFlow) override;
  63. virtual void DidReflow(nsPresContext* aPresContext,
  64. const ReflowInput* aReflowInput,
  65. nsDidReflowStatus aStatus) override;
  66. virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
  67. virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
  68. const nsDisplayListSet& aLists) override;
  69. virtual nsContainerFrame* GetContentInsertionFrame() override;
  70. /**
  71. * Get the "type" of the frame
  72. *
  73. * @see nsGkAtoms::scrollFrame
  74. */
  75. virtual nsIAtom* GetType() const override;
  76. virtual bool IsFrameOfType(uint32_t aFlags) const override
  77. {
  78. return nsHTMLScrollFrame::IsFrameOfType(aFlags &
  79. ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
  80. }
  81. #ifdef DEBUG_FRAME_DUMP
  82. virtual nsresult GetFrameName(nsAString& aResult) const override;
  83. #endif
  84. // nsIFormControlFrame
  85. virtual nsresult SetFormProperty(nsIAtom* aName, const nsAString& aValue) override;
  86. virtual void SetFocus(bool aOn = true, bool aRepaint = false) override;
  87. virtual mozilla::ScrollStyles GetScrollStyles() const override;
  88. virtual bool ShouldPropagateComputedBSizeToScrolledContent() const override;
  89. // for accessibility purposes
  90. #ifdef ACCESSIBILITY
  91. virtual mozilla::a11y::AccType AccessibleType() override;
  92. #endif
  93. // nsIListControlFrame
  94. virtual void SetComboboxFrame(nsIFrame* aComboboxFrame) override;
  95. virtual int32_t GetSelectedIndex() override;
  96. virtual mozilla::dom::HTMLOptionElement* GetCurrentOption() override;
  97. /**
  98. * Gets the text of the currently selected item.
  99. * If the there are zero items then an empty string is returned
  100. * If there is nothing selected, then the 0th item's text is returned.
  101. */
  102. virtual void GetOptionText(uint32_t aIndex, nsAString& aStr) override;
  103. virtual void CaptureMouseEvents(bool aGrabMouseEvents) override;
  104. virtual nscoord GetBSizeOfARow() override;
  105. virtual uint32_t GetNumberOfOptions() override;
  106. virtual void AboutToDropDown() override;
  107. /**
  108. * @note This method might destroy the frame, pres shell and other objects.
  109. */
  110. virtual void AboutToRollup() override;
  111. /**
  112. * Dispatch a DOM oninput and onchange event synchroniously.
  113. * @note This method might destroy the frame, pres shell and other objects.
  114. */
  115. virtual void FireOnInputAndOnChange() override;
  116. /**
  117. * Makes aIndex the selected option of a combobox list.
  118. * @note This method might destroy the frame, pres shell and other objects.
  119. */
  120. virtual void ComboboxFinish(int32_t aIndex) override;
  121. virtual void OnContentReset() override;
  122. // nsISelectControlFrame
  123. NS_IMETHOD AddOption(int32_t index) override;
  124. NS_IMETHOD RemoveOption(int32_t index) override;
  125. NS_IMETHOD DoneAddingChildren(bool aIsDone) override;
  126. /**
  127. * Gets the content (an option) by index and then set it as
  128. * being selected or not selected.
  129. */
  130. NS_IMETHOD OnOptionSelected(int32_t aIndex, bool aSelected) override;
  131. NS_IMETHOD OnSetSelectedIndex(int32_t aOldIndex, int32_t aNewIndex) override;
  132. /**
  133. * Mouse event listeners.
  134. * @note These methods might destroy the frame, pres shell and other objects.
  135. */
  136. nsresult MouseDown(nsIDOMEvent* aMouseEvent);
  137. nsresult MouseUp(nsIDOMEvent* aMouseEvent);
  138. nsresult MouseMove(nsIDOMEvent* aMouseEvent);
  139. nsresult DragMove(nsIDOMEvent* aMouseEvent);
  140. nsresult KeyDown(nsIDOMEvent* aKeyEvent);
  141. nsresult KeyPress(nsIDOMEvent* aKeyEvent);
  142. /**
  143. * Returns the options collection for mContent, if any.
  144. */
  145. mozilla::dom::HTMLOptionsCollection* GetOptions() const;
  146. /**
  147. * Returns the HTMLOptionElement for a given index in mContent's collection.
  148. */
  149. mozilla::dom::HTMLOptionElement* GetOption(uint32_t aIndex) const;
  150. static void ComboboxFocusSet();
  151. // Helper
  152. bool IsFocused() { return this == mFocused; }
  153. /**
  154. * Function to paint the focus rect when our nsSelectsAreaFrame is painting.
  155. * @param aPt the offset of this frame, relative to the rendering reference
  156. * frame
  157. */
  158. void PaintFocus(mozilla::gfx::DrawTarget* aDrawTarget, nsPoint aPt);
  159. /**
  160. * If this frame IsFocused(), invalidates an area that includes anything
  161. * that PaintFocus will or could have painted --- basically the whole
  162. * GetOptionsContainer, plus some extra stuff if there are no options. This
  163. * must be called every time mEndSelectionIndex changes.
  164. */
  165. void InvalidateFocus();
  166. /**
  167. * Function to calculate the block size of a row, for use with the
  168. * "size" attribute.
  169. * Can't be const because GetNumberOfOptions() isn't const.
  170. */
  171. nscoord CalcBSizeOfARow();
  172. /**
  173. * Function to ask whether we're currently in what might be the
  174. * first pass of a two-pass reflow.
  175. */
  176. bool MightNeedSecondPass() const {
  177. return mMightNeedSecondPass;
  178. }
  179. void SetSuppressScrollbarUpdate(bool aSuppress) {
  180. nsHTMLScrollFrame::SetSuppressScrollbarUpdate(aSuppress);
  181. }
  182. /**
  183. * Return whether the list is in dropdown mode.
  184. */
  185. bool IsInDropDownMode() const;
  186. /**
  187. * Return the number of displayed rows in the list.
  188. */
  189. uint32_t GetNumDisplayRows() const { return mNumDisplayRows; }
  190. /**
  191. * Return true if the drop-down list can display more rows.
  192. * (always false if not in drop-down mode)
  193. */
  194. bool GetDropdownCanGrow() const { return mDropdownCanGrow; }
  195. /**
  196. * Dropdowns need views
  197. */
  198. virtual bool NeedsView() override { return IsInDropDownMode(); }
  199. /**
  200. * Frees statics owned by this class.
  201. */
  202. static void Shutdown();
  203. #ifdef ACCESSIBILITY
  204. /**
  205. * Post a custom DOM event for the change, so that accessibility can
  206. * fire a native focus event for accessibility
  207. * (Some 3rd party products need to track our focus)
  208. */
  209. void FireMenuItemActiveEvent(); // Inform assistive tech what got focused
  210. #endif
  211. protected:
  212. /**
  213. * Updates the selected text in a combobox and then calls FireOnChange().
  214. * @note This method might destroy the frame, pres shell and other objects.
  215. * Returns false if calling it destroyed |this|.
  216. */
  217. bool UpdateSelection();
  218. /**
  219. * Returns whether mContent supports multiple selection.
  220. */
  221. bool GetMultiple() const {
  222. return mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::multiple);
  223. }
  224. /**
  225. * Toggles (show/hide) the combobox dropdown menu.
  226. * @note This method might destroy the frame, pres shell and other objects.
  227. */
  228. void DropDownToggleKey(nsIDOMEvent* aKeyEvent);
  229. nsresult IsOptionDisabled(int32_t anIndex, bool &aIsDisabled);
  230. /**
  231. * @note This method might destroy the frame, pres shell and other objects.
  232. */
  233. void ScrollToFrame(mozilla::dom::HTMLOptionElement& aOptElement);
  234. /**
  235. * @note This method might destroy the frame, pres shell and other objects.
  236. */
  237. void ScrollToIndex(int32_t anIndex);
  238. /**
  239. * When the user clicks on the comboboxframe to show the dropdown
  240. * listbox, they then have to move the mouse into the list. We don't
  241. * want to process those mouse events as selection events (i.e., to
  242. * scroll list items into view). So we ignore the events until
  243. * the mouse moves below our border-inner-edge, when
  244. * mItemSelectionStarted is set.
  245. *
  246. * @param aPoint relative to this frame
  247. */
  248. bool IgnoreMouseEventForSelection(nsIDOMEvent* aEvent);
  249. /**
  250. * If the dropdown is showing and the mouse has moved below our
  251. * border-inner-edge, then set mItemSelectionStarted.
  252. */
  253. void UpdateInListState(nsIDOMEvent* aEvent);
  254. void AdjustIndexForDisabledOpt(int32_t aStartIndex, int32_t &anNewIndex,
  255. int32_t aNumOptions, int32_t aDoAdjustInc, int32_t aDoAdjustIncNext);
  256. /**
  257. * Resets the select back to it's original default values;
  258. * those values as determined by the original HTML
  259. */
  260. virtual void ResetList(bool aAllowScrolling);
  261. explicit nsListControlFrame(nsStyleContext* aContext);
  262. virtual ~nsListControlFrame();
  263. /**
  264. * Sets the mSelectedIndex and mOldSelectedIndex from figuring out what
  265. * item was selected using content
  266. * @param aPoint the event point, in listcontrolframe coordinates
  267. * @return NS_OK if it successfully found the selection
  268. */
  269. nsresult GetIndexFromDOMEvent(nsIDOMEvent* aMouseEvent, int32_t& aCurIndex);
  270. bool CheckIfAllFramesHere();
  271. bool IsLeftButton(nsIDOMEvent* aMouseEvent);
  272. // guess at a row block size based on our own style.
  273. nscoord CalcFallbackRowBSize(float aFontSizeInflation);
  274. // CalcIntrinsicBSize computes our intrinsic block size (taking the
  275. // "size" attribute into account). This should only be called in
  276. // non-dropdown mode.
  277. nscoord CalcIntrinsicBSize(nscoord aBSizeOfARow, int32_t aNumberOfOptions);
  278. // Dropped down stuff
  279. void SetComboboxItem(int32_t aIndex);
  280. /**
  281. * Method to reflow ourselves as a dropdown list. This differs from
  282. * reflow as a listbox because the criteria for needing a second
  283. * pass are different. This will be called from Reflow() as needed.
  284. */
  285. void ReflowAsDropdown(nsPresContext* aPresContext,
  286. ReflowOutput& aDesiredSize,
  287. const ReflowInput& aReflowInput,
  288. nsReflowStatus& aStatus);
  289. // Selection
  290. bool SetOptionsSelectedFromFrame(int32_t aStartIndex,
  291. int32_t aEndIndex,
  292. bool aValue,
  293. bool aClearAll);
  294. bool ToggleOptionSelectedFromFrame(int32_t aIndex);
  295. /**
  296. * @note This method might destroy the frame, pres shell and other objects.
  297. */
  298. bool SingleSelection(int32_t aClickedIndex, bool aDoToggle);
  299. bool ExtendedSelection(int32_t aStartIndex, int32_t aEndIndex,
  300. bool aClearAll);
  301. /**
  302. * @note This method might destroy the frame, pres shell and other objects.
  303. */
  304. bool PerformSelection(int32_t aClickedIndex, bool aIsShift,
  305. bool aIsControl);
  306. /**
  307. * @note This method might destroy the frame, pres shell and other objects.
  308. */
  309. bool HandleListSelection(nsIDOMEvent * aDOMEvent, int32_t selectedIndex);
  310. void InitSelectionRange(int32_t aClickedIndex);
  311. void PostHandleKeyEvent(int32_t aNewIndex, uint32_t aCharCode,
  312. bool aIsShift, bool aIsControlOrMeta);
  313. public:
  314. nsSelectsAreaFrame* GetOptionsContainer() const {
  315. return static_cast<nsSelectsAreaFrame*>(GetScrolledFrame());
  316. }
  317. protected:
  318. nscoord BSizeOfARow() {
  319. return GetOptionsContainer()->BSizeOfARow();
  320. }
  321. /**
  322. * @return how many displayable options/optgroups this frame has.
  323. */
  324. uint32_t GetNumberOfRows();
  325. // Data Members
  326. int32_t mStartSelectionIndex;
  327. int32_t mEndSelectionIndex;
  328. nsIComboboxControlFrame *mComboboxFrame;
  329. uint32_t mNumDisplayRows;
  330. bool mChangesSinceDragStart:1;
  331. bool mButtonDown:1;
  332. // Has the user selected a visible item since we showed the
  333. // dropdown?
  334. bool mItemSelectionStarted:1;
  335. bool mIsAllContentHere:1;
  336. bool mIsAllFramesHere:1;
  337. bool mHasBeenInitialized:1;
  338. bool mNeedToReset:1;
  339. bool mPostChildrenLoadedReset:1;
  340. //bool value for multiple discontiguous selection
  341. bool mControlSelectMode:1;
  342. // True if we're in the middle of a reflow and might need a second
  343. // pass. This only happens for auto heights.
  344. bool mMightNeedSecondPass:1;
  345. /**
  346. * Set to aPresContext->HasPendingInterrupt() at the start of Reflow.
  347. * Set to false at the end of DidReflow.
  348. */
  349. bool mHasPendingInterruptAtStartOfReflow:1;
  350. // True if the drop-down can show more rows. Always false if this list
  351. // is not in drop-down mode.
  352. bool mDropdownCanGrow:1;
  353. // True if the selection can be set to nothing or disabled options.
  354. bool mForceSelection:1;
  355. // The last computed block size we reflowed at if we're a combobox
  356. // dropdown.
  357. // XXXbz should we be using a subclass here? Or just not worry
  358. // about the extra member on listboxes?
  359. nscoord mLastDropdownComputedBSize;
  360. // At the time of our last dropdown, the backstop color to draw in case we
  361. // are translucent.
  362. nscolor mLastDropdownBackstopColor;
  363. RefPtr<nsListEventListener> mEventListener;
  364. static nsListControlFrame * mFocused;
  365. static nsString * sIncrementalString;
  366. #ifdef DO_REFLOW_COUNTER
  367. int32_t mReflowId;
  368. #endif
  369. private:
  370. // for incremental typing navigation
  371. static nsAString& GetIncrementalString ();
  372. static DOMTimeStamp gLastKeyTime;
  373. class MOZ_RAII AutoIncrementalSearchResetter
  374. {
  375. public:
  376. AutoIncrementalSearchResetter() :
  377. mCancelled(false)
  378. {
  379. }
  380. ~AutoIncrementalSearchResetter()
  381. {
  382. if (!mCancelled) {
  383. nsListControlFrame::GetIncrementalString().Truncate();
  384. }
  385. }
  386. void Cancel()
  387. {
  388. mCancelled = true;
  389. }
  390. private:
  391. bool mCancelled;
  392. };
  393. };
  394. #endif /* nsListControlFrame_h___ */