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 "nsIAnonymousContentCreator.h" 29 #include "nsISelectControlFrame.h" 30 #include "nsIRollupListener.h" 31 #include "nsThreadUtils.h" 32 33 class nsComboboxDisplayFrame; 34 class nsTextNode; 35 36 namespace mozilla { 37 class PresShell; 38 class HTMLSelectEventListener; 39 namespace dom { 40 class HTMLSelectElement; 41 } 42 43 namespace gfx { 44 class DrawTarget; 45 } // namespace gfx 46 } // namespace mozilla 47 48 class nsComboboxControlFrame final : public nsBlockFrame, 49 public nsIFormControlFrame, 50 public nsIAnonymousContentCreator, 51 public nsISelectControlFrame { 52 using DrawTarget = mozilla::gfx::DrawTarget; 53 using Element = mozilla::dom::Element; 54 55 public: 56 friend nsComboboxControlFrame* NS_NewComboboxControlFrame( 57 mozilla::PresShell* aPresShell, ComputedStyle* aStyle, 58 nsFrameState aFlags); 59 friend class nsComboboxDisplayFrame; 60 61 explicit nsComboboxControlFrame(ComputedStyle* aStyle, 62 nsPresContext* aPresContext); 63 ~nsComboboxControlFrame(); 64 65 NS_DECL_QUERYFRAME 66 NS_DECL_FRAMEARENA_HELPERS(nsComboboxControlFrame) 67 68 // nsIAnonymousContentCreator 69 nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) final; 70 void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements, 71 uint32_t aFilter) final; 72 73 nsIContent* GetDisplayNode() const; 74 nsIFrame* CreateFrameForDisplayNode(); 75 76 #ifdef ACCESSIBILITY 77 mozilla::a11y::AccType AccessibleType() final; 78 #endif 79 80 nscoord GetMinISize(gfxContext* aRenderingContext) final; 81 82 nscoord GetPrefISize(gfxContext* aRenderingContext) final; 83 84 void Reflow(nsPresContext* aCX, ReflowOutput& aDesiredSize, 85 const ReflowInput& aReflowInput, nsReflowStatus& aStatus) final; 86 87 MOZ_CAN_RUN_SCRIPT_BOUNDARY 88 nsresult HandleEvent(nsPresContext* aPresContext, 89 mozilla::WidgetGUIEvent* aEvent, 90 nsEventStatus* aEventStatus) final; 91 92 void BuildDisplayList(nsDisplayListBuilder* aBuilder, 93 const nsDisplayListSet& aLists) final; 94 95 void PaintFocus(DrawTarget& aDrawTarget, nsPoint aPt); 96 IsFrameOfType(uint32_t aFlags)97 bool IsFrameOfType(uint32_t aFlags) const final { 98 return nsBlockFrame::IsFrameOfType( 99 aFlags & ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock)); 100 } 101 102 void Init(nsIContent* aContent, nsContainerFrame* aParent, 103 nsIFrame* aPrevInFlow) final; 104 105 #ifdef DEBUG_FRAME_DUMP 106 nsresult GetFrameName(nsAString& aResult) const final; 107 #endif 108 void DestroyFrom(nsIFrame* aDestructRoot, 109 PostDestroyData& aPostDestroyData) final; 110 void SetInitialChildList(ChildListID aListID, nsFrameList& aChildList) final; 111 const nsFrameList& GetChildList(ChildListID aListID) const final; 112 void GetChildLists(nsTArray<ChildList>* aLists) const final; 113 114 nsContainerFrame* GetContentInsertionFrame() final; 115 116 // Return the dropdown and display frame. 117 void AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult) final; 118 119 // nsIFormControlFrame SetFormProperty(nsAtom * aName,const nsAString & aValue)120 nsresult SetFormProperty(nsAtom* aName, const nsAString& aValue) final { 121 return NS_OK; 122 } 123 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 MOZ_CAN_RUN_SCRIPT_BOUNDARY 134 void SetFocus(bool aOn, bool aRepaint) final; 135 136 /** 137 * Return the available space before and after this frame for 138 * placing the drop-down list, and the current 2D translation. 139 * Note that either or both can be less than or equal to zero, 140 * if both are then the drop-down should be closed. 141 */ 142 void GetAvailableDropdownSpace(mozilla::WritingMode aWM, nscoord* aBefore, 143 nscoord* aAfter, 144 mozilla::LogicalPoint* aTranslation); 145 int32_t GetIndexOfDisplayArea(); 146 /** 147 * @note This method might destroy |this|. 148 */ 149 nsresult RedisplaySelectedText(); 150 int32_t UpdateRecentIndex(int32_t aIndex); 151 152 bool IsDroppedDown() const; 153 154 // nsISelectControlFrame 155 NS_IMETHOD AddOption(int32_t index) final; 156 NS_IMETHOD RemoveOption(int32_t index) final; 157 NS_IMETHOD DoneAddingChildren(bool aIsDone) final; 158 NS_IMETHOD OnOptionSelected(int32_t aIndex, bool aSelected) final; 159 NS_IMETHOD_(void) 160 OnSetSelectedIndex(int32_t aOldIndex, int32_t aNewIndex) final; 161 162 int32_t CharCountOfLargestOptionForInflation() const; 163 164 protected: 165 friend class RedisplayTextEvent; 166 friend class nsAsyncResize; 167 friend class nsResizeDropdownAtFinalPosition; 168 169 // Return true if we should render a dropdown button. 170 bool HasDropDownButton() const; 171 nscoord DropDownButtonISize(); 172 173 enum DropDownPositionState { 174 // can't show the dropdown at its current position 175 eDropDownPositionSuppressed, 176 // a resize reflow is pending, don't show it yet 177 eDropDownPositionPendingResize, 178 // the dropdown has its final size and position and can be displayed here 179 eDropDownPositionFinal 180 }; 181 DropDownPositionState AbsolutelyPositionDropDown(); 182 183 // Helper for GetMinISize/GetPrefISize 184 nscoord GetIntrinsicISize(gfxContext* aRenderingContext, 185 mozilla::IntrinsicISizeType aType); 186 187 class RedisplayTextEvent : public mozilla::Runnable { 188 public: 189 NS_DECL_NSIRUNNABLE RedisplayTextEvent(nsComboboxControlFrame * c)190 explicit RedisplayTextEvent(nsComboboxControlFrame* c) 191 : mozilla::Runnable("nsComboboxControlFrame::RedisplayTextEvent"), 192 mControlFrame(c) {} Revoke()193 void Revoke() { mControlFrame = nullptr; } 194 195 private: 196 nsComboboxControlFrame* mControlFrame; 197 }; 198 199 void CheckFireOnChange(); 200 void FireValueChangeEvent(); 201 nsresult RedisplayText(); 202 void HandleRedisplayTextEvent(); 203 void ActuallyDisplayText(bool aNotify); 204 205 // If our total transform to the root frame of the root document is only a 2d 206 // translation then return that translation, otherwise returns (0,0). 207 nsPoint GetCSSTransformTranslation(); 208 209 mozilla::dom::HTMLSelectElement& Select() const; 210 void GetOptionText(uint32_t aIndex, nsAString& aText) const; 211 212 nsFrameList mPopupFrames; // additional named child list 213 RefPtr<nsTextNode> mDisplayContent; // Anonymous content used to display the 214 // current selection 215 RefPtr<Element> mButtonContent; // Anonymous content for the button 216 nsContainerFrame* mDisplayFrame; // frame to display selection 217 nsIFrame* mButtonFrame; // button frame 218 219 // The inline size of our display area. Used by that frame's reflow 220 // to size to the full inline size except the drop-marker. 221 nscoord mDisplayISize; 222 // The maximum inline size of our display area, which is the 223 // nsComoboxControlFrame's border-box. 224 // 225 // Going over this would be observable via DOM APIs like client / scrollWidth. 226 nscoord mMaxDisplayISize; 227 228 nsRevocableEventPtr<RedisplayTextEvent> mRedisplayTextEvent; 229 230 int32_t mRecentSelectedIndex; 231 int32_t mDisplayedIndex; 232 nsString mDisplayedOptionTextOrPreview; 233 234 RefPtr<mozilla::HTMLSelectEventListener> mEventListener; 235 236 // See comment in HandleRedisplayTextEvent(). 237 bool mInRedisplayText; 238 bool mIsOpenInParentProcess; 239 240 // static class data member for Bug 32920 241 // only one control can be focused at a time 242 static nsComboboxControlFrame* sFocused; 243 244 #ifdef DO_REFLOW_COUNTER 245 int32_t mReflowId; 246 #endif 247 }; 248 249 #endif 250