nsComboboxControlFrame.h 12 KB

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