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