1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/forms/nsListControlFrame.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,472 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 +#ifndef nsListControlFrame_h___ 1.9 +#define nsListControlFrame_h___ 1.10 + 1.11 +#ifdef DEBUG_evaughan 1.12 +//#define DEBUG_rods 1.13 +#endif 1.14 + 1.15 +#ifdef DEBUG_rods 1.16 +//#define DO_REFLOW_DEBUG 1.17 +//#define DO_REFLOW_COUNTER 1.18 +//#define DO_UNCONSTRAINED_CHECK 1.19 +//#define DO_PIXELS 1.20 +#endif 1.21 + 1.22 +#include "mozilla/Attributes.h" 1.23 +#include "nsGfxScrollFrame.h" 1.24 +#include "nsIFormControlFrame.h" 1.25 +#include "nsIListControlFrame.h" 1.26 +#include "nsISelectControlFrame.h" 1.27 +#include "nsAutoPtr.h" 1.28 +#include "nsSelectsAreaFrame.h" 1.29 + 1.30 +// X.h defines KeyPress 1.31 +#ifdef KeyPress 1.32 +#undef KeyPress 1.33 +#endif 1.34 + 1.35 +class nsIDOMHTMLSelectElement; 1.36 +class nsIDOMHTMLOptionsCollection; 1.37 +class nsIComboboxControlFrame; 1.38 +class nsPresContext; 1.39 +class nsListEventListener; 1.40 + 1.41 +namespace mozilla { 1.42 +namespace dom { 1.43 +class HTMLOptionElement; 1.44 +class HTMLOptionsCollection; 1.45 +} // namespace dom 1.46 +} // namespace mozilla 1.47 + 1.48 +/** 1.49 + * Frame-based listbox. 1.50 + */ 1.51 + 1.52 +class nsListControlFrame : public nsHTMLScrollFrame, 1.53 + public nsIFormControlFrame, 1.54 + public nsIListControlFrame, 1.55 + public nsISelectControlFrame 1.56 +{ 1.57 +public: 1.58 + friend nsIFrame* NS_NewListControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); 1.59 + 1.60 + NS_DECL_QUERYFRAME 1.61 + NS_DECL_FRAMEARENA_HELPERS 1.62 + 1.63 + // nsIFrame 1.64 + virtual nsresult HandleEvent(nsPresContext* aPresContext, 1.65 + mozilla::WidgetGUIEvent* aEvent, 1.66 + nsEventStatus* aEventStatus) MOZ_OVERRIDE; 1.67 + 1.68 + virtual nsresult SetInitialChildList(ChildListID aListID, 1.69 + nsFrameList& aChildList) MOZ_OVERRIDE; 1.70 + 1.71 + virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE; 1.72 + virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE; 1.73 + 1.74 + virtual nsresult Reflow(nsPresContext* aCX, 1.75 + nsHTMLReflowMetrics& aDesiredSize, 1.76 + const nsHTMLReflowState& aReflowState, 1.77 + nsReflowStatus& aStatus) MOZ_OVERRIDE; 1.78 + 1.79 + virtual void Init(nsIContent* aContent, 1.80 + nsIFrame* aParent, 1.81 + nsIFrame* aPrevInFlow) MOZ_OVERRIDE; 1.82 + 1.83 + virtual nsresult DidReflow(nsPresContext* aPresContext, 1.84 + const nsHTMLReflowState* aReflowState, 1.85 + nsDidReflowStatus aStatus) MOZ_OVERRIDE; 1.86 + virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE; 1.87 + 1.88 + virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, 1.89 + const nsRect& aDirtyRect, 1.90 + const nsDisplayListSet& aLists) MOZ_OVERRIDE; 1.91 + 1.92 + virtual nsIFrame* GetContentInsertionFrame() MOZ_OVERRIDE; 1.93 + 1.94 + /** 1.95 + * Get the "type" of the frame 1.96 + * 1.97 + * @see nsGkAtoms::scrollFrame 1.98 + */ 1.99 + virtual nsIAtom* GetType() const MOZ_OVERRIDE; 1.100 + 1.101 + virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE 1.102 + { 1.103 + return nsHTMLScrollFrame::IsFrameOfType(aFlags & 1.104 + ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock)); 1.105 + } 1.106 + 1.107 +#ifdef DEBUG_FRAME_DUMP 1.108 + virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE; 1.109 +#endif 1.110 + 1.111 + // nsIFormControlFrame 1.112 + virtual nsresult SetFormProperty(nsIAtom* aName, const nsAString& aValue) MOZ_OVERRIDE; 1.113 + virtual void SetFocus(bool aOn = true, bool aRepaint = false) MOZ_OVERRIDE; 1.114 + 1.115 + virtual mozilla::ScrollbarStyles GetScrollbarStyles() const MOZ_OVERRIDE; 1.116 + virtual bool ShouldPropagateComputedHeightToScrolledContent() const MOZ_OVERRIDE; 1.117 + 1.118 + // for accessibility purposes 1.119 +#ifdef ACCESSIBILITY 1.120 + virtual mozilla::a11y::AccType AccessibleType() MOZ_OVERRIDE; 1.121 +#endif 1.122 + 1.123 + // nsIListControlFrame 1.124 + virtual void SetComboboxFrame(nsIFrame* aComboboxFrame) MOZ_OVERRIDE; 1.125 + virtual int32_t GetSelectedIndex() MOZ_OVERRIDE; 1.126 + virtual mozilla::dom::HTMLOptionElement* GetCurrentOption() MOZ_OVERRIDE; 1.127 + 1.128 + /** 1.129 + * Gets the text of the currently selected item. 1.130 + * If the there are zero items then an empty string is returned 1.131 + * If there is nothing selected, then the 0th item's text is returned. 1.132 + */ 1.133 + virtual void GetOptionText(uint32_t aIndex, nsAString& aStr) MOZ_OVERRIDE; 1.134 + 1.135 + virtual void CaptureMouseEvents(bool aGrabMouseEvents) MOZ_OVERRIDE; 1.136 + virtual nscoord GetHeightOfARow() MOZ_OVERRIDE; 1.137 + virtual uint32_t GetNumberOfOptions() MOZ_OVERRIDE; 1.138 + virtual void AboutToDropDown() MOZ_OVERRIDE; 1.139 + 1.140 + /** 1.141 + * @note This method might destroy the frame, pres shell and other objects. 1.142 + */ 1.143 + virtual void AboutToRollup() MOZ_OVERRIDE; 1.144 + 1.145 + /** 1.146 + * Dispatch a DOM onchange event synchroniously. 1.147 + * @note This method might destroy the frame, pres shell and other objects. 1.148 + */ 1.149 + virtual void FireOnChange() MOZ_OVERRIDE; 1.150 + 1.151 + /** 1.152 + * Makes aIndex the selected option of a combobox list. 1.153 + * @note This method might destroy the frame, pres shell and other objects. 1.154 + */ 1.155 + virtual void ComboboxFinish(int32_t aIndex) MOZ_OVERRIDE; 1.156 + virtual void OnContentReset() MOZ_OVERRIDE; 1.157 + 1.158 + // nsISelectControlFrame 1.159 + NS_IMETHOD AddOption(int32_t index) MOZ_OVERRIDE; 1.160 + NS_IMETHOD RemoveOption(int32_t index) MOZ_OVERRIDE; 1.161 + NS_IMETHOD DoneAddingChildren(bool aIsDone) MOZ_OVERRIDE; 1.162 + 1.163 + /** 1.164 + * Gets the content (an option) by index and then set it as 1.165 + * being selected or not selected. 1.166 + */ 1.167 + NS_IMETHOD OnOptionSelected(int32_t aIndex, bool aSelected) MOZ_OVERRIDE; 1.168 + NS_IMETHOD OnSetSelectedIndex(int32_t aOldIndex, int32_t aNewIndex) MOZ_OVERRIDE; 1.169 + 1.170 + /** 1.171 + * Mouse event listeners. 1.172 + * @note These methods might destroy the frame, pres shell and other objects. 1.173 + */ 1.174 + nsresult MouseDown(nsIDOMEvent* aMouseEvent); 1.175 + nsresult MouseUp(nsIDOMEvent* aMouseEvent); 1.176 + nsresult MouseMove(nsIDOMEvent* aMouseEvent); 1.177 + nsresult DragMove(nsIDOMEvent* aMouseEvent); 1.178 + nsresult KeyDown(nsIDOMEvent* aKeyEvent); 1.179 + nsresult KeyPress(nsIDOMEvent* aKeyEvent); 1.180 + 1.181 + /** 1.182 + * Returns the options collection for mContent, if any. 1.183 + */ 1.184 + mozilla::dom::HTMLOptionsCollection* GetOptions() const; 1.185 + /** 1.186 + * Returns the HTMLOptionElement for a given index in mContent's collection. 1.187 + */ 1.188 + mozilla::dom::HTMLOptionElement* GetOption(uint32_t aIndex) const; 1.189 + 1.190 + static void ComboboxFocusSet(); 1.191 + 1.192 + // Helper 1.193 + bool IsFocused() { return this == mFocused; } 1.194 + 1.195 + /** 1.196 + * Function to paint the focus rect when our nsSelectsAreaFrame is painting. 1.197 + * @param aPt the offset of this frame, relative to the rendering reference 1.198 + * frame 1.199 + */ 1.200 + void PaintFocus(nsRenderingContext& aRC, nsPoint aPt); 1.201 + /** 1.202 + * If this frame IsFocused(), invalidates an area that includes anything 1.203 + * that PaintFocus will or could have painted --- basically the whole 1.204 + * GetOptionsContainer, plus some extra stuff if there are no options. This 1.205 + * must be called every time mEndSelectionIndex changes. 1.206 + */ 1.207 + void InvalidateFocus(); 1.208 + 1.209 + /** 1.210 + * Function to calculate the height a row, for use with the "size" attribute. 1.211 + * Can't be const because GetNumberOfOptions() isn't const. 1.212 + */ 1.213 + nscoord CalcHeightOfARow(); 1.214 + 1.215 + /** 1.216 + * Function to ask whether we're currently in what might be the 1.217 + * first pass of a two-pass reflow. 1.218 + */ 1.219 + bool MightNeedSecondPass() const { 1.220 + return mMightNeedSecondPass; 1.221 + } 1.222 + 1.223 + void SetSuppressScrollbarUpdate(bool aSuppress) { 1.224 + nsHTMLScrollFrame::SetSuppressScrollbarUpdate(aSuppress); 1.225 + } 1.226 + 1.227 + /** 1.228 + * Return whether the list is in dropdown mode. 1.229 + */ 1.230 + bool IsInDropDownMode() const; 1.231 + 1.232 + /** 1.233 + * Return the number of displayed rows in the list. 1.234 + */ 1.235 + uint32_t GetNumDisplayRows() const { return mNumDisplayRows; } 1.236 + 1.237 + /** 1.238 + * Return true if the drop-down list can display more rows. 1.239 + * (always false if not in drop-down mode) 1.240 + */ 1.241 + bool GetDropdownCanGrow() const { return mDropdownCanGrow; } 1.242 + 1.243 + /** 1.244 + * Dropdowns need views 1.245 + */ 1.246 + virtual bool NeedsView() MOZ_OVERRIDE { return IsInDropDownMode(); } 1.247 + 1.248 + /** 1.249 + * Frees statics owned by this class. 1.250 + */ 1.251 + static void Shutdown(); 1.252 + 1.253 +#ifdef ACCESSIBILITY 1.254 + /** 1.255 + * Post a custom DOM event for the change, so that accessibility can 1.256 + * fire a native focus event for accessibility 1.257 + * (Some 3rd party products need to track our focus) 1.258 + */ 1.259 + void FireMenuItemActiveEvent(); // Inform assistive tech what got focused 1.260 +#endif 1.261 + 1.262 +protected: 1.263 + /** 1.264 + * Updates the selected text in a combobox and then calls FireOnChange(). 1.265 + * @note This method might destroy the frame, pres shell and other objects. 1.266 + * Returns false if calling it destroyed |this|. 1.267 + */ 1.268 + bool UpdateSelection(); 1.269 + 1.270 + /** 1.271 + * Returns whether mContent supports multiple selection. 1.272 + */ 1.273 + bool GetMultiple() const { 1.274 + return mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::multiple); 1.275 + } 1.276 + 1.277 + 1.278 + /** 1.279 + * Toggles (show/hide) the combobox dropdown menu. 1.280 + * @note This method might destroy the frame, pres shell and other objects. 1.281 + */ 1.282 + void DropDownToggleKey(nsIDOMEvent* aKeyEvent); 1.283 + 1.284 + nsresult IsOptionDisabled(int32_t anIndex, bool &aIsDisabled); 1.285 + /** 1.286 + * @note This method might destroy the frame, pres shell and other objects. 1.287 + */ 1.288 + void ScrollToFrame(mozilla::dom::HTMLOptionElement& aOptElement); 1.289 + /** 1.290 + * @note This method might destroy the frame, pres shell and other objects. 1.291 + */ 1.292 + void ScrollToIndex(int32_t anIndex); 1.293 + 1.294 + /** 1.295 + * When the user clicks on the comboboxframe to show the dropdown 1.296 + * listbox, they then have to move the mouse into the list. We don't 1.297 + * want to process those mouse events as selection events (i.e., to 1.298 + * scroll list items into view). So we ignore the events until 1.299 + * the mouse moves below our border-inner-edge, when 1.300 + * mItemSelectionStarted is set. 1.301 + * 1.302 + * @param aPoint relative to this frame 1.303 + */ 1.304 + bool IgnoreMouseEventForSelection(nsIDOMEvent* aEvent); 1.305 + 1.306 + /** 1.307 + * If the dropdown is showing and the mouse has moved below our 1.308 + * border-inner-edge, then set mItemSelectionStarted. 1.309 + */ 1.310 + void UpdateInListState(nsIDOMEvent* aEvent); 1.311 + void AdjustIndexForDisabledOpt(int32_t aStartIndex, int32_t &anNewIndex, 1.312 + int32_t aNumOptions, int32_t aDoAdjustInc, int32_t aDoAdjustIncNext); 1.313 + 1.314 + /** 1.315 + * Resets the select back to it's original default values; 1.316 + * those values as determined by the original HTML 1.317 + */ 1.318 + virtual void ResetList(bool aAllowScrolling); 1.319 + 1.320 + nsListControlFrame(nsIPresShell* aShell, nsIDocument* aDocument, nsStyleContext* aContext); 1.321 + virtual ~nsListControlFrame(); 1.322 + 1.323 + /** 1.324 + * Sets the mSelectedIndex and mOldSelectedIndex from figuring out what 1.325 + * item was selected using content 1.326 + * @param aPoint the event point, in listcontrolframe coordinates 1.327 + * @return NS_OK if it successfully found the selection 1.328 + */ 1.329 + nsresult GetIndexFromDOMEvent(nsIDOMEvent* aMouseEvent, int32_t& aCurIndex); 1.330 + 1.331 + bool CheckIfAllFramesHere(); 1.332 + bool IsLeftButton(nsIDOMEvent* aMouseEvent); 1.333 + 1.334 + // guess at a row height based on our own style. 1.335 + nscoord CalcFallbackRowHeight(float aFontSizeInflation); 1.336 + 1.337 + // CalcIntrinsicHeight computes our intrinsic height (taking the "size" 1.338 + // attribute into account). This should only be called in non-dropdown mode. 1.339 + nscoord CalcIntrinsicHeight(nscoord aHeightOfARow, int32_t aNumberOfOptions); 1.340 + 1.341 + // Dropped down stuff 1.342 + void SetComboboxItem(int32_t aIndex); 1.343 + 1.344 + /** 1.345 + * Method to reflow ourselves as a dropdown list. This differs from 1.346 + * reflow as a listbox because the criteria for needing a second 1.347 + * pass are different. This will be called from Reflow() as needed. 1.348 + */ 1.349 + nsresult ReflowAsDropdown(nsPresContext* aPresContext, 1.350 + nsHTMLReflowMetrics& aDesiredSize, 1.351 + const nsHTMLReflowState& aReflowState, 1.352 + nsReflowStatus& aStatus); 1.353 + 1.354 + // Selection 1.355 + bool SetOptionsSelectedFromFrame(int32_t aStartIndex, 1.356 + int32_t aEndIndex, 1.357 + bool aValue, 1.358 + bool aClearAll); 1.359 + bool ToggleOptionSelectedFromFrame(int32_t aIndex); 1.360 + /** 1.361 + * @note This method might destroy the frame, pres shell and other objects. 1.362 + */ 1.363 + bool SingleSelection(int32_t aClickedIndex, bool aDoToggle); 1.364 + bool ExtendedSelection(int32_t aStartIndex, int32_t aEndIndex, 1.365 + bool aClearAll); 1.366 + /** 1.367 + * @note This method might destroy the frame, pres shell and other objects. 1.368 + */ 1.369 + bool PerformSelection(int32_t aClickedIndex, bool aIsShift, 1.370 + bool aIsControl); 1.371 + /** 1.372 + * @note This method might destroy the frame, pres shell and other objects. 1.373 + */ 1.374 + bool HandleListSelection(nsIDOMEvent * aDOMEvent, int32_t selectedIndex); 1.375 + void InitSelectionRange(int32_t aClickedIndex); 1.376 + void PostHandleKeyEvent(int32_t aNewIndex, uint32_t aCharCode, 1.377 + bool aIsShift, bool aIsControlOrMeta); 1.378 + 1.379 +public: 1.380 + nsSelectsAreaFrame* GetOptionsContainer() const { 1.381 + return static_cast<nsSelectsAreaFrame*>(GetScrolledFrame()); 1.382 + } 1.383 + 1.384 +protected: 1.385 + nscoord HeightOfARow() { 1.386 + return GetOptionsContainer()->HeightOfARow(); 1.387 + } 1.388 + 1.389 + /** 1.390 + * @return how many displayable options/optgroups this frame has. 1.391 + */ 1.392 + uint32_t GetNumberOfRows(); 1.393 + 1.394 + // Data Members 1.395 + int32_t mStartSelectionIndex; 1.396 + int32_t mEndSelectionIndex; 1.397 + 1.398 + nsIComboboxControlFrame *mComboboxFrame; 1.399 + uint32_t mNumDisplayRows; 1.400 + bool mChangesSinceDragStart:1; 1.401 + bool mButtonDown:1; 1.402 + // Has the user selected a visible item since we showed the 1.403 + // dropdown? 1.404 + bool mItemSelectionStarted:1; 1.405 + 1.406 + bool mIsAllContentHere:1; 1.407 + bool mIsAllFramesHere:1; 1.408 + bool mHasBeenInitialized:1; 1.409 + bool mNeedToReset:1; 1.410 + bool mPostChildrenLoadedReset:1; 1.411 + 1.412 + //bool value for multiple discontiguous selection 1.413 + bool mControlSelectMode:1; 1.414 + 1.415 + // True if we're in the middle of a reflow and might need a second 1.416 + // pass. This only happens for auto heights. 1.417 + bool mMightNeedSecondPass:1; 1.418 + 1.419 + /** 1.420 + * Set to aPresContext->HasPendingInterrupt() at the start of Reflow. 1.421 + * Set to false at the end of DidReflow. 1.422 + */ 1.423 + bool mHasPendingInterruptAtStartOfReflow:1; 1.424 + 1.425 + // True if the drop-down can show more rows. Always false if this list 1.426 + // is not in drop-down mode. 1.427 + bool mDropdownCanGrow:1; 1.428 + 1.429 + // The last computed height we reflowed at if we're a combobox dropdown. 1.430 + // XXXbz should we be using a subclass here? Or just not worry 1.431 + // about the extra member on listboxes? 1.432 + nscoord mLastDropdownComputedHeight; 1.433 + 1.434 + // At the time of our last dropdown, the backstop color to draw in case we 1.435 + // are translucent. 1.436 + nscolor mLastDropdownBackstopColor; 1.437 + 1.438 + nsRefPtr<nsListEventListener> mEventListener; 1.439 + 1.440 + static nsListControlFrame * mFocused; 1.441 + static nsString * sIncrementalString; 1.442 + 1.443 +#ifdef DO_REFLOW_COUNTER 1.444 + int32_t mReflowId; 1.445 +#endif 1.446 + 1.447 +private: 1.448 + // for incremental typing navigation 1.449 + static nsAString& GetIncrementalString (); 1.450 + static DOMTimeStamp gLastKeyTime; 1.451 + 1.452 + class MOZ_STACK_CLASS AutoIncrementalSearchResetter 1.453 + { 1.454 + public: 1.455 + AutoIncrementalSearchResetter() : 1.456 + mCancelled(false) 1.457 + { 1.458 + } 1.459 + ~AutoIncrementalSearchResetter() 1.460 + { 1.461 + if (!mCancelled) { 1.462 + nsListControlFrame::GetIncrementalString().Truncate(); 1.463 + } 1.464 + } 1.465 + void Cancel() 1.466 + { 1.467 + mCancelled = true; 1.468 + } 1.469 + private: 1.470 + bool mCancelled; 1.471 + }; 1.472 +}; 1.473 + 1.474 +#endif /* nsListControlFrame_h___ */ 1.475 +