LCOV - code coverage report
Current view: top level - layout/forms - nsComboboxControlFrame.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 721 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 94 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : 
       6             : #include "nsComboboxControlFrame.h"
       7             : 
       8             : #include "gfxContext.h"
       9             : #include "gfxUtils.h"
      10             : #include "mozilla/gfx/2D.h"
      11             : #include "mozilla/gfx/PathHelpers.h"
      12             : #include "nsCOMPtr.h"
      13             : #include "nsFocusManager.h"
      14             : #include "nsFormControlFrame.h"
      15             : #include "nsGkAtoms.h"
      16             : #include "nsCSSAnonBoxes.h"
      17             : #include "nsHTMLParts.h"
      18             : #include "nsIFormControl.h"
      19             : #include "nsNameSpaceManager.h"
      20             : #include "nsIListControlFrame.h"
      21             : #include "nsPIDOMWindow.h"
      22             : #include "nsIPresShell.h"
      23             : #include "nsPresState.h"
      24             : #include "nsContentList.h"
      25             : #include "nsView.h"
      26             : #include "nsViewManager.h"
      27             : #include "nsIDOMEventListener.h"
      28             : #include "nsIDOMNode.h"
      29             : #include "nsISelectControlFrame.h"
      30             : #include "nsContentUtils.h"
      31             : #include "nsIDocument.h"
      32             : #include "nsIScrollableFrame.h"
      33             : #include "nsListControlFrame.h"
      34             : #include "mozilla/StyleSetHandle.h"
      35             : #include "mozilla/StyleSetHandleInlines.h"
      36             : #include "nsNodeInfoManager.h"
      37             : #include "nsContentCreatorFunctions.h"
      38             : #include "nsLayoutUtils.h"
      39             : #include "nsDisplayList.h"
      40             : #include "nsITheme.h"
      41             : #include "nsThemeConstants.h"
      42             : #include "mozilla/Likely.h"
      43             : #include <algorithm>
      44             : #include "nsTextNode.h"
      45             : #include "mozilla/AsyncEventDispatcher.h"
      46             : #include "mozilla/EventStates.h"
      47             : #include "mozilla/LookAndFeel.h"
      48             : #include "mozilla/MouseEvents.h"
      49             : #include "mozilla/Unused.h"
      50             : #include "gfx2DGlue.h"
      51             : #include "mozilla/widget/nsAutoRollup.h"
      52             : 
      53             : #ifdef XP_WIN
      54             : #define COMBOBOX_ROLLUP_CONSUME_EVENT 0
      55             : #else
      56             : #define COMBOBOX_ROLLUP_CONSUME_EVENT 1
      57             : #endif
      58             : 
      59             : using namespace mozilla;
      60             : using namespace mozilla::gfx;
      61             : 
      62             : NS_IMETHODIMP
      63           0 : nsComboboxControlFrame::RedisplayTextEvent::Run()
      64             : {
      65           0 :   if (mControlFrame)
      66           0 :     mControlFrame->HandleRedisplayTextEvent();
      67           0 :   return NS_OK;
      68             : }
      69             : 
      70             : class nsPresState;
      71             : 
      72             : #define FIX_FOR_BUG_53259
      73             : 
      74             : // Drop down list event management.
      75             : // The combo box uses the following strategy for managing the drop-down list.
      76             : // If the combo box or its arrow button is clicked on the drop-down list is displayed
      77             : // If mouse exits the combo box with the drop-down list displayed the drop-down list
      78             : // is asked to capture events
      79             : // The drop-down list will capture all events including mouse down and up and will always
      80             : // return with ListWasSelected method call regardless of whether an item in the list was
      81             : // actually selected.
      82             : // The ListWasSelected code will turn off mouse-capture for the drop-down list.
      83             : // The drop-down list does not explicitly set capture when it is in the drop-down mode.
      84             : 
      85             : 
      86             : /**
      87             :  * Helper class that listens to the combo boxes button. If the button is pressed the
      88             :  * combo box is toggled to open or close. this is used by Accessibility which presses
      89             :  * that button Programmatically.
      90             :  */
      91             : class nsComboButtonListener : public nsIDOMEventListener
      92             : {
      93             : private:
      94           0 :   virtual ~nsComboButtonListener() {}
      95             : 
      96             : public:
      97             :   NS_DECL_ISUPPORTS
      98             : 
      99           0 :   NS_IMETHOD HandleEvent(nsIDOMEvent*) override
     100             :   {
     101           0 :     mComboBox->ShowDropDown(!mComboBox->IsDroppedDown());
     102           0 :     return NS_OK;
     103             :   }
     104             : 
     105           0 :   explicit nsComboButtonListener(nsComboboxControlFrame* aCombobox)
     106           0 :   {
     107           0 :     mComboBox = aCombobox;
     108           0 :   }
     109             : 
     110             :   nsComboboxControlFrame* mComboBox;
     111             : };
     112             : 
     113           0 : NS_IMPL_ISUPPORTS(nsComboButtonListener,
     114             :                   nsIDOMEventListener)
     115             : 
     116             : // static class data member for Bug 32920
     117             : nsComboboxControlFrame* nsComboboxControlFrame::sFocused = nullptr;
     118             : 
     119             : nsComboboxControlFrame*
     120           0 : NS_NewComboboxControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, nsFrameState aStateFlags)
     121             : {
     122           0 :   nsComboboxControlFrame* it = new (aPresShell) nsComboboxControlFrame(aContext);
     123             : 
     124           0 :   if (it) {
     125             :     // set the state flags (if any are provided)
     126           0 :     it->AddStateBits(aStateFlags);
     127             :   }
     128             : 
     129           0 :   return it;
     130             : }
     131             : 
     132           0 : NS_IMPL_FRAMEARENA_HELPERS(nsComboboxControlFrame)
     133             : 
     134             : //-----------------------------------------------------------
     135             : // Reflow Debugging Macros
     136             : // These let us "see" how many reflow counts are happening
     137             : //-----------------------------------------------------------
     138             : #ifdef DO_REFLOW_COUNTER
     139             : 
     140             : #define MAX_REFLOW_CNT 1024
     141             : static int32_t gTotalReqs    = 0;;
     142             : static int32_t gTotalReflows = 0;;
     143             : static int32_t gReflowControlCntRQ[MAX_REFLOW_CNT];
     144             : static int32_t gReflowControlCnt[MAX_REFLOW_CNT];
     145             : static int32_t gReflowInx = -1;
     146             : 
     147             : #define REFLOW_COUNTER() \
     148             :   if (mReflowId > -1) \
     149             :     gReflowControlCnt[mReflowId]++;
     150             : 
     151             : #define REFLOW_COUNTER_REQUEST() \
     152             :   if (mReflowId > -1) \
     153             :     gReflowControlCntRQ[mReflowId]++;
     154             : 
     155             : #define REFLOW_COUNTER_DUMP(__desc) \
     156             :   if (mReflowId > -1) {\
     157             :     gTotalReqs    += gReflowControlCntRQ[mReflowId];\
     158             :     gTotalReflows += gReflowControlCnt[mReflowId];\
     159             :     printf("** Id:%5d %s RF: %d RQ: %d   %d/%d  %5.2f\n", \
     160             :            mReflowId, (__desc), \
     161             :            gReflowControlCnt[mReflowId], \
     162             :            gReflowControlCntRQ[mReflowId],\
     163             :            gTotalReflows, gTotalReqs, float(gTotalReflows)/float(gTotalReqs)*100.0f);\
     164             :   }
     165             : 
     166             : #define REFLOW_COUNTER_INIT() \
     167             :   if (gReflowInx < MAX_REFLOW_CNT) { \
     168             :     gReflowInx++; \
     169             :     mReflowId = gReflowInx; \
     170             :     gReflowControlCnt[mReflowId] = 0; \
     171             :     gReflowControlCntRQ[mReflowId] = 0; \
     172             :   } else { \
     173             :     mReflowId = -1; \
     174             :   }
     175             : 
     176             : // reflow messages
     177             : #define REFLOW_DEBUG_MSG(_msg1) printf((_msg1))
     178             : #define REFLOW_DEBUG_MSG2(_msg1, _msg2) printf((_msg1), (_msg2))
     179             : #define REFLOW_DEBUG_MSG3(_msg1, _msg2, _msg3) printf((_msg1), (_msg2), (_msg3))
     180             : #define REFLOW_DEBUG_MSG4(_msg1, _msg2, _msg3, _msg4) printf((_msg1), (_msg2), (_msg3), (_msg4))
     181             : 
     182             : #else //-------------
     183             : 
     184             : #define REFLOW_COUNTER_REQUEST()
     185             : #define REFLOW_COUNTER()
     186             : #define REFLOW_COUNTER_DUMP(__desc)
     187             : #define REFLOW_COUNTER_INIT()
     188             : 
     189             : #define REFLOW_DEBUG_MSG(_msg)
     190             : #define REFLOW_DEBUG_MSG2(_msg1, _msg2)
     191             : #define REFLOW_DEBUG_MSG3(_msg1, _msg2, _msg3)
     192             : #define REFLOW_DEBUG_MSG4(_msg1, _msg2, _msg3, _msg4)
     193             : 
     194             : 
     195             : #endif
     196             : 
     197             : //------------------------------------------
     198             : // This is for being VERY noisy
     199             : //------------------------------------------
     200             : #ifdef DO_VERY_NOISY
     201             : #define REFLOW_NOISY_MSG(_msg1) printf((_msg1))
     202             : #define REFLOW_NOISY_MSG2(_msg1, _msg2) printf((_msg1), (_msg2))
     203             : #define REFLOW_NOISY_MSG3(_msg1, _msg2, _msg3) printf((_msg1), (_msg2), (_msg3))
     204             : #define REFLOW_NOISY_MSG4(_msg1, _msg2, _msg3, _msg4) printf((_msg1), (_msg2), (_msg3), (_msg4))
     205             : #else
     206             : #define REFLOW_NOISY_MSG(_msg)
     207             : #define REFLOW_NOISY_MSG2(_msg1, _msg2)
     208             : #define REFLOW_NOISY_MSG3(_msg1, _msg2, _msg3)
     209             : #define REFLOW_NOISY_MSG4(_msg1, _msg2, _msg3, _msg4)
     210             : #endif
     211             : 
     212             : //------------------------------------------
     213             : // Displays value in pixels or twips
     214             : //------------------------------------------
     215             : #ifdef DO_PIXELS
     216             : #define PX(__v) __v / 15
     217             : #else
     218             : #define PX(__v) __v
     219             : #endif
     220             : 
     221             : //------------------------------------------------------
     222             : //-- Done with macros
     223             : //------------------------------------------------------
     224             : 
     225           0 : nsComboboxControlFrame::nsComboboxControlFrame(nsStyleContext* aContext)
     226             :   : nsBlockFrame(aContext, kClassID)
     227             :   , mDisplayFrame(nullptr)
     228             :   , mButtonFrame(nullptr)
     229             :   , mDropdownFrame(nullptr)
     230             :   , mListControlFrame(nullptr)
     231             :   , mDisplayISize(0)
     232             :   , mRecentSelectedIndex(NS_SKIP_NOTIFY_INDEX)
     233             :   , mDisplayedIndex(-1)
     234             :   , mLastDropDownBeforeScreenBCoord(nscoord_MIN)
     235             :   , mLastDropDownAfterScreenBCoord(nscoord_MIN)
     236             :   , mDroppedDown(false)
     237             :   , mInRedisplayText(false)
     238             :   , mDelayedShowDropDown(false)
     239           0 :   , mIsOpenInParentProcess(false)
     240             : {
     241             :   REFLOW_COUNTER_INIT()
     242           0 : }
     243             : 
     244             : //--------------------------------------------------------------
     245           0 : nsComboboxControlFrame::~nsComboboxControlFrame()
     246             : {
     247             :   REFLOW_COUNTER_DUMP("nsCCF");
     248           0 : }
     249             : 
     250             : //--------------------------------------------------------------
     251             : 
     252           0 : NS_QUERYFRAME_HEAD(nsComboboxControlFrame)
     253           0 :   NS_QUERYFRAME_ENTRY(nsComboboxControlFrame)
     254           0 :   NS_QUERYFRAME_ENTRY(nsIComboboxControlFrame)
     255           0 :   NS_QUERYFRAME_ENTRY(nsIFormControlFrame)
     256           0 :   NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
     257           0 :   NS_QUERYFRAME_ENTRY(nsISelectControlFrame)
     258           0 :   NS_QUERYFRAME_ENTRY(nsIStatefulFrame)
     259           0 : NS_QUERYFRAME_TAIL_INHERITING(nsBlockFrame)
     260             : 
     261             : #ifdef ACCESSIBILITY
     262             : a11y::AccType
     263           0 : nsComboboxControlFrame::AccessibleType()
     264             : {
     265           0 :   return a11y::eHTMLComboboxType;
     266             : }
     267             : #endif
     268             : 
     269             : void
     270           0 : nsComboboxControlFrame::SetFocus(bool aOn, bool aRepaint)
     271             : {
     272           0 :   AutoWeakFrame weakFrame(this);
     273           0 :   if (aOn) {
     274           0 :     nsListControlFrame::ComboboxFocusSet();
     275           0 :     sFocused = this;
     276           0 :     if (mDelayedShowDropDown) {
     277           0 :       ShowDropDown(true); // might destroy us
     278           0 :       if (!weakFrame.IsAlive()) {
     279           0 :         return;
     280             :       }
     281             :     }
     282             :   } else {
     283           0 :     sFocused = nullptr;
     284           0 :     mDelayedShowDropDown = false;
     285           0 :     if (mDroppedDown) {
     286           0 :       mListControlFrame->ComboboxFinish(mDisplayedIndex); // might destroy us
     287           0 :       if (!weakFrame.IsAlive()) {
     288           0 :         return;
     289             :       }
     290             :     }
     291             :     // May delete |this|.
     292           0 :     mListControlFrame->FireOnInputAndOnChange();
     293             :   }
     294             : 
     295           0 :   if (!weakFrame.IsAlive()) {
     296           0 :     return;
     297             :   }
     298             : 
     299             :   // This is needed on a temporary basis. It causes the focus
     300             :   // rect to be drawn. This is much faster than ReResolvingStyle
     301             :   // Bug 32920
     302           0 :   InvalidateFrame();
     303             : }
     304             : 
     305             : void
     306           0 : nsComboboxControlFrame::ShowPopup(bool aShowPopup)
     307             : {
     308           0 :   nsView* view = mDropdownFrame->GetView();
     309           0 :   nsViewManager* viewManager = view->GetViewManager();
     310             : 
     311           0 :   if (aShowPopup) {
     312           0 :     nsRect rect = mDropdownFrame->GetRect();
     313           0 :     rect.x = rect.y = 0;
     314           0 :     viewManager->ResizeView(view, rect);
     315           0 :     viewManager->SetViewVisibility(view, nsViewVisibility_kShow);
     316             :   } else {
     317           0 :     viewManager->SetViewVisibility(view, nsViewVisibility_kHide);
     318           0 :     nsRect emptyRect(0, 0, 0, 0);
     319           0 :     viewManager->ResizeView(view, emptyRect);
     320             :   }
     321             : 
     322             :   // fire a popup dom event if it is safe to do so
     323           0 :   nsCOMPtr<nsIPresShell> shell = PresContext()->GetPresShell();
     324           0 :   if (shell && nsContentUtils::IsSafeToRunScript()) {
     325           0 :     nsEventStatus status = nsEventStatus_eIgnore;
     326             :     WidgetMouseEvent event(true, aShowPopup ? eXULPopupShowing : eXULPopupHiding,
     327           0 :                            nullptr, WidgetMouseEvent::eReal);
     328             : 
     329           0 :     shell->HandleDOMEventWithTarget(mContent, &event, &status);
     330             :   }
     331           0 : }
     332             : 
     333             : bool
     334           0 : nsComboboxControlFrame::ShowList(bool aShowList)
     335             : {
     336           0 :   nsView* view = mDropdownFrame->GetView();
     337           0 :   if (aShowList) {
     338           0 :     NS_ASSERTION(!view->HasWidget(),
     339             :                  "We shouldn't have a widget before we need to display the popup");
     340             : 
     341             :     // Create the widget for the drop-down list
     342           0 :     view->GetViewManager()->SetViewFloating(view, true);
     343             : 
     344           0 :     nsWidgetInitData widgetData;
     345           0 :     widgetData.mWindowType  = eWindowType_popup;
     346           0 :     widgetData.mBorderStyle = eBorderStyle_default;
     347           0 :     view->CreateWidgetForPopup(&widgetData);
     348             :   } else {
     349           0 :     nsIWidget* widget = view->GetWidget();
     350           0 :     if (widget) {
     351             :       // We must do this before ShowPopup in case it destroys us (bug 813442).
     352           0 :       widget->CaptureRollupEvents(this, false);
     353             :     }
     354             :   }
     355             : 
     356           0 :   AutoWeakFrame weakFrame(this);
     357           0 :   ShowPopup(aShowList);  // might destroy us
     358           0 :   if (!weakFrame.IsAlive()) {
     359           0 :     return false;
     360             :   }
     361             : 
     362           0 :   mDroppedDown = aShowList;
     363           0 :   nsIWidget* widget = view->GetWidget();
     364           0 :   if (mDroppedDown) {
     365             :     // The listcontrol frame will call back to the nsComboboxControlFrame's
     366             :     // ListWasSelected which will stop the capture.
     367           0 :     mListControlFrame->AboutToDropDown();
     368           0 :     mListControlFrame->CaptureMouseEvents(true);
     369           0 :     if (widget) {
     370           0 :       widget->CaptureRollupEvents(this, true);
     371             :     }
     372             :   } else {
     373           0 :     if (widget) {
     374           0 :       view->DestroyWidget();
     375             :     }
     376             :   }
     377             : 
     378           0 :   return weakFrame.IsAlive();
     379             : }
     380             : 
     381             : class nsResizeDropdownAtFinalPosition final
     382             :   : public nsIReflowCallback, public Runnable
     383             : {
     384             : public:
     385           0 :   explicit nsResizeDropdownAtFinalPosition(nsComboboxControlFrame* aFrame)
     386           0 :     : mozilla::Runnable("nsResizeDropdownAtFinalPosition")
     387           0 :     , mFrame(aFrame)
     388             :   {
     389           0 :   }
     390             : 
     391             : protected:
     392           0 :   ~nsResizeDropdownAtFinalPosition()
     393           0 :   {
     394           0 :   }
     395             : 
     396             : public:
     397           0 :   virtual bool ReflowFinished() override
     398             :   {
     399           0 :     Run();
     400           0 :     NS_RELEASE_THIS();
     401           0 :     return false;
     402             :   }
     403             : 
     404           0 :   virtual void ReflowCallbackCanceled() override
     405             :   {
     406           0 :     NS_RELEASE_THIS();
     407           0 :   }
     408             : 
     409           0 :   NS_IMETHOD Run() override
     410             :   {
     411           0 :     if (mFrame.IsAlive()) {
     412           0 :       static_cast<nsComboboxControlFrame*>(mFrame.GetFrame())->
     413           0 :         AbsolutelyPositionDropDown();
     414             :     }
     415           0 :     return NS_OK;
     416             :   }
     417             : 
     418             :   WeakFrame mFrame;
     419             : };
     420             : 
     421             : void
     422           0 : nsComboboxControlFrame::ReflowDropdown(nsPresContext*  aPresContext,
     423             :                                        const ReflowInput& aReflowInput)
     424             : {
     425             :   // All we want out of it later on, really, is the block size of a row, so we
     426             :   // don't even need to cache mDropdownFrame's ascent or anything.  If we don't
     427             :   // need to reflow it, just bail out here.
     428           0 :   if (!aReflowInput.ShouldReflowAllKids() &&
     429           0 :       !NS_SUBTREE_DIRTY(mDropdownFrame)) {
     430           0 :     return;
     431             :   }
     432             : 
     433             :   // XXXbz this will, for small-block-size dropdowns, have extra space
     434             :   // on the appropriate edge for the scrollbar we don't show... but
     435             :   // that's the best we can do here for now.
     436           0 :   WritingMode wm = mDropdownFrame->GetWritingMode();
     437           0 :   LogicalSize availSize = aReflowInput.AvailableSize(wm);
     438           0 :   availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
     439             :   ReflowInput kidReflowInput(aPresContext, aReflowInput, mDropdownFrame,
     440           0 :                                    availSize);
     441             : 
     442             :   // If the dropdown's intrinsic inline size is narrower than our
     443             :   // specified inline size, then expand it out.  We want our border-box
     444             :   // inline size to end up the same as the dropdown's so account for
     445             :   // both sets of mComputedBorderPadding.
     446           0 :   nscoord forcedISize = aReflowInput.ComputedISize() +
     447           0 :     aReflowInput.ComputedLogicalBorderPadding().IStartEnd(wm) -
     448           0 :     kidReflowInput.ComputedLogicalBorderPadding().IStartEnd(wm);
     449           0 :   kidReflowInput.SetComputedISize(std::max(kidReflowInput.ComputedISize(),
     450           0 :                                          forcedISize));
     451             : 
     452             :   // ensure we start off hidden
     453           0 :   if (!mDroppedDown && GetStateBits() & NS_FRAME_FIRST_REFLOW) {
     454           0 :     nsView* view = mDropdownFrame->GetView();
     455           0 :     nsViewManager* viewManager = view->GetViewManager();
     456           0 :     viewManager->SetViewVisibility(view, nsViewVisibility_kHide);
     457           0 :     nsRect emptyRect(0, 0, 0, 0);
     458           0 :     viewManager->ResizeView(view, emptyRect);
     459             :   }
     460             : 
     461             :   // Allow the child to move/size/change-visibility its view if it's currently
     462             :   // dropped down
     463           0 :   int32_t flags = mDroppedDown ? 0
     464             :                                : NS_FRAME_NO_MOVE_FRAME |
     465             :                                  NS_FRAME_NO_VISIBILITY |
     466           0 :                                  NS_FRAME_NO_SIZE_VIEW;
     467             : 
     468             :   //XXX Can this be different from the dropdown's writing mode?
     469             :   // That would be odd!
     470             :   // Note that we don't need to pass the true frame position or container size
     471             :   // to ReflowChild or FinishReflowChild here; it will be positioned as needed
     472             :   // by AbsolutelyPositionDropDown().
     473           0 :   WritingMode outerWM = GetWritingMode();
     474           0 :   const nsSize dummyContainerSize;
     475           0 :   ReflowOutput desiredSize(aReflowInput);
     476           0 :   nsReflowStatus ignoredStatus;
     477           0 :   ReflowChild(mDropdownFrame, aPresContext, desiredSize,
     478           0 :               kidReflowInput, outerWM, LogicalPoint(outerWM),
     479           0 :               dummyContainerSize, flags, ignoredStatus);
     480             : 
     481             :    // Set the child's width and height to its desired size
     482           0 :   FinishReflowChild(mDropdownFrame, aPresContext, desiredSize, &kidReflowInput,
     483           0 :                     outerWM, LogicalPoint(outerWM), dummyContainerSize, flags);
     484             : }
     485             : 
     486             : nsPoint
     487           0 : nsComboboxControlFrame::GetCSSTransformTranslation()
     488             : {
     489           0 :   nsIFrame* frame = this;
     490           0 :   bool is3DTransform = false;
     491           0 :   Matrix transform;
     492           0 :   while (frame) {
     493             :     nsIFrame* parent;
     494           0 :     Matrix4x4 ctm = frame->GetTransformMatrix(nullptr, &parent);
     495           0 :     Matrix matrix;
     496           0 :     if (ctm.Is2D(&matrix)) {
     497           0 :       transform = transform * matrix;
     498             :     } else {
     499           0 :       is3DTransform = true;
     500           0 :       break;
     501             :     }
     502           0 :     frame = parent;
     503             :   }
     504           0 :   nsPoint translation;
     505           0 :   if (!is3DTransform && !transform.HasNonTranslation()) {
     506           0 :     nsPresContext* pc = PresContext();
     507             :     // To get the translation introduced only by transforms we subtract the
     508             :     // regular non-transform translation.
     509           0 :     nsRootPresContext* rootPC = pc->GetRootPresContext();
     510           0 :     if (rootPC) {
     511           0 :       int32_t apd = pc->AppUnitsPerDevPixel();
     512           0 :       translation.x = NSFloatPixelsToAppUnits(transform._31, apd);
     513           0 :       translation.y = NSFloatPixelsToAppUnits(transform._32, apd);
     514           0 :       translation -= GetOffsetToCrossDoc(rootPC->PresShell()->GetRootFrame());
     515             :     }
     516             :   }
     517           0 :   return translation;
     518             : }
     519             : 
     520           0 : class nsAsyncRollup : public Runnable
     521             : {
     522             : public:
     523           0 :   explicit nsAsyncRollup(nsComboboxControlFrame* aFrame)
     524           0 :     : mozilla::Runnable("nsAsyncRollup")
     525           0 :     , mFrame(aFrame)
     526             :   {
     527           0 :   }
     528           0 :   NS_IMETHOD Run() override
     529             :   {
     530           0 :     if (mFrame.IsAlive()) {
     531           0 :       static_cast<nsComboboxControlFrame*>(mFrame.GetFrame())
     532           0 :         ->RollupFromList();
     533             :     }
     534           0 :     return NS_OK;
     535             :   }
     536             :   WeakFrame mFrame;
     537             : };
     538             : 
     539           0 : class nsAsyncResize : public Runnable
     540             : {
     541             : public:
     542           0 :   explicit nsAsyncResize(nsComboboxControlFrame* aFrame)
     543           0 :     : mozilla::Runnable("nsAsyncResize")
     544           0 :     , mFrame(aFrame)
     545             :   {
     546           0 :   }
     547           0 :   NS_IMETHOD Run() override
     548             :   {
     549           0 :     if (mFrame.IsAlive()) {
     550             :       nsComboboxControlFrame* combo =
     551           0 :         static_cast<nsComboboxControlFrame*>(mFrame.GetFrame());
     552           0 :       static_cast<nsListControlFrame*>(combo->mDropdownFrame)->
     553           0 :         SetSuppressScrollbarUpdate(true);
     554           0 :       nsCOMPtr<nsIPresShell> shell = mFrame->PresContext()->PresShell();
     555           0 :       shell->FrameNeedsReflow(combo->mDropdownFrame, nsIPresShell::eResize,
     556           0 :                               NS_FRAME_IS_DIRTY);
     557           0 :       shell->FlushPendingNotifications(FlushType::Layout);
     558           0 :       if (mFrame.IsAlive()) {
     559           0 :         combo = static_cast<nsComboboxControlFrame*>(mFrame.GetFrame());
     560           0 :         static_cast<nsListControlFrame*>(combo->mDropdownFrame)->
     561           0 :           SetSuppressScrollbarUpdate(false);
     562           0 :         if (combo->mDelayedShowDropDown) {
     563           0 :           combo->ShowDropDown(true);
     564             :         }
     565             :       }
     566             :     }
     567           0 :     return NS_OK;
     568             :   }
     569             :   WeakFrame mFrame;
     570             : };
     571             : 
     572             : void
     573           0 : nsComboboxControlFrame::GetAvailableDropdownSpace(WritingMode aWM,
     574             :                                                   nscoord* aBefore,
     575             :                                                   nscoord* aAfter,
     576             :                                                   LogicalPoint* aTranslation)
     577             : {
     578           0 :   MOZ_ASSERT(!XRE_IsContentProcess());
     579             :   // Note: At first glance, it appears that you could simply get the
     580             :   // absolute bounding box for the dropdown list by first getting its
     581             :   // view, then getting the view's nsIWidget, then asking the nsIWidget
     582             :   // for its AbsoluteBounds.
     583             :   // The problem with this approach, is that the dropdown list's bcoord
     584             :   // location can change based on whether the dropdown is placed after
     585             :   // or before the display frame.  The approach taken here is to get the
     586             :   // absolute position of the display frame and use its location to
     587             :   // determine if the dropdown will go offscreen.
     588             : 
     589             :   // Normal frame geometry (eg GetOffsetTo, mRect) doesn't include transforms.
     590             :   // In the special case that our transform is only a 2D translation we
     591             :   // introduce this hack so that the dropdown will show up in the right place.
     592             :   // Use null container size when converting a vector from logical to physical.
     593           0 :   const nsSize nullContainerSize;
     594           0 :   *aTranslation = LogicalPoint(aWM, GetCSSTransformTranslation(),
     595             :                                nullContainerSize);
     596           0 :   *aBefore = 0;
     597           0 :   *aAfter = 0;
     598             : 
     599           0 :   nsRect screen = nsFormControlFrame::GetUsableScreenRect(PresContext());
     600           0 :   nsSize containerSize = screen.Size();
     601           0 :   LogicalRect logicalScreen(aWM, screen, containerSize);
     602           0 :   if (mLastDropDownAfterScreenBCoord == nscoord_MIN) {
     603           0 :     LogicalRect thisScreenRect(aWM, GetScreenRectInAppUnits(),
     604           0 :                                containerSize);
     605           0 :     mLastDropDownAfterScreenBCoord = thisScreenRect.BEnd(aWM) +
     606           0 :                                      aTranslation->B(aWM);
     607           0 :     mLastDropDownBeforeScreenBCoord = thisScreenRect.BStart(aWM) +
     608           0 :                                       aTranslation->B(aWM);
     609             :   }
     610             : 
     611             :   nscoord minBCoord;
     612           0 :   nsPresContext* pc = PresContext()->GetToplevelContentDocumentPresContext();
     613           0 :   nsIFrame* root = pc ? pc->PresShell()->GetRootFrame() : nullptr;
     614           0 :   if (root) {
     615           0 :     minBCoord = LogicalRect(aWM,
     616           0 :                             root->GetScreenRectInAppUnits(),
     617           0 :                             containerSize).BStart(aWM);
     618           0 :     if (mLastDropDownAfterScreenBCoord < minBCoord) {
     619             :       // Don't allow the drop-down to be placed before the content area.
     620           0 :       return;
     621             :     }
     622             :   } else {
     623           0 :     minBCoord = logicalScreen.BStart(aWM);
     624             :   }
     625             : 
     626           0 :   nscoord after = logicalScreen.BEnd(aWM) - mLastDropDownAfterScreenBCoord;
     627           0 :   nscoord before = mLastDropDownBeforeScreenBCoord - minBCoord;
     628             : 
     629             :   // If the difference between the space before and after is less
     630             :   // than a row-block-size, then we favor the space after.
     631           0 :   if (before >= after) {
     632           0 :     nsListControlFrame* lcf = static_cast<nsListControlFrame*>(mDropdownFrame);
     633           0 :     nscoord rowBSize = lcf->GetBSizeOfARow();
     634           0 :     if (before < after + rowBSize) {
     635           0 :       before -= rowBSize;
     636             :     }
     637             :   }
     638             : 
     639           0 :   *aAfter = after;
     640           0 :   *aBefore = before;
     641             : }
     642             : 
     643             : nsComboboxControlFrame::DropDownPositionState
     644           0 : nsComboboxControlFrame::AbsolutelyPositionDropDown()
     645             : {
     646           0 :   if (XRE_IsContentProcess()) {
     647           0 :     return eDropDownPositionSuppressed;
     648             :   }
     649             : 
     650           0 :   WritingMode wm = GetWritingMode();
     651           0 :   LogicalPoint translation(wm);
     652             :   nscoord before, after;
     653           0 :   mLastDropDownAfterScreenBCoord = nscoord_MIN;
     654           0 :   GetAvailableDropdownSpace(wm, &before, &after, &translation);
     655           0 :   if (before <= 0 && after <= 0) {
     656           0 :     if (IsDroppedDown()) {
     657             :       // Hide the view immediately to minimize flicker.
     658           0 :       nsView* view = mDropdownFrame->GetView();
     659           0 :       view->GetViewManager()->SetViewVisibility(view, nsViewVisibility_kHide);
     660           0 :       NS_DispatchToCurrentThread(new nsAsyncRollup(this));
     661             :     }
     662           0 :     return eDropDownPositionSuppressed;
     663             :   }
     664             : 
     665           0 :   LogicalSize dropdownSize = mDropdownFrame->GetLogicalSize(wm);
     666           0 :   nscoord bSize = std::max(before, after);
     667           0 :   nsListControlFrame* lcf = static_cast<nsListControlFrame*>(mDropdownFrame);
     668           0 :   if (bSize < dropdownSize.BSize(wm)) {
     669           0 :     if (lcf->GetNumDisplayRows() > 1) {
     670             :       // The drop-down doesn't fit and currently shows more than 1 row -
     671             :       // schedule a resize to show fewer rows.
     672           0 :       NS_DispatchToCurrentThread(new nsAsyncResize(this));
     673           0 :       return eDropDownPositionPendingResize;
     674             :     }
     675           0 :   } else if (bSize > (dropdownSize.BSize(wm) + lcf->GetBSizeOfARow() * 1.5) &&
     676           0 :              lcf->GetDropdownCanGrow()) {
     677             :     // The drop-down fits but there is room for at least 1.5 more rows -
     678             :     // schedule a resize to show more rows if it has more rows to show.
     679             :     // (1.5 rows for good measure to avoid any rounding issues that would
     680             :     // lead to a loop of reflow requests)
     681           0 :     NS_DispatchToCurrentThread(new nsAsyncResize(this));
     682           0 :     return eDropDownPositionPendingResize;
     683             :   }
     684             : 
     685             :   // Position the drop-down after if there is room, otherwise place it before
     686             :   // if there is room.  If there is no room for it on either side then place
     687             :   // it after (to avoid overlapping UI like the URL bar).
     688           0 :   bool b = dropdownSize.BSize(wm)<= after || dropdownSize.BSize(wm) > before;
     689           0 :   LogicalPoint dropdownPosition(wm, 0, b ? BSize(wm) : -dropdownSize.BSize(wm));
     690             : 
     691             :   // Don't position the view unless the position changed since it might cause
     692             :   // a call to NotifyGeometryChange() and an infinite loop here.
     693           0 :   nsSize containerSize = GetSize();
     694             :   const LogicalPoint currentPos =
     695           0 :     mDropdownFrame->GetLogicalPosition(containerSize);
     696           0 :   const LogicalPoint newPos = dropdownPosition + translation;
     697           0 :   if (currentPos != newPos) {
     698           0 :     mDropdownFrame->SetPosition(wm, newPos, containerSize);
     699           0 :     nsContainerFrame::PositionFrameView(mDropdownFrame);
     700             :   }
     701           0 :   return eDropDownPositionFinal;
     702             : }
     703             : 
     704             : void
     705           0 : nsComboboxControlFrame::NotifyGeometryChange()
     706             : {
     707           0 :   if (XRE_IsContentProcess()) {
     708           0 :     return;
     709             :   }
     710             : 
     711             :   // We don't need to resize if we're not dropped down since ShowDropDown
     712             :   // does that, or if we're dirty then the reflow callback does it,
     713             :   // or if we have a delayed ShowDropDown pending.
     714           0 :   if (IsDroppedDown() &&
     715           0 :       !(GetStateBits() & NS_FRAME_IS_DIRTY) &&
     716           0 :       !mDelayedShowDropDown) {
     717             :     // Async because we're likely in a middle of a scroll here so
     718             :     // frame/view positions are in flux.
     719             :     RefPtr<nsResizeDropdownAtFinalPosition> resize =
     720           0 :       new nsResizeDropdownAtFinalPosition(this);
     721           0 :     NS_DispatchToCurrentThread(resize);
     722             :   }
     723             : }
     724             : 
     725             : //----------------------------------------------------------
     726             : //
     727             : //----------------------------------------------------------
     728             : #ifdef DO_REFLOW_DEBUG
     729             : static int myCounter = 0;
     730             : 
     731             : static void printSize(char * aDesc, nscoord aSize)
     732             : {
     733             :   printf(" %s: ", aDesc);
     734             :   if (aSize == NS_UNCONSTRAINEDSIZE) {
     735             :     printf("UC");
     736             :   } else {
     737             :     printf("%d", PX(aSize));
     738             :   }
     739             : }
     740             : #endif
     741             : 
     742             : //-------------------------------------------------------------------
     743             : //-- Main Reflow for the Combobox
     744             : //-------------------------------------------------------------------
     745             : 
     746             : nscoord
     747           0 : nsComboboxControlFrame::GetIntrinsicISize(gfxContext* aRenderingContext,
     748             :                                           nsLayoutUtils::IntrinsicISizeType aType)
     749             : {
     750             :   // get the scrollbar width, we'll use this later
     751           0 :   nscoord scrollbarWidth = 0;
     752           0 :   nsPresContext* presContext = PresContext();
     753           0 :   if (mListControlFrame) {
     754           0 :     nsIScrollableFrame* scrollable = do_QueryFrame(mListControlFrame);
     755           0 :     NS_ASSERTION(scrollable, "List must be a scrollable frame");
     756           0 :     scrollbarWidth = scrollable->GetNondisappearingScrollbarWidth(
     757           0 :       presContext, aRenderingContext, GetWritingMode());
     758             :   }
     759             : 
     760           0 :   nscoord displayISize = 0;
     761           0 :   if (MOZ_LIKELY(mDisplayFrame)) {
     762           0 :     displayISize = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
     763           0 :                                                         mDisplayFrame,
     764             :                                                         aType);
     765             :   }
     766             : 
     767           0 :   if (mDropdownFrame) {
     768             :     nscoord dropdownContentISize;
     769             :     bool isUsingOverlayScrollbars =
     770           0 :       LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) != 0;
     771           0 :     if (aType == nsLayoutUtils::MIN_ISIZE) {
     772           0 :       dropdownContentISize = mDropdownFrame->GetMinISize(aRenderingContext);
     773           0 :       if (isUsingOverlayScrollbars) {
     774           0 :         dropdownContentISize += scrollbarWidth;
     775             :       }
     776             :     } else {
     777           0 :       NS_ASSERTION(aType == nsLayoutUtils::PREF_ISIZE, "Unexpected type");
     778           0 :       dropdownContentISize = mDropdownFrame->GetPrefISize(aRenderingContext);
     779           0 :       if (isUsingOverlayScrollbars) {
     780           0 :         dropdownContentISize += scrollbarWidth;
     781             :       }
     782             :     }
     783           0 :     dropdownContentISize = NSCoordSaturatingSubtract(dropdownContentISize,
     784             :                                                      scrollbarWidth,
     785             :                                                      nscoord_MAX);
     786             : 
     787           0 :     displayISize = std::max(dropdownContentISize, displayISize);
     788             :   }
     789             : 
     790             :   // add room for the dropmarker button if there is one
     791           0 :   const nsStyleDisplay* disp = StyleDisplay();
     792           0 :   if ((!IsThemed(disp) ||
     793           0 :        presContext->GetTheme()->ThemeNeedsComboboxDropmarker()) &&
     794           0 :       disp->mAppearance != NS_THEME_NONE) {
     795           0 :     displayISize += scrollbarWidth;
     796             :   }
     797             : 
     798           0 :   return displayISize;
     799             : 
     800             : }
     801             : 
     802             : nscoord
     803           0 : nsComboboxControlFrame::GetMinISize(gfxContext *aRenderingContext)
     804             : {
     805             :   nscoord minISize;
     806           0 :   DISPLAY_MIN_WIDTH(this, minISize);
     807           0 :   minISize = GetIntrinsicISize(aRenderingContext, nsLayoutUtils::MIN_ISIZE);
     808           0 :   return minISize;
     809             : }
     810             : 
     811             : nscoord
     812           0 : nsComboboxControlFrame::GetPrefISize(gfxContext *aRenderingContext)
     813             : {
     814             :   nscoord prefISize;
     815           0 :   DISPLAY_PREF_WIDTH(this, prefISize);
     816           0 :   prefISize = GetIntrinsicISize(aRenderingContext, nsLayoutUtils::PREF_ISIZE);
     817           0 :   return prefISize;
     818             : }
     819             : 
     820             : void
     821           0 : nsComboboxControlFrame::Reflow(nsPresContext*          aPresContext,
     822             :                                ReflowOutput&     aDesiredSize,
     823             :                                const ReflowInput& aReflowInput,
     824             :                                nsReflowStatus&          aStatus)
     825             : {
     826           0 :   MarkInReflow();
     827             :   // Constraints we try to satisfy:
     828             : 
     829             :   // 1) Default inline size of button is the vertical scrollbar size
     830             :   // 2) If the inline size of button is bigger than our inline size, set
     831             :   //    inline size of button to 0.
     832             :   // 3) Default block size of button is block size of display area
     833             :   // 4) Inline size of display area is whatever is left over from our
     834             :   //    inline size after allocating inline size for the button.
     835             :   // 5) Block Size of display area is GetBSizeOfARow() on the
     836             :   //    mListControlFrame.
     837             : 
     838           0 :   if (!mDisplayFrame || !mButtonFrame || !mDropdownFrame) {
     839           0 :     NS_ERROR("Why did the frame constructor allow this to happen?  Fix it!!");
     840           0 :     return;
     841             :   }
     842             : 
     843             :   // Make sure the displayed text is the same as the selected option, bug 297389.
     844           0 :   if (!mDroppedDown) {
     845           0 :     mDisplayedIndex = mListControlFrame->GetSelectedIndex();
     846             :   }
     847             :   // In dropped down mode the "selected index" is the hovered menu item,
     848             :   // we want the last selected item which is |mDisplayedIndex| in this case.
     849           0 :   RedisplayText();
     850             : 
     851             :   // First reflow our dropdown so that we know how tall we should be.
     852           0 :   ReflowDropdown(aPresContext, aReflowInput);
     853             :   RefPtr<nsResizeDropdownAtFinalPosition> resize =
     854           0 :     new nsResizeDropdownAtFinalPosition(this);
     855           0 :   if (NS_SUCCEEDED(aPresContext->PresShell()->PostReflowCallback(resize))) {
     856             :     // The reflow callback queue doesn't AddRef so we keep it alive until
     857             :     // it's released in its ReflowFinished / ReflowCallbackCanceled.
     858           0 :     Unused << resize.forget();
     859             :   }
     860             : 
     861             :   // Get the width of the vertical scrollbar.  That will be the inline
     862             :   // size of the dropdown button.
     863           0 :   WritingMode wm = aReflowInput.GetWritingMode();
     864             :   nscoord buttonISize;
     865           0 :   const nsStyleDisplay *disp = StyleDisplay();
     866           0 :   if ((IsThemed(disp) && !aPresContext->GetTheme()->ThemeNeedsComboboxDropmarker()) ||
     867           0 :       StyleDisplay()->mAppearance == NS_THEME_NONE) {
     868           0 :     buttonISize = 0;
     869             :   }
     870             :   else {
     871           0 :     nsIScrollableFrame* scrollable = do_QueryFrame(mListControlFrame);
     872           0 :     NS_ASSERTION(scrollable, "List must be a scrollable frame");
     873           0 :     buttonISize = scrollable->GetNondisappearingScrollbarWidth(
     874           0 :       PresContext(), aReflowInput.mRenderingContext, wm);
     875           0 :     if (buttonISize > aReflowInput.ComputedISize()) {
     876           0 :       buttonISize = 0;
     877             :     }
     878             :   }
     879             : 
     880           0 :   mDisplayISize = aReflowInput.ComputedISize() - buttonISize;
     881             : 
     882           0 :   nsBlockFrame::Reflow(aPresContext, aDesiredSize, aReflowInput, aStatus);
     883             : 
     884             :   // The button should occupy the same space as a scrollbar
     885           0 :   nsSize containerSize = aDesiredSize.PhysicalSize();
     886           0 :   LogicalRect buttonRect = mButtonFrame->GetLogicalRect(containerSize);
     887             : 
     888           0 :   buttonRect.IStart(wm) =
     889           0 :     aReflowInput.ComputedLogicalBorderPadding().IStartEnd(wm) +
     890           0 :     mDisplayISize -
     891           0 :     (aReflowInput.ComputedLogicalBorderPadding().IEnd(wm) -
     892           0 :      aReflowInput.ComputedLogicalPadding().IEnd(wm));
     893           0 :   buttonRect.ISize(wm) = buttonISize;
     894             : 
     895           0 :   buttonRect.BStart(wm) = this->GetLogicalUsedBorder(wm).BStart(wm);
     896           0 :   buttonRect.BSize(wm) = mDisplayFrame->BSize(wm) +
     897           0 :                          this->GetLogicalUsedPadding(wm).BStartEnd(wm);
     898             : 
     899           0 :   mButtonFrame->SetRect(buttonRect, containerSize);
     900             : 
     901           0 :   if (!aStatus.IsInlineBreakBefore() &&
     902           0 :       !aStatus.IsFullyComplete()) {
     903             :     // This frame didn't fit inside a fragmentation container.  Splitting
     904             :     // a nsComboboxControlFrame makes no sense, so we override the status here.
     905           0 :     aStatus.Reset();
     906             :   }
     907             : }
     908             : 
     909             : //--------------------------------------------------------------
     910             : 
     911             : #ifdef DEBUG_FRAME_DUMP
     912             : nsresult
     913           0 : nsComboboxControlFrame::GetFrameName(nsAString& aResult) const
     914             : {
     915           0 :   return MakeFrameName(NS_LITERAL_STRING("ComboboxControl"), aResult);
     916             : }
     917             : #endif
     918             : 
     919             : 
     920             : //----------------------------------------------------------------------
     921             : // nsIComboboxControlFrame
     922             : //----------------------------------------------------------------------
     923             : void
     924           0 : nsComboboxControlFrame::ShowDropDown(bool aDoDropDown)
     925             : {
     926           0 :   MOZ_ASSERT(!XRE_IsContentProcess());
     927           0 :   mDelayedShowDropDown = false;
     928           0 :   EventStates eventStates = mContent->AsElement()->State();
     929           0 :   if (aDoDropDown && eventStates.HasState(NS_EVENT_STATE_DISABLED)) {
     930           0 :     return;
     931             :   }
     932             : 
     933           0 :   if (!mDroppedDown && aDoDropDown) {
     934           0 :     nsFocusManager* fm = nsFocusManager::GetFocusManager();
     935           0 :     if (!fm || fm->GetFocusedContent() == GetContent()) {
     936           0 :       DropDownPositionState state = AbsolutelyPositionDropDown();
     937           0 :       if (state == eDropDownPositionFinal) {
     938           0 :         ShowList(aDoDropDown); // might destroy us
     939           0 :       } else if (state == eDropDownPositionPendingResize) {
     940             :         // Delay until after the resize reflow, see nsAsyncResize.
     941           0 :         mDelayedShowDropDown = true;
     942             :       }
     943             :     } else {
     944             :       // Delay until we get focus, see SetFocus().
     945           0 :       mDelayedShowDropDown = true;
     946           0 :     }
     947           0 :   } else if (mDroppedDown && !aDoDropDown) {
     948           0 :     ShowList(aDoDropDown); // might destroy us
     949             :   }
     950             : }
     951             : 
     952             : void
     953           0 : nsComboboxControlFrame::SetDropDown(nsIFrame* aDropDownFrame)
     954             : {
     955           0 :   mDropdownFrame = aDropDownFrame;
     956           0 :   mListControlFrame = do_QueryFrame(mDropdownFrame);
     957           0 :   if (!sFocused && nsContentUtils::IsFocusedContent(GetContent())) {
     958           0 :     sFocused = this;
     959           0 :     nsListControlFrame::ComboboxFocusSet();
     960             :   }
     961           0 : }
     962             : 
     963             : nsIFrame*
     964           0 : nsComboboxControlFrame::GetDropDown()
     965             : {
     966           0 :   return mDropdownFrame;
     967             : }
     968             : 
     969             : ///////////////////////////////////////////////////////////////
     970             : 
     971             : void
     972           0 : nsComboboxControlFrame::SetPreviewText(const nsAString& aValue)
     973             : {
     974           0 :   nsAutoString previewValue(aValue);
     975           0 :   nsContentUtils::RemoveNewlines(previewValue);
     976             : 
     977           0 :   mPreviewText = previewValue;
     978           0 :   RedisplayText();
     979           0 : }
     980             : 
     981             : NS_IMETHODIMP
     982           0 : nsComboboxControlFrame::RedisplaySelectedText()
     983             : {
     984           0 :   nsAutoScriptBlocker scriptBlocker;
     985           0 :   mDisplayedIndex = mListControlFrame->GetSelectedIndex();
     986           0 :   return RedisplayText();
     987             : }
     988             : 
     989             : 
     990             : nsresult
     991           0 : nsComboboxControlFrame::RedisplayText()
     992             : {
     993           0 :   nsString previousText(mDisplayedOptionTextOrPreview);
     994             :   // Get the text to display
     995           0 :   if (!mPreviewText.IsEmpty()) {
     996           0 :     mDisplayedOptionTextOrPreview = mPreviewText;
     997           0 :   } else if (mDisplayedIndex != -1) {
     998           0 :     mListControlFrame->GetOptionText(mDisplayedIndex, mDisplayedOptionTextOrPreview);
     999             :   } else {
    1000           0 :     mDisplayedOptionTextOrPreview.Truncate();
    1001             :   }
    1002             : 
    1003             :   REFLOW_DEBUG_MSG2("RedisplayText \"%s\"\n",
    1004             :                     NS_LossyConvertUTF16toASCII(mDisplayedOptionTextOrPreview).get());
    1005             : 
    1006             :   // Send reflow command because the new text maybe larger
    1007           0 :   nsresult rv = NS_OK;
    1008           0 :   if (mDisplayContent &&
    1009           0 :       !previousText.Equals(mDisplayedOptionTextOrPreview)) {
    1010             :     // Don't call ActuallyDisplayText(true) directly here since that
    1011             :     // could cause recursive frame construction. See bug 283117 and the comment in
    1012             :     // HandleRedisplayTextEvent() below.
    1013             : 
    1014             :     // Revoke outstanding events to avoid out-of-order events which could mean
    1015             :     // displaying the wrong text.
    1016           0 :     mRedisplayTextEvent.Revoke();
    1017             : 
    1018           0 :     NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
    1019             :                  "If we happen to run our redisplay event now, we might kill "
    1020             :                  "ourselves!");
    1021             : 
    1022           0 :     RefPtr<RedisplayTextEvent> event = new RedisplayTextEvent(this);
    1023           0 :     mRedisplayTextEvent = event;
    1024           0 :     nsContentUtils::AddScriptRunner(event);
    1025             :   }
    1026           0 :   return rv;
    1027             : }
    1028             : 
    1029             : void
    1030           0 : nsComboboxControlFrame::HandleRedisplayTextEvent()
    1031             : {
    1032             :   // First, make sure that the content model is up to date and we've
    1033             :   // constructed the frames for all our content in the right places.
    1034             :   // Otherwise they'll end up under the wrong insertion frame when we
    1035             :   // ActuallyDisplayText, since that flushes out the content sink by
    1036             :   // calling SetText on a DOM node with aNotify set to true.  See bug
    1037             :   // 289730.
    1038           0 :   AutoWeakFrame weakThis(this);
    1039           0 :   PresContext()->Document()->
    1040           0 :     FlushPendingNotifications(FlushType::ContentAndNotify);
    1041           0 :   if (!weakThis.IsAlive())
    1042           0 :     return;
    1043             : 
    1044             :   // Redirect frame insertions during this method (see GetContentInsertionFrame())
    1045             :   // so that any reframing that the frame constructor forces upon us is inserted
    1046             :   // into the correct parent (mDisplayFrame). See bug 282607.
    1047           0 :   NS_PRECONDITION(!mInRedisplayText, "Nested RedisplayText");
    1048           0 :   mInRedisplayText = true;
    1049           0 :   mRedisplayTextEvent.Forget();
    1050             : 
    1051           0 :   ActuallyDisplayText(true);
    1052             :   // XXXbz This should perhaps be eResize.  Check.
    1053           0 :   PresContext()->PresShell()->FrameNeedsReflow(mDisplayFrame,
    1054             :                                                nsIPresShell::eStyleChange,
    1055           0 :                                                NS_FRAME_IS_DIRTY);
    1056             : 
    1057           0 :   mInRedisplayText = false;
    1058             : }
    1059             : 
    1060             : void
    1061           0 : nsComboboxControlFrame::ActuallyDisplayText(bool aNotify)
    1062             : {
    1063           0 :   if (mDisplayedOptionTextOrPreview.IsEmpty()) {
    1064             :     // Have to use a non-breaking space for line-block-size calculations
    1065             :     // to be right
    1066             :     static const char16_t space = 0xA0;
    1067           0 :     mDisplayContent->SetText(&space, 1, aNotify);
    1068             :   } else {
    1069           0 :     mDisplayContent->SetText(mDisplayedOptionTextOrPreview, aNotify);
    1070             :   }
    1071           0 : }
    1072             : 
    1073             : int32_t
    1074           0 : nsComboboxControlFrame::GetIndexOfDisplayArea()
    1075             : {
    1076           0 :   return mDisplayedIndex;
    1077             : }
    1078             : 
    1079             : //----------------------------------------------------------------------
    1080             : // nsISelectControlFrame
    1081             : //----------------------------------------------------------------------
    1082             : NS_IMETHODIMP
    1083           0 : nsComboboxControlFrame::DoneAddingChildren(bool aIsDone)
    1084             : {
    1085           0 :   nsISelectControlFrame* listFrame = do_QueryFrame(mDropdownFrame);
    1086           0 :   if (!listFrame)
    1087           0 :     return NS_ERROR_FAILURE;
    1088             : 
    1089           0 :   return listFrame->DoneAddingChildren(aIsDone);
    1090             : }
    1091             : 
    1092             : NS_IMETHODIMP
    1093           0 : nsComboboxControlFrame::AddOption(int32_t aIndex)
    1094             : {
    1095           0 :   if (aIndex <= mDisplayedIndex) {
    1096           0 :     ++mDisplayedIndex;
    1097             :   }
    1098             : 
    1099           0 :   nsListControlFrame* lcf = static_cast<nsListControlFrame*>(mDropdownFrame);
    1100           0 :   return lcf->AddOption(aIndex);
    1101             : }
    1102             : 
    1103             : 
    1104             : NS_IMETHODIMP
    1105           0 : nsComboboxControlFrame::RemoveOption(int32_t aIndex)
    1106             : {
    1107           0 :   AutoWeakFrame weakThis(this);
    1108           0 :   if (mListControlFrame->GetNumberOfOptions() > 0) {
    1109           0 :     if (aIndex < mDisplayedIndex) {
    1110           0 :       --mDisplayedIndex;
    1111           0 :     } else if (aIndex == mDisplayedIndex) {
    1112           0 :       mDisplayedIndex = 0; // IE6 compat
    1113           0 :       RedisplayText();
    1114             :     }
    1115             :   }
    1116             :   else {
    1117             :     // If we removed the last option, we need to blank things out
    1118           0 :     mDisplayedIndex = -1;
    1119           0 :     RedisplayText();
    1120             :   }
    1121             : 
    1122           0 :   if (!weakThis.IsAlive())
    1123           0 :     return NS_OK;
    1124             : 
    1125           0 :   nsListControlFrame* lcf = static_cast<nsListControlFrame*>(mDropdownFrame);
    1126           0 :   return lcf->RemoveOption(aIndex);
    1127             : }
    1128             : 
    1129             : NS_IMETHODIMP
    1130           0 : nsComboboxControlFrame::OnSetSelectedIndex(int32_t aOldIndex, int32_t aNewIndex)
    1131             : {
    1132           0 :   nsAutoScriptBlocker scriptBlocker;
    1133           0 :   mDisplayedIndex = aNewIndex;
    1134           0 :   RedisplayText();
    1135           0 :   NS_ASSERTION(mDropdownFrame, "No dropdown frame!");
    1136             : 
    1137           0 :   nsISelectControlFrame* listFrame = do_QueryFrame(mDropdownFrame);
    1138           0 :   NS_ASSERTION(listFrame, "No list frame!");
    1139             : 
    1140           0 :   return listFrame->OnSetSelectedIndex(aOldIndex, aNewIndex);
    1141             : }
    1142             : 
    1143             : // End nsISelectControlFrame
    1144             : //----------------------------------------------------------------------
    1145             : 
    1146             : nsresult
    1147           0 : nsComboboxControlFrame::HandleEvent(nsPresContext* aPresContext,
    1148             :                                     WidgetGUIEvent* aEvent,
    1149             :                                     nsEventStatus* aEventStatus)
    1150             : {
    1151           0 :   NS_ENSURE_ARG_POINTER(aEventStatus);
    1152             : 
    1153           0 :   if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
    1154           0 :     return NS_OK;
    1155             :   }
    1156             : 
    1157           0 :   EventStates eventStates = mContent->AsElement()->State();
    1158           0 :   if (eventStates.HasState(NS_EVENT_STATE_DISABLED)) {
    1159           0 :     return NS_OK;
    1160             :   }
    1161             : 
    1162             : #if COMBOBOX_ROLLUP_CONSUME_EVENT == 0
    1163             :   if (aEvent->mMessage == eMouseDown) {
    1164             :     if (GetContent() == mozilla::widget::nsAutoRollup::GetLastRollup()) {
    1165             :       // This event did a Rollup on this control - prevent it from opening
    1166             :       // the dropdown again!
    1167             :       *aEventStatus = nsEventStatus_eConsumeNoDefault;
    1168             :       return NS_OK;
    1169             :     }
    1170             :   }
    1171             : #endif
    1172             : 
    1173             :   // If we have style that affects how we are selected, feed event down to
    1174             :   // nsFrame::HandleEvent so that selection takes place when appropriate.
    1175           0 :   const nsStyleUserInterface* uiStyle = StyleUserInterface();
    1176           0 :   if (uiStyle->mUserInput == StyleUserInput::None ||
    1177           0 :       uiStyle->mUserInput == StyleUserInput::Disabled) {
    1178           0 :     return nsBlockFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
    1179             :   }
    1180           0 :   return NS_OK;
    1181             : }
    1182             : 
    1183             : 
    1184             : nsresult
    1185           0 : nsComboboxControlFrame::SetFormProperty(nsIAtom* aName, const nsAString& aValue)
    1186             : {
    1187           0 :   nsIFormControlFrame* fcFrame = do_QueryFrame(mDropdownFrame);
    1188           0 :   if (!fcFrame) {
    1189           0 :     return NS_NOINTERFACE;
    1190             :   }
    1191             : 
    1192           0 :   return fcFrame->SetFormProperty(aName, aValue);
    1193             : }
    1194             : 
    1195             : nsContainerFrame*
    1196           0 : nsComboboxControlFrame::GetContentInsertionFrame() {
    1197           0 :   return mInRedisplayText ? mDisplayFrame : mDropdownFrame->GetContentInsertionFrame();
    1198             : }
    1199             : 
    1200             : void
    1201           0 : nsComboboxControlFrame::AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult)
    1202             : {
    1203           0 :   aResult.AppendElement(OwnedAnonBox(mDropdownFrame));
    1204           0 :   aResult.AppendElement(OwnedAnonBox(mDisplayFrame));
    1205           0 : }
    1206             : 
    1207             : nsresult
    1208           0 : nsComboboxControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
    1209             : {
    1210             :   // The frames used to display the combo box and the button used to popup the dropdown list
    1211             :   // are created through anonymous content. The dropdown list is not created through anonymous
    1212             :   // content because its frame is initialized specifically for the drop-down case and it is placed
    1213             :   // a special list referenced through NS_COMBO_FRAME_POPUP_LIST_INDEX to keep separate from the
    1214             :   // layout of the display and button.
    1215             :   //
    1216             :   // Note: The value attribute of the display content is set when an item is selected in the dropdown list.
    1217             :   // If the content specified below does not honor the value attribute than nothing will be displayed.
    1218             : 
    1219             :   // For now the content that is created corresponds to two input buttons. It would be better to create the
    1220             :   // tag as something other than input, but then there isn't any way to create a button frame since it
    1221             :   // isn't possible to set the display type in CSS2 to create a button frame.
    1222             : 
    1223             :     // create content used for display
    1224             :   //nsIAtom* tag = NS_Atomize("mozcombodisplay");
    1225             : 
    1226             :   // Add a child text content node for the label
    1227             : 
    1228           0 :   nsNodeInfoManager *nimgr = mContent->NodeInfo()->NodeInfoManager();
    1229             : 
    1230           0 :   mDisplayContent = new nsTextNode(nimgr);
    1231             : 
    1232             :   // set the value of the text node
    1233           0 :   mDisplayedIndex = mListControlFrame->GetSelectedIndex();
    1234           0 :   if (mDisplayedIndex != -1) {
    1235           0 :     mListControlFrame->GetOptionText(mDisplayedIndex, mDisplayedOptionTextOrPreview);
    1236             :   }
    1237           0 :   ActuallyDisplayText(false);
    1238             : 
    1239           0 :   if (!aElements.AppendElement(mDisplayContent))
    1240           0 :     return NS_ERROR_OUT_OF_MEMORY;
    1241             : 
    1242           0 :   mButtonContent = mContent->OwnerDoc()->CreateHTMLElement(nsGkAtoms::button);
    1243           0 :   if (!mButtonContent)
    1244           0 :     return NS_ERROR_OUT_OF_MEMORY;
    1245             : 
    1246             :   // make someone to listen to the button. If its pressed by someone like Accessibility
    1247             :   // then open or close the combo box.
    1248           0 :   mButtonListener = new nsComboButtonListener(this);
    1249           0 :   mButtonContent->AddEventListener(NS_LITERAL_STRING("click"), mButtonListener,
    1250           0 :                                    false, false);
    1251             : 
    1252           0 :   mButtonContent->SetAttr(kNameSpaceID_None, nsGkAtoms::type,
    1253           0 :                           NS_LITERAL_STRING("button"), false);
    1254             :   // Set tabindex="-1" so that the button is not tabbable
    1255           0 :   mButtonContent->SetAttr(kNameSpaceID_None, nsGkAtoms::tabindex,
    1256           0 :                           NS_LITERAL_STRING("-1"), false);
    1257             : 
    1258           0 :   WritingMode wm = GetWritingMode();
    1259           0 :   if (wm.IsVertical()) {
    1260           0 :     mButtonContent->SetAttr(kNameSpaceID_None, nsGkAtoms::orientation,
    1261           0 :                             wm.IsVerticalRL() ? NS_LITERAL_STRING("left")
    1262           0 :                                               : NS_LITERAL_STRING("right"),
    1263           0 :                             false);
    1264             :   }
    1265             : 
    1266           0 :   if (!aElements.AppendElement(mButtonContent))
    1267           0 :     return NS_ERROR_OUT_OF_MEMORY;
    1268             : 
    1269           0 :   return NS_OK;
    1270             : }
    1271             : 
    1272             : void
    1273           0 : nsComboboxControlFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
    1274             :                                                  uint32_t aFilter)
    1275             : {
    1276           0 :   if (mDisplayContent) {
    1277           0 :     aElements.AppendElement(mDisplayContent);
    1278             :   }
    1279             : 
    1280           0 :   if (mButtonContent) {
    1281           0 :     aElements.AppendElement(mButtonContent);
    1282             :   }
    1283           0 : }
    1284             : 
    1285             : // XXXbz this is a for-now hack.  Now that display:inline-block works,
    1286             : // need to revisit this.
    1287           0 : class nsComboboxDisplayFrame : public nsBlockFrame {
    1288             : public:
    1289           0 :   NS_DECL_FRAMEARENA_HELPERS(nsComboboxDisplayFrame)
    1290             : 
    1291           0 :   nsComboboxDisplayFrame(nsStyleContext* aContext,
    1292             :                          nsComboboxControlFrame* aComboBox)
    1293           0 :     : nsBlockFrame(aContext, kClassID)
    1294           0 :     , mComboBox(aComboBox)
    1295           0 :   {}
    1296             : 
    1297             : #ifdef DEBUG_FRAME_DUMP
    1298           0 :   nsresult GetFrameName(nsAString& aResult) const override
    1299             :   {
    1300           0 :     return MakeFrameName(NS_LITERAL_STRING("ComboboxDisplay"), aResult);
    1301             :   }
    1302             : #endif
    1303             : 
    1304           0 :   virtual bool IsFrameOfType(uint32_t aFlags) const override
    1305             :   {
    1306           0 :     return nsBlockFrame::IsFrameOfType(aFlags &
    1307           0 :       ~(nsIFrame::eReplacedContainsBlock));
    1308             :   }
    1309             : 
    1310             :   virtual void Reflow(nsPresContext*           aPresContext,
    1311             :                           ReflowOutput&     aDesiredSize,
    1312             :                           const ReflowInput& aReflowInput,
    1313             :                           nsReflowStatus&          aStatus) override;
    1314             : 
    1315             :   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
    1316             :                                 const nsRect&           aDirtyRect,
    1317             :                                 const nsDisplayListSet& aLists) override;
    1318             : 
    1319             : protected:
    1320             :   nsComboboxControlFrame* mComboBox;
    1321             : };
    1322             : 
    1323           0 : NS_IMPL_FRAMEARENA_HELPERS(nsComboboxDisplayFrame)
    1324             : 
    1325             : void
    1326           0 : nsComboboxDisplayFrame::Reflow(nsPresContext*           aPresContext,
    1327             :                                ReflowOutput&     aDesiredSize,
    1328             :                                const ReflowInput& aReflowInput,
    1329             :                                nsReflowStatus&          aStatus)
    1330             : {
    1331           0 :   ReflowInput state(aReflowInput);
    1332           0 :   if (state.ComputedBSize() == NS_INTRINSICSIZE) {
    1333             :     // Note that the only way we can have a computed block size here is
    1334             :     // if the combobox had a specified block size.  If it didn't, size
    1335             :     // based on what our rows look like, for lack of anything better.
    1336           0 :     state.SetComputedBSize(mComboBox->mListControlFrame->GetBSizeOfARow());
    1337             :   }
    1338           0 :   WritingMode wm = aReflowInput.GetWritingMode();
    1339           0 :   nscoord computedISize = mComboBox->mDisplayISize -
    1340           0 :     state.ComputedLogicalBorderPadding().IStartEnd(wm);
    1341           0 :   if (computedISize < 0) {
    1342           0 :     computedISize = 0;
    1343             :   }
    1344           0 :   state.SetComputedISize(computedISize);
    1345           0 :   nsBlockFrame::Reflow(aPresContext, aDesiredSize, state, aStatus);
    1346           0 :   aStatus.Reset(); // this type of frame can't be split
    1347           0 : }
    1348             : 
    1349             : void
    1350           0 : nsComboboxDisplayFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
    1351             :                                          const nsRect&           aDirtyRect,
    1352             :                                          const nsDisplayListSet& aLists)
    1353             : {
    1354           0 :   nsDisplayListCollection set;
    1355           0 :   nsBlockFrame::BuildDisplayList(aBuilder, aDirtyRect, set);
    1356             : 
    1357             :   // remove background items if parent frame is themed
    1358           0 :   if (mComboBox->IsThemed()) {
    1359           0 :     set.BorderBackground()->DeleteAll();
    1360             :   }
    1361             : 
    1362           0 :   set.MoveTo(aLists);
    1363           0 : }
    1364             : 
    1365             : nsIFrame*
    1366           0 : nsComboboxControlFrame::CreateFrameForDisplayNode()
    1367             : {
    1368           0 :   MOZ_ASSERT(mDisplayContent);
    1369             : 
    1370             :   // Get PresShell
    1371           0 :   nsIPresShell *shell = PresContext()->PresShell();
    1372           0 :   StyleSetHandle styleSet = shell->StyleSet();
    1373             : 
    1374             :   // create the style contexts for the anonymous block frame and text frame
    1375           0 :   RefPtr<nsStyleContext> styleContext;
    1376             :   styleContext = styleSet->
    1377           0 :     ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::mozDisplayComboboxControlFrame,
    1378           0 :                                        mStyleContext);
    1379             : 
    1380           0 :   RefPtr<nsStyleContext> textStyleContext;
    1381             :   textStyleContext =
    1382           0 :     styleSet->ResolveStyleForText(mDisplayContent, mStyleContext);
    1383             : 
    1384             :   // Start by creating our anonymous block frame
    1385           0 :   mDisplayFrame = new (shell) nsComboboxDisplayFrame(styleContext, this);
    1386           0 :   mDisplayFrame->Init(mContent, this, nullptr);
    1387             : 
    1388             :   // Create a text frame and put it inside the block frame
    1389           0 :   nsIFrame* textFrame = NS_NewTextFrame(shell, textStyleContext);
    1390             : 
    1391             :   // initialize the text frame
    1392           0 :   textFrame->Init(mDisplayContent, mDisplayFrame, nullptr);
    1393           0 :   mDisplayContent->SetPrimaryFrame(textFrame);
    1394             : 
    1395           0 :   nsFrameList textList(textFrame, textFrame);
    1396           0 :   mDisplayFrame->SetInitialChildList(kPrincipalList, textList);
    1397           0 :   return mDisplayFrame;
    1398             : }
    1399             : 
    1400             : void
    1401           0 : nsComboboxControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
    1402             : {
    1403           0 :   if (sFocused == this) {
    1404           0 :     sFocused = nullptr;
    1405             :   }
    1406             : 
    1407             :   // Revoke any pending RedisplayTextEvent
    1408           0 :   mRedisplayTextEvent.Revoke();
    1409             : 
    1410           0 :   nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), false);
    1411             : 
    1412           0 :   if (mDroppedDown) {
    1413           0 :     MOZ_ASSERT(mDropdownFrame, "mDroppedDown without frame");
    1414           0 :     nsView* view = mDropdownFrame->GetView();
    1415           0 :     MOZ_ASSERT(view);
    1416           0 :     nsIWidget* widget = view->GetWidget();
    1417           0 :     if (widget) {
    1418           0 :       widget->CaptureRollupEvents(this, false);
    1419             :     }
    1420             :   }
    1421             : 
    1422             :   // Cleanup frames in popup child list
    1423           0 :   mPopupFrames.DestroyFramesFrom(aDestructRoot);
    1424           0 :   nsContentUtils::DestroyAnonymousContent(&mDisplayContent);
    1425           0 :   nsContentUtils::DestroyAnonymousContent(&mButtonContent);
    1426           0 :   nsBlockFrame::DestroyFrom(aDestructRoot);
    1427           0 : }
    1428             : 
    1429             : const nsFrameList&
    1430           0 : nsComboboxControlFrame::GetChildList(ChildListID aListID) const
    1431             : {
    1432           0 :   if (kSelectPopupList == aListID) {
    1433           0 :     return mPopupFrames;
    1434             :   }
    1435           0 :   return nsBlockFrame::GetChildList(aListID);
    1436             : }
    1437             : 
    1438             : void
    1439           0 : nsComboboxControlFrame::GetChildLists(nsTArray<ChildList>* aLists) const
    1440             : {
    1441           0 :   nsBlockFrame::GetChildLists(aLists);
    1442           0 :   mPopupFrames.AppendIfNonempty(aLists, kSelectPopupList);
    1443           0 : }
    1444             : 
    1445             : void
    1446           0 : nsComboboxControlFrame::SetInitialChildList(ChildListID     aListID,
    1447             :                                             nsFrameList&    aChildList)
    1448             : {
    1449           0 :   if (kSelectPopupList == aListID) {
    1450           0 :     mPopupFrames.SetFrames(aChildList);
    1451             :   } else {
    1452           0 :     for (nsFrameList::Enumerator e(aChildList); !e.AtEnd(); e.Next()) {
    1453             :       nsCOMPtr<nsIFormControl> formControl =
    1454           0 :         do_QueryInterface(e.get()->GetContent());
    1455           0 :       if (formControl && formControl->ControlType() == NS_FORM_BUTTON_BUTTON) {
    1456           0 :         mButtonFrame = e.get();
    1457           0 :         break;
    1458             :       }
    1459             :     }
    1460           0 :     NS_ASSERTION(mButtonFrame, "missing button frame in initial child list");
    1461           0 :     nsBlockFrame::SetInitialChildList(aListID, aChildList);
    1462             :   }
    1463           0 : }
    1464             : 
    1465             : //----------------------------------------------------------------------
    1466             :   //nsIRollupListener
    1467             : //----------------------------------------------------------------------
    1468             : bool
    1469           0 : nsComboboxControlFrame::Rollup(uint32_t aCount, bool aFlush,
    1470             :                                const nsIntPoint* pos, nsIContent** aLastRolledUp)
    1471             : {
    1472           0 :   if (aLastRolledUp) {
    1473           0 :     *aLastRolledUp = nullptr;
    1474             :   }
    1475             : 
    1476           0 :   if (!mDroppedDown) {
    1477           0 :     return false;
    1478             :   }
    1479             : 
    1480           0 :   bool consume = !!COMBOBOX_ROLLUP_CONSUME_EVENT;
    1481           0 :   AutoWeakFrame weakFrame(this);
    1482           0 :   mListControlFrame->AboutToRollup(); // might destroy us
    1483           0 :   if (!weakFrame.IsAlive()) {
    1484           0 :     return consume;
    1485             :   }
    1486           0 :   ShowDropDown(false); // might destroy us
    1487           0 :   if (weakFrame.IsAlive()) {
    1488           0 :     mListControlFrame->CaptureMouseEvents(false);
    1489             :   }
    1490             : 
    1491           0 :   if (aFlush && weakFrame.IsAlive()) {
    1492             :     // The popup's visibility doesn't update until the minimize animation has
    1493             :     // finished, so call UpdateWidgetGeometry to update it right away.
    1494           0 :     nsViewManager* viewManager = mDropdownFrame->GetView()->GetViewManager();
    1495           0 :     viewManager->UpdateWidgetGeometry(); // might destroy us
    1496             :   }
    1497             : 
    1498           0 :   if (!weakFrame.IsAlive()) {
    1499           0 :     return consume;
    1500             :   }
    1501             : 
    1502           0 :   if (aLastRolledUp) {
    1503           0 :     *aLastRolledUp = GetContent();
    1504             :   }
    1505           0 :   return consume;
    1506             : }
    1507             : 
    1508             : nsIWidget*
    1509           0 : nsComboboxControlFrame::GetRollupWidget()
    1510             : {
    1511           0 :   nsView* view = mDropdownFrame->GetView();
    1512           0 :   MOZ_ASSERT(view);
    1513           0 :   return view->GetWidget();
    1514             : }
    1515             : 
    1516             : void
    1517           0 : nsComboboxControlFrame::RollupFromList()
    1518             : {
    1519           0 :   if (ShowList(false))
    1520           0 :     mListControlFrame->CaptureMouseEvents(false);
    1521           0 : }
    1522             : 
    1523             : int32_t
    1524           0 : nsComboboxControlFrame::UpdateRecentIndex(int32_t aIndex)
    1525             : {
    1526           0 :   int32_t index = mRecentSelectedIndex;
    1527           0 :   if (mRecentSelectedIndex == NS_SKIP_NOTIFY_INDEX || aIndex == NS_SKIP_NOTIFY_INDEX)
    1528           0 :     mRecentSelectedIndex = aIndex;
    1529           0 :   return index;
    1530             : }
    1531             : 
    1532             : class nsDisplayComboboxFocus : public nsDisplayItem {
    1533             : public:
    1534           0 :   nsDisplayComboboxFocus(nsDisplayListBuilder* aBuilder,
    1535             :                          nsComboboxControlFrame* aFrame)
    1536           0 :     : nsDisplayItem(aBuilder, aFrame) {
    1537           0 :     MOZ_COUNT_CTOR(nsDisplayComboboxFocus);
    1538           0 :   }
    1539             : #ifdef NS_BUILD_REFCNT_LOGGING
    1540           0 :   virtual ~nsDisplayComboboxFocus() {
    1541           0 :     MOZ_COUNT_DTOR(nsDisplayComboboxFocus);
    1542           0 :   }
    1543             : #endif
    1544             : 
    1545             :   virtual void Paint(nsDisplayListBuilder* aBuilder,
    1546             :                      gfxContext* aCtx) override;
    1547           0 :   NS_DISPLAY_DECL_NAME("ComboboxFocus", TYPE_COMBOBOX_FOCUS)
    1548             : };
    1549             : 
    1550           0 : void nsDisplayComboboxFocus::Paint(nsDisplayListBuilder* aBuilder,
    1551             :                                    gfxContext* aCtx)
    1552             : {
    1553           0 :   static_cast<nsComboboxControlFrame*>(mFrame)
    1554           0 :     ->PaintFocus(*aCtx->GetDrawTarget(), ToReferenceFrame());
    1555           0 : }
    1556             : 
    1557             : void
    1558           0 : nsComboboxControlFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
    1559             :                                          const nsRect&           aDirtyRect,
    1560             :                                          const nsDisplayListSet& aLists)
    1561             : {
    1562             : #ifdef NOISY
    1563             :   printf("%p paint at (%d, %d, %d, %d)\n", this,
    1564             :     aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height);
    1565             : #endif
    1566             : 
    1567           0 :   if (aBuilder->IsForEventDelivery()) {
    1568             :     // Don't allow children to receive events.
    1569             :     // REVIEW: following old GetFrameForPoint
    1570           0 :     DisplayBorderBackgroundOutline(aBuilder, aLists);
    1571             :   } else {
    1572             :     // REVIEW: Our in-flow child frames are inline-level so they will paint in our
    1573             :     // content list, so we don't need to mess with layers.
    1574           0 :     nsBlockFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
    1575             :   }
    1576             : 
    1577             :   // draw a focus indicator only when focus rings should be drawn
    1578           0 :   nsIDocument* doc = mContent->GetComposedDoc();
    1579           0 :   if (doc) {
    1580           0 :     nsPIDOMWindowOuter* window = doc->GetWindow();
    1581           0 :     if (window && window->ShouldShowFocusRing()) {
    1582           0 :       nsPresContext *presContext = PresContext();
    1583           0 :       const nsStyleDisplay *disp = StyleDisplay();
    1584           0 :       if ((!IsThemed(disp) ||
    1585           0 :            !presContext->GetTheme()->ThemeDrawsFocusForWidget(disp->mAppearance)) &&
    1586           0 :           mDisplayFrame && IsVisibleForPainting(aBuilder)) {
    1587           0 :         aLists.Content()->AppendNewToTop(
    1588           0 :           new (aBuilder) nsDisplayComboboxFocus(aBuilder, this));
    1589             :       }
    1590             :     }
    1591             :   }
    1592             : 
    1593           0 :   DisplaySelectionOverlay(aBuilder, aLists.Content());
    1594           0 : }
    1595             : 
    1596           0 : void nsComboboxControlFrame::PaintFocus(DrawTarget& aDrawTarget, nsPoint aPt)
    1597             : {
    1598             :   /* Do we need to do anything? */
    1599           0 :   EventStates eventStates = mContent->AsElement()->State();
    1600           0 :   if (eventStates.HasState(NS_EVENT_STATE_DISABLED) || sFocused != this)
    1601           0 :     return;
    1602             : 
    1603           0 :   int32_t appUnitsPerDevPixel = PresContext()->AppUnitsPerDevPixel();
    1604             : 
    1605           0 :   nsRect clipRect = mDisplayFrame->GetRect() + aPt;
    1606           0 :   aDrawTarget.PushClipRect(NSRectToSnappedRect(clipRect,
    1607             :                                                appUnitsPerDevPixel,
    1608           0 :                                                aDrawTarget));
    1609             : 
    1610             :   // REVIEW: Why does the old code paint mDisplayFrame again? We've
    1611             :   // already painted it in the children above. So clipping it here won't do
    1612             :   // us much good.
    1613             : 
    1614             :   /////////////////////
    1615             :   // draw focus
    1616             : 
    1617           0 :   StrokeOptions strokeOptions;
    1618           0 :   nsLayoutUtils::InitDashPattern(strokeOptions, NS_STYLE_BORDER_STYLE_DOTTED);
    1619           0 :   ColorPattern color(ToDeviceColor(StyleColor()->mColor));
    1620           0 :   nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
    1621           0 :   clipRect.width -= onePixel;
    1622           0 :   clipRect.height -= onePixel;
    1623           0 :   Rect r = ToRect(nsLayoutUtils::RectToGfxRect(clipRect, appUnitsPerDevPixel));
    1624           0 :   StrokeSnappedEdgesOfRect(r, aDrawTarget, color, strokeOptions);
    1625             : 
    1626           0 :   aDrawTarget.PopClip();
    1627             : }
    1628             : 
    1629             : //---------------------------------------------------------
    1630             : // gets the content (an option) by index and then set it as
    1631             : // being selected or not selected
    1632             : //---------------------------------------------------------
    1633             : NS_IMETHODIMP
    1634           0 : nsComboboxControlFrame::OnOptionSelected(int32_t aIndex, bool aSelected)
    1635             : {
    1636           0 :   if (mDroppedDown) {
    1637           0 :     nsISelectControlFrame *selectFrame = do_QueryFrame(mListControlFrame);
    1638           0 :     if (selectFrame) {
    1639           0 :       selectFrame->OnOptionSelected(aIndex, aSelected);
    1640             :     }
    1641             :   } else {
    1642           0 :     if (aSelected) {
    1643           0 :       nsAutoScriptBlocker blocker;
    1644           0 :       mDisplayedIndex = aIndex;
    1645           0 :       RedisplayText();
    1646             :     } else {
    1647           0 :       AutoWeakFrame weakFrame(this);
    1648           0 :       RedisplaySelectedText();
    1649           0 :       if (weakFrame.IsAlive()) {
    1650           0 :         FireValueChangeEvent(); // Fire after old option is unselected
    1651             :       }
    1652             :     }
    1653             :   }
    1654             : 
    1655           0 :   return NS_OK;
    1656             : }
    1657             : 
    1658           0 : void nsComboboxControlFrame::FireValueChangeEvent()
    1659             : {
    1660             :   // Fire ValueChange event to indicate data value of combo box has changed
    1661           0 :   nsContentUtils::AddScriptRunner(
    1662           0 :     new AsyncEventDispatcher(mContent, NS_LITERAL_STRING("ValueChange"), true,
    1663           0 :                              false));
    1664           0 : }
    1665             : 
    1666             : void
    1667           0 : nsComboboxControlFrame::OnContentReset()
    1668             : {
    1669           0 :   if (mListControlFrame) {
    1670           0 :     mListControlFrame->OnContentReset();
    1671             :   }
    1672           0 : }
    1673             : 
    1674             : 
    1675             : //--------------------------------------------------------
    1676             : // nsIStatefulFrame
    1677             : //--------------------------------------------------------
    1678             : NS_IMETHODIMP
    1679           0 : nsComboboxControlFrame::SaveState(nsPresState** aState)
    1680             : {
    1681           0 :   MOZ_ASSERT(!(*aState));
    1682           0 :   (*aState) = new nsPresState();
    1683           0 :   (*aState)->SetDroppedDown(mDroppedDown);
    1684           0 :   return NS_OK;
    1685             : }
    1686             : 
    1687             : NS_IMETHODIMP
    1688           0 : nsComboboxControlFrame::RestoreState(nsPresState* aState)
    1689             : {
    1690           0 :   if (!aState) {
    1691           0 :     return NS_ERROR_FAILURE;
    1692             :   }
    1693           0 :   ShowList(aState->GetDroppedDown()); // might destroy us
    1694           0 :   return NS_OK;
    1695             : }
    1696             : 
    1697             : // Append a suffix so that the state key for the combobox is different
    1698             : // from the state key the list control uses to sometimes save the scroll
    1699             : // position for the same Element
    1700             : NS_IMETHODIMP
    1701           0 : nsComboboxControlFrame::GenerateStateKey(nsIContent* aContent,
    1702             :                                         nsIDocument* aDocument,
    1703             :                                         nsACString& aKey)
    1704             : {
    1705           0 :   nsresult rv = nsContentUtils::GenerateStateKey(aContent, aDocument, aKey);
    1706           0 :   if (NS_FAILED(rv) || aKey.IsEmpty()) {
    1707           0 :     return rv;
    1708             :   }
    1709           0 :   aKey.Append("CCF");
    1710           0 :   return NS_OK;
    1711             : }
    1712             : 
    1713             : // Fennec uses a custom combobox built-in widget.
    1714             : //
    1715             : 
    1716             : /* static */
    1717             : bool
    1718           0 : nsComboboxControlFrame::ToolkitHasNativePopup()
    1719             : {
    1720             : #ifdef MOZ_USE_NATIVE_POPUP_WINDOWS
    1721             :   return true;
    1722             : #else
    1723           0 :   return false;
    1724             : #endif /* MOZ_USE_NATIVE_POPUP_WINDOWS */
    1725             : }
    1726             : 

Generated by: LCOV version 1.13