LCOV - code coverage report
Current view: directory - layout/forms - nsComboboxControlFrame.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 594 0 0.0 %
Date: 2012-06-02 Functions: 82 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Pierre Phaneuf <pp@ludusdesign.com>
      24                 :  *   Mats Palmgren <matspal@gmail.com>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : #include "nsCOMPtr.h"
      40                 : #include "nsReadableUtils.h"
      41                 : #include "nsComboboxControlFrame.h"
      42                 : #include "nsIDOMEventTarget.h"
      43                 : #include "nsFrameManager.h"
      44                 : #include "nsFormControlFrame.h"
      45                 : #include "nsGfxButtonControlFrame.h"
      46                 : #include "nsGkAtoms.h"
      47                 : #include "nsCSSAnonBoxes.h"
      48                 : #include "nsHTMLParts.h"
      49                 : #include "nsIFormControl.h"
      50                 : #include "nsINameSpaceManager.h"
      51                 : #include "nsIDOMElement.h"
      52                 : #include "nsIListControlFrame.h"
      53                 : #include "nsIDOMHTMLCollection.h" 
      54                 : #include "nsIDOMHTMLSelectElement.h" 
      55                 : #include "nsIDOMHTMLOptionElement.h" 
      56                 : #include "nsPIDOMWindow.h"
      57                 : #include "nsIPresShell.h"
      58                 : #include "nsIView.h"
      59                 : #include "nsIViewManager.h"
      60                 : #include "nsEventDispatcher.h"
      61                 : #include "nsEventListenerManager.h"
      62                 : #include "nsIDOMNode.h"
      63                 : #include "nsIPrivateDOMEvent.h"
      64                 : #include "nsISelectControlFrame.h"
      65                 : #include "nsXPCOM.h"
      66                 : #include "nsISupportsPrimitives.h"
      67                 : #include "nsIComponentManager.h"
      68                 : #include "nsContentUtils.h"
      69                 : #include "nsTextFragment.h"
      70                 : #include "nsCSSFrameConstructor.h"
      71                 : #include "nsIDocument.h"
      72                 : #include "nsINodeInfo.h"
      73                 : #include "nsIScrollableFrame.h"
      74                 : #include "nsListControlFrame.h"
      75                 : #include "nsContentCID.h"
      76                 : #ifdef ACCESSIBILITY
      77                 : #include "nsAccessibilityService.h"
      78                 : #endif
      79                 : #include "nsIServiceManager.h"
      80                 : #include "nsGUIEvent.h"
      81                 : #include "nsAutoPtr.h"
      82                 : #include "nsStyleSet.h"
      83                 : #include "nsNodeInfoManager.h"
      84                 : #include "nsContentCreatorFunctions.h"
      85                 : #include "nsLayoutUtils.h"
      86                 : #include "nsDisplayList.h"
      87                 : #include "nsITheme.h"
      88                 : #include "nsThemeConstants.h"
      89                 : #include "nsAsyncDOMEvent.h"
      90                 : #include "nsRenderingContext.h"
      91                 : #include "mozilla/Preferences.h"
      92                 : 
      93                 : using namespace mozilla;
      94                 : 
      95                 : NS_IMETHODIMP
      96               0 : nsComboboxControlFrame::RedisplayTextEvent::Run()
      97                 : {
      98               0 :   if (mControlFrame)
      99               0 :     mControlFrame->HandleRedisplayTextEvent();
     100               0 :   return NS_OK;
     101                 : }
     102                 : 
     103                 : class nsPresState;
     104                 : 
     105                 : #define FIX_FOR_BUG_53259
     106                 : 
     107                 : // Drop down list event management.
     108                 : // The combo box uses the following strategy for managing the drop-down list.
     109                 : // If the combo box or it's arrow button is clicked on the drop-down list is displayed
     110                 : // If mouse exit's the combo box with the drop-down list displayed the drop-down list
     111                 : // is asked to capture events
     112                 : // The drop-down list will capture all events including mouse down and up and will always
     113                 : // return with ListWasSelected method call regardless of whether an item in the list was
     114                 : // actually selected.
     115                 : // The ListWasSelected code will turn off mouse-capture for the drop-down list.
     116                 : // The drop-down list does not explicitly set capture when it is in the drop-down mode.
     117                 : 
     118                 : 
     119                 : //XXX: This is temporary. It simulates pseudo states by using a attribute selector on 
     120                 : 
     121                 : const PRInt32 kSizeNotSet = -1;
     122                 : 
     123                 : /**
     124                 :  * Helper class that listens to the combo boxes button. If the button is pressed the 
     125                 :  * combo box is toggled to open or close. this is used by Accessibility which presses
     126                 :  * that button Programmatically.
     127                 :  */
     128                 : class nsComboButtonListener : public nsIDOMEventListener
     129                 : {
     130                 : public:
     131                 :   NS_DECL_ISUPPORTS
     132                 : 
     133               0 :   NS_IMETHOD HandleEvent(nsIDOMEvent*)
     134                 :   {
     135               0 :     mComboBox->ShowDropDown(!mComboBox->IsDroppedDown());
     136               0 :     return NS_OK; 
     137                 :   }
     138                 : 
     139               0 :   nsComboButtonListener(nsComboboxControlFrame* aCombobox) 
     140               0 :   { 
     141               0 :     mComboBox = aCombobox; 
     142               0 :   }
     143                 : 
     144               0 :   virtual ~nsComboButtonListener() {}
     145                 : 
     146                 :   nsComboboxControlFrame* mComboBox;
     147                 : };
     148                 : 
     149               0 : NS_IMPL_ISUPPORTS1(nsComboButtonListener,
     150                 :                    nsIDOMEventListener)
     151                 : 
     152                 : // static class data member for Bug 32920
     153                 : nsComboboxControlFrame * nsComboboxControlFrame::mFocused = nsnull;
     154                 : 
     155                 : nsIFrame*
     156               0 : NS_NewComboboxControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, PRUint32 aStateFlags)
     157                 : {
     158               0 :   nsComboboxControlFrame* it = new (aPresShell) nsComboboxControlFrame(aContext);
     159                 : 
     160               0 :   if (it) {
     161                 :     // set the state flags (if any are provided)
     162               0 :     it->AddStateBits(aStateFlags);
     163                 :   }
     164                 : 
     165               0 :   return it;
     166                 : }
     167                 : 
     168               0 : NS_IMPL_FRAMEARENA_HELPERS(nsComboboxControlFrame)
     169                 : 
     170                 : namespace {
     171                 : 
     172               0 : class DestroyWidgetRunnable : public nsRunnable {
     173                 : public:
     174                 :   NS_DECL_NSIRUNNABLE
     175                 : 
     176               0 :   explicit DestroyWidgetRunnable(nsIContent* aCombobox) :
     177                 :     mCombobox(aCombobox),
     178               0 :     mWidget(GetWidget())
     179                 :   {
     180               0 :   }
     181                 : 
     182                 : private:
     183                 :   nsIWidget* GetWidget(nsIView** aOutView = nsnull) const;
     184                 : 
     185                 : private:
     186                 :   nsCOMPtr<nsIContent> mCombobox;
     187                 :   nsIWidget* mWidget;
     188                 : };
     189                 : 
     190               0 : NS_IMETHODIMP DestroyWidgetRunnable::Run()
     191                 : {
     192               0 :   nsIView* view = nsnull;
     193               0 :   nsIWidget* currentWidget = GetWidget(&view);
     194                 :   // Make sure that we are destroying the same widget as what was requested
     195                 :   // when the event was fired.
     196               0 :   if (view && mWidget && mWidget == currentWidget) {
     197               0 :     view->DestroyWidget();
     198                 :   }
     199               0 :   return NS_OK;
     200                 : }
     201                 : 
     202               0 : nsIWidget* DestroyWidgetRunnable::GetWidget(nsIView** aOutView) const
     203                 : {
     204               0 :   nsIFrame* primaryFrame = mCombobox->GetPrimaryFrame();
     205               0 :   nsIComboboxControlFrame* comboboxFrame = do_QueryFrame(primaryFrame);
     206               0 :   if (comboboxFrame) {
     207               0 :     nsIFrame* dropdown = comboboxFrame->GetDropDown();
     208               0 :     if (dropdown) {
     209               0 :       nsIView* view = dropdown->GetView();
     210               0 :       NS_ASSERTION(view, "nsComboboxControlFrame view is null");
     211               0 :       if (aOutView) {
     212               0 :         *aOutView = view;
     213                 :       }
     214               0 :       if (view) {
     215               0 :         return view->GetWidget();
     216                 :       }
     217                 :     }
     218                 :   }
     219               0 :   return nsnull;
     220                 : }
     221                 : 
     222                 : }
     223                 : 
     224                 : //-----------------------------------------------------------
     225                 : // Reflow Debugging Macros
     226                 : // These let us "see" how many reflow counts are happening
     227                 : //-----------------------------------------------------------
     228                 : #ifdef DO_REFLOW_COUNTER
     229                 : 
     230                 : #define MAX_REFLOW_CNT 1024
     231                 : static PRInt32 gTotalReqs    = 0;;
     232                 : static PRInt32 gTotalReflows = 0;;
     233                 : static PRInt32 gReflowControlCntRQ[MAX_REFLOW_CNT];
     234                 : static PRInt32 gReflowControlCnt[MAX_REFLOW_CNT];
     235                 : static PRInt32 gReflowInx = -1;
     236                 : 
     237                 : #define REFLOW_COUNTER() \
     238                 :   if (mReflowId > -1) \
     239                 :     gReflowControlCnt[mReflowId]++;
     240                 : 
     241                 : #define REFLOW_COUNTER_REQUEST() \
     242                 :   if (mReflowId > -1) \
     243                 :     gReflowControlCntRQ[mReflowId]++;
     244                 : 
     245                 : #define REFLOW_COUNTER_DUMP(__desc) \
     246                 :   if (mReflowId > -1) {\
     247                 :     gTotalReqs    += gReflowControlCntRQ[mReflowId];\
     248                 :     gTotalReflows += gReflowControlCnt[mReflowId];\
     249                 :     printf("** Id:%5d %s RF: %d RQ: %d   %d/%d  %5.2f\n", \
     250                 :            mReflowId, (__desc), \
     251                 :            gReflowControlCnt[mReflowId], \
     252                 :            gReflowControlCntRQ[mReflowId],\
     253                 :            gTotalReflows, gTotalReqs, float(gTotalReflows)/float(gTotalReqs)*100.0f);\
     254                 :   }
     255                 : 
     256                 : #define REFLOW_COUNTER_INIT() \
     257                 :   if (gReflowInx < MAX_REFLOW_CNT) { \
     258                 :     gReflowInx++; \
     259                 :     mReflowId = gReflowInx; \
     260                 :     gReflowControlCnt[mReflowId] = 0; \
     261                 :     gReflowControlCntRQ[mReflowId] = 0; \
     262                 :   } else { \
     263                 :     mReflowId = -1; \
     264                 :   }
     265                 : 
     266                 : // reflow messages
     267                 : #define REFLOW_DEBUG_MSG(_msg1) printf((_msg1))
     268                 : #define REFLOW_DEBUG_MSG2(_msg1, _msg2) printf((_msg1), (_msg2))
     269                 : #define REFLOW_DEBUG_MSG3(_msg1, _msg2, _msg3) printf((_msg1), (_msg2), (_msg3))
     270                 : #define REFLOW_DEBUG_MSG4(_msg1, _msg2, _msg3, _msg4) printf((_msg1), (_msg2), (_msg3), (_msg4))
     271                 : 
     272                 : #else //-------------
     273                 : 
     274                 : #define REFLOW_COUNTER_REQUEST() 
     275                 : #define REFLOW_COUNTER() 
     276                 : #define REFLOW_COUNTER_DUMP(__desc) 
     277                 : #define REFLOW_COUNTER_INIT() 
     278                 : 
     279                 : #define REFLOW_DEBUG_MSG(_msg) 
     280                 : #define REFLOW_DEBUG_MSG2(_msg1, _msg2) 
     281                 : #define REFLOW_DEBUG_MSG3(_msg1, _msg2, _msg3) 
     282                 : #define REFLOW_DEBUG_MSG4(_msg1, _msg2, _msg3, _msg4) 
     283                 : 
     284                 : 
     285                 : #endif
     286                 : 
     287                 : //------------------------------------------
     288                 : // This is for being VERY noisy
     289                 : //------------------------------------------
     290                 : #ifdef DO_VERY_NOISY
     291                 : #define REFLOW_NOISY_MSG(_msg1) printf((_msg1))
     292                 : #define REFLOW_NOISY_MSG2(_msg1, _msg2) printf((_msg1), (_msg2))
     293                 : #define REFLOW_NOISY_MSG3(_msg1, _msg2, _msg3) printf((_msg1), (_msg2), (_msg3))
     294                 : #define REFLOW_NOISY_MSG4(_msg1, _msg2, _msg3, _msg4) printf((_msg1), (_msg2), (_msg3), (_msg4))
     295                 : #else
     296                 : #define REFLOW_NOISY_MSG(_msg) 
     297                 : #define REFLOW_NOISY_MSG2(_msg1, _msg2) 
     298                 : #define REFLOW_NOISY_MSG3(_msg1, _msg2, _msg3) 
     299                 : #define REFLOW_NOISY_MSG4(_msg1, _msg2, _msg3, _msg4) 
     300                 : #endif
     301                 : 
     302                 : //------------------------------------------
     303                 : // Displays value in pixels or twips
     304                 : //------------------------------------------
     305                 : #ifdef DO_PIXELS
     306                 : #define PX(__v) __v / 15
     307                 : #else
     308                 : #define PX(__v) __v 
     309                 : #endif
     310                 : 
     311                 : //------------------------------------------------------
     312                 : //-- Done with macros
     313                 : //------------------------------------------------------
     314                 : 
     315               0 : nsComboboxControlFrame::nsComboboxControlFrame(nsStyleContext* aContext)
     316                 :   : nsBlockFrame(aContext),
     317               0 :     mDisplayWidth(0)
     318                 : {
     319               0 :   mListControlFrame            = nsnull;
     320               0 :   mDroppedDown                 = false;
     321               0 :   mDisplayFrame                = nsnull;
     322               0 :   mButtonFrame                 = nsnull;
     323               0 :   mDropdownFrame               = nsnull;
     324                 : 
     325               0 :   mInRedisplayText = false;
     326                 : 
     327               0 :   mRecentSelectedIndex = NS_SKIP_NOTIFY_INDEX;
     328                 : 
     329                 :   REFLOW_COUNTER_INIT()
     330               0 : }
     331                 : 
     332                 : //--------------------------------------------------------------
     333               0 : nsComboboxControlFrame::~nsComboboxControlFrame()
     334                 : {
     335                 :   REFLOW_COUNTER_DUMP("nsCCF");
     336               0 : }
     337                 : 
     338                 : //--------------------------------------------------------------
     339                 : 
     340               0 : NS_QUERYFRAME_HEAD(nsComboboxControlFrame)
     341               0 :   NS_QUERYFRAME_ENTRY(nsIComboboxControlFrame)
     342               0 :   NS_QUERYFRAME_ENTRY(nsIFormControlFrame)
     343               0 :   NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
     344               0 :   NS_QUERYFRAME_ENTRY(nsISelectControlFrame)
     345               0 :   NS_QUERYFRAME_ENTRY(nsIStatefulFrame)
     346               0 : NS_QUERYFRAME_TAIL_INHERITING(nsBlockFrame)
     347                 : 
     348                 : #ifdef ACCESSIBILITY
     349                 : already_AddRefed<nsAccessible>
     350               0 : nsComboboxControlFrame::CreateAccessible()
     351                 : {
     352               0 :   nsAccessibilityService* accService = nsIPresShell::AccService();
     353               0 :   if (accService) {
     354                 :     return accService->CreateHTMLComboboxAccessible(mContent,
     355               0 :                                                     PresContext()->PresShell());
     356                 :   }
     357                 : 
     358               0 :   return nsnull;
     359                 : }
     360                 : #endif
     361                 : 
     362                 : void 
     363               0 : nsComboboxControlFrame::SetFocus(bool aOn, bool aRepaint)
     364                 : {
     365               0 :   nsWeakFrame weakFrame(this);
     366               0 :   if (aOn) {
     367               0 :     nsListControlFrame::ComboboxFocusSet();
     368               0 :     mFocused = this;
     369                 :   } else {
     370               0 :     mFocused = nsnull;
     371               0 :     if (mDroppedDown) {
     372               0 :       mListControlFrame->ComboboxFinish(mDisplayedIndex); // might destroy us
     373               0 :       if (!weakFrame.IsAlive()) {
     374                 :         return;
     375                 :       }
     376                 :     }
     377                 :     // May delete |this|.
     378               0 :     mListControlFrame->FireOnChange();
     379                 :   }
     380                 : 
     381               0 :   if (!weakFrame.IsAlive()) {
     382                 :     return;
     383                 :   }
     384                 : 
     385                 :   // This is needed on a temporary basis. It causes the focus
     386                 :   // rect to be drawn. This is much faster than ReResolvingStyle
     387                 :   // Bug 32920
     388               0 :   Invalidate(nsRect(0,0,mRect.width,mRect.height));
     389                 : }
     390                 : 
     391                 : void
     392               0 : nsComboboxControlFrame::ShowPopup(bool aShowPopup)
     393                 : {
     394               0 :   nsIView* view = mDropdownFrame->GetView();
     395               0 :   nsIViewManager* viewManager = view->GetViewManager();
     396                 : 
     397               0 :   if (aShowPopup) {
     398               0 :     nsRect rect = mDropdownFrame->GetRect();
     399               0 :     rect.x = rect.y = 0;
     400               0 :     viewManager->ResizeView(view, rect);
     401               0 :     viewManager->SetViewVisibility(view, nsViewVisibility_kShow);
     402                 :   } else {
     403               0 :     viewManager->SetViewVisibility(view, nsViewVisibility_kHide);
     404               0 :     nsRect emptyRect(0, 0, 0, 0);
     405               0 :     viewManager->ResizeView(view, emptyRect);
     406                 :   }
     407                 : 
     408                 :   // fire a popup dom event
     409               0 :   nsEventStatus status = nsEventStatus_eIgnore;
     410                 :   nsMouseEvent event(true, aShowPopup ?
     411                 :                      NS_XUL_POPUP_SHOWING : NS_XUL_POPUP_HIDING, nsnull,
     412               0 :                      nsMouseEvent::eReal);
     413                 : 
     414               0 :   nsCOMPtr<nsIPresShell> shell = PresContext()->GetPresShell();
     415               0 :   if (shell) 
     416               0 :     shell->HandleDOMEventWithTarget(mContent, &event, &status);
     417               0 : }
     418                 : 
     419                 : bool
     420               0 : nsComboboxControlFrame::ShowList(bool aShowList)
     421                 : {
     422               0 :   nsCOMPtr<nsIPresShell> shell = PresContext()->GetPresShell();
     423                 : 
     424               0 :   nsWeakFrame weakFrame(this);
     425                 : 
     426               0 :   if (aShowList) {
     427               0 :     nsIView* view = mDropdownFrame->GetView();
     428               0 :     NS_ASSERTION(!view->HasWidget(),
     429                 :                  "We shoudldn't have a widget before we need to display the popup");
     430                 : 
     431                 :     // Create the widget for the drop-down list
     432               0 :     view->GetViewManager()->SetViewFloating(view, true);
     433                 : 
     434               0 :     nsWidgetInitData widgetData;
     435               0 :     widgetData.mWindowType  = eWindowType_popup;
     436               0 :     widgetData.mBorderStyle = eBorderStyle_default;
     437               0 :     view->CreateWidgetForPopup(&widgetData);
     438                 :   }
     439                 : 
     440               0 :   ShowPopup(aShowList);  // might destroy us
     441               0 :   if (!weakFrame.IsAlive()) {
     442               0 :     return false;
     443                 :   }
     444                 : 
     445               0 :   mDroppedDown = aShowList;
     446               0 :   if (mDroppedDown) {
     447                 :     // The listcontrol frame will call back to the nsComboboxControlFrame's
     448                 :     // ListWasSelected which will stop the capture.
     449               0 :     mListControlFrame->AboutToDropDown();
     450               0 :     mListControlFrame->CaptureMouseEvents(true);
     451                 :   }
     452                 : 
     453                 :   // XXXbz so why do we need to flush here, exactly?
     454               0 :   shell->GetDocument()->FlushPendingNotifications(Flush_Layout);
     455               0 :   if (!weakFrame.IsAlive()) {
     456               0 :     return false;
     457                 :   }
     458                 : 
     459               0 :   nsIFrame* listFrame = do_QueryFrame(mListControlFrame);
     460               0 :   if (listFrame) {
     461               0 :     nsIView* view = listFrame->GetView();
     462               0 :     NS_ASSERTION(view, "nsComboboxControlFrame view is null");
     463               0 :     if (view) {
     464               0 :       nsIWidget* widget = view->GetWidget();
     465               0 :       if (widget) {
     466               0 :         widget->CaptureRollupEvents(this, mDroppedDown, mDroppedDown);
     467                 : 
     468               0 :         if (!aShowList) {
     469                 :           nsCOMPtr<nsIRunnable> widgetDestroyer =
     470               0 :             new DestroyWidgetRunnable(GetContent());
     471               0 :           NS_DispatchToMainThread(widgetDestroyer);
     472                 :         }
     473                 :       }
     474                 :     }
     475                 :   }
     476                 : 
     477               0 :   return weakFrame.IsAlive();
     478                 : }
     479                 : 
     480                 : nsresult
     481               0 : nsComboboxControlFrame::ReflowDropdown(nsPresContext*  aPresContext, 
     482                 :                                        const nsHTMLReflowState& aReflowState)
     483                 : {
     484                 :   // All we want out of it later on, really, is the height of a row, so we
     485                 :   // don't even need to cache mDropdownFrame's ascent or anything.  If we don't
     486                 :   // need to reflow it, just bail out here.
     487               0 :   if (!aReflowState.ShouldReflowAllKids() &&
     488               0 :       !NS_SUBTREE_DIRTY(mDropdownFrame)) {
     489               0 :     return NS_OK;
     490                 :   }
     491                 : 
     492                 :   // XXXbz this will, for small-height dropdowns, have extra space on the right
     493                 :   // edge for the scrollbar we don't show... but that's the best we can do here
     494                 :   // for now.
     495               0 :   nsSize availSize(aReflowState.availableWidth, NS_UNCONSTRAINEDSIZE);
     496                 :   nsHTMLReflowState kidReflowState(aPresContext, aReflowState, mDropdownFrame,
     497               0 :                                    availSize);
     498                 : 
     499                 :   // If the dropdown's intrinsic width is narrower than our specified width,
     500                 :   // then expand it out.  We want our border-box width to end up the same as
     501                 :   // the dropdown's so account for both sets of mComputedBorderPadding.
     502               0 :   nscoord forcedWidth = aReflowState.ComputedWidth() +
     503               0 :     aReflowState.mComputedBorderPadding.LeftRight() -
     504               0 :     kidReflowState.mComputedBorderPadding.LeftRight();
     505               0 :   kidReflowState.SetComputedWidth(NS_MAX(kidReflowState.ComputedWidth(),
     506               0 :                                          forcedWidth));
     507                 : 
     508                 :   // ensure we start off hidden
     509               0 :   if (GetStateBits() & NS_FRAME_FIRST_REFLOW) {
     510               0 :     nsIView* view = mDropdownFrame->GetView();
     511               0 :     nsIViewManager* viewManager = view->GetViewManager();
     512               0 :     viewManager->SetViewVisibility(view, nsViewVisibility_kHide);
     513               0 :     nsRect emptyRect(0, 0, 0, 0);
     514               0 :     viewManager->ResizeView(view, emptyRect);
     515                 :   }
     516                 :   
     517                 :   // Allow the child to move/size/change-visibility its view if it's currently
     518                 :   // dropped down
     519               0 :   PRInt32 flags = NS_FRAME_NO_MOVE_FRAME | NS_FRAME_NO_VISIBILITY | NS_FRAME_NO_SIZE_VIEW;
     520               0 :   if (mDroppedDown) {
     521               0 :     flags = 0;
     522                 :   }
     523               0 :   nsRect rect = mDropdownFrame->GetRect();
     524               0 :   nsHTMLReflowMetrics desiredSize;
     525                 :   nsReflowStatus ignoredStatus;
     526                 :   nsresult rv = ReflowChild(mDropdownFrame, aPresContext, desiredSize,
     527                 :                             kidReflowState, rect.x, rect.y, flags,
     528               0 :                             ignoredStatus);
     529                 :  
     530                 :    // Set the child's width and height to it's desired size
     531                 :   FinishReflowChild(mDropdownFrame, aPresContext, &kidReflowState,
     532               0 :                     desiredSize, rect.x, rect.y, flags);
     533               0 :   return rv;
     534                 : }
     535                 : 
     536                 : nsPoint
     537               0 : nsComboboxControlFrame::GetCSSTransformTranslation()
     538                 : {
     539               0 :   nsIFrame* frame = this;
     540               0 :   bool is3DTransform = false;
     541               0 :   gfxMatrix transform;
     542               0 :   while (frame) {
     543                 :     nsIFrame* parent;
     544               0 :     gfx3DMatrix ctm = frame->GetTransformMatrix(nsnull, &parent);
     545               0 :     gfxMatrix matrix;
     546               0 :     if (ctm.Is2D(&matrix)) {
     547               0 :       transform = transform * matrix;
     548                 :     } else {
     549               0 :       is3DTransform = true;
     550               0 :       break;
     551                 :     }
     552               0 :     frame = parent;
     553                 :   }
     554               0 :   nsPoint translation;
     555               0 :   if (!is3DTransform && !transform.HasNonTranslation()) {
     556               0 :     nsPresContext* pc = PresContext();
     557               0 :     gfxPoint pixelTranslation = transform.GetTranslation();
     558               0 :     PRInt32 apd = pc->AppUnitsPerDevPixel();
     559               0 :     translation.x = NSFloatPixelsToAppUnits(float(pixelTranslation.x), apd);
     560               0 :     translation.y = NSFloatPixelsToAppUnits(float(pixelTranslation.y), apd);
     561                 :     // To get the translation introduced only by transforms we subtract the
     562                 :     // regular non-transform translation.
     563               0 :     nsRootPresContext* rootPC = pc->GetRootPresContext();
     564               0 :     if (rootPC) {
     565               0 :       translation -= GetOffsetToCrossDoc(rootPC->PresShell()->GetRootFrame());
     566                 :     } else {
     567               0 :       translation.x = translation.y = 0;
     568                 :     }
     569                 :   }
     570                 :   return translation;
     571                 : }
     572                 : 
     573                 : void
     574               0 : nsComboboxControlFrame::AbsolutelyPositionDropDown()
     575                 : {
     576                 :    // Position the dropdown list. It is positioned below the display frame if there is enough
     577                 :    // room on the screen to display the entire list. Otherwise it is placed above the display
     578                 :    // frame.
     579                 : 
     580                 :    // Note: As first glance, it appears that you could simply get the absolute bounding box for the
     581                 :    // dropdown list by first getting its view, then getting the view's nsIWidget, then asking the nsIWidget
     582                 :    // for it's AbsoluteBounds. The problem with this approach, is that the dropdown lists y location can
     583                 :    // change based on whether the dropdown is placed below or above the display frame.
     584                 :    // The approach, taken here is to get use the absolute position of the display frame and use it's location
     585                 :    // to determine if the dropdown will go offscreen.
     586                 : 
     587                 :   // Normal frame geometry (eg GetOffsetTo, mRect) doesn't include transforms.
     588                 :   // In the special case that our transform is only a 2D translation we
     589                 :   // introduce this hack so that the dropdown will show up in the right place.
     590               0 :   nsPoint translation = GetCSSTransformTranslation();
     591                 : 
     592                 :    // Use the height calculated for the area frame so it includes both
     593                 :    // the display and button heights.
     594               0 :   nscoord dropdownYOffset = GetRect().height;
     595               0 :   nsSize dropdownSize = mDropdownFrame->GetSize();
     596                 : 
     597               0 :   nsRect screen = nsFormControlFrame::GetUsableScreenRect(PresContext());
     598                 : 
     599                 :   // Check to see if the drop-down list will go offscreen
     600               0 :   if ((GetScreenRectInAppUnits() + translation).YMost() + dropdownSize.height > screen.YMost()) {
     601                 :     // move the dropdown list up
     602               0 :     dropdownYOffset = - (dropdownSize.height);
     603                 :   }
     604                 : 
     605               0 :   nsPoint dropdownPosition;
     606               0 :   const nsStyleVisibility* vis = GetStyleVisibility();
     607               0 :   if (vis->mDirection == NS_STYLE_DIRECTION_RTL) {
     608                 :     // Align the right edge of the drop-down with the right edge of the control.
     609               0 :     dropdownPosition.x = GetRect().width - dropdownSize.width;
     610                 :   } else {
     611               0 :     dropdownPosition.x = 0;
     612                 :   }
     613               0 :   dropdownPosition.y = dropdownYOffset; 
     614                 : 
     615               0 :   mDropdownFrame->SetPosition(dropdownPosition + translation);
     616               0 : }
     617                 : 
     618                 : //----------------------------------------------------------
     619                 : // 
     620                 : //----------------------------------------------------------
     621                 : #ifdef DO_REFLOW_DEBUG
     622                 : static int myCounter = 0;
     623                 : 
     624                 : static void printSize(char * aDesc, nscoord aSize) 
     625                 : {
     626                 :   printf(" %s: ", aDesc);
     627                 :   if (aSize == NS_UNCONSTRAINEDSIZE) {
     628                 :     printf("UC");
     629                 :   } else {
     630                 :     printf("%d", PX(aSize));
     631                 :   }
     632                 : }
     633                 : #endif
     634                 : 
     635                 : //-------------------------------------------------------------------
     636                 : //-- Main Reflow for the Combobox
     637                 : //-------------------------------------------------------------------
     638                 : 
     639                 : nscoord
     640               0 : nsComboboxControlFrame::GetIntrinsicWidth(nsRenderingContext* aRenderingContext,
     641                 :                                           nsLayoutUtils::IntrinsicWidthType aType)
     642                 : {
     643                 :   // get the scrollbar width, we'll use this later
     644               0 :   nscoord scrollbarWidth = 0;
     645               0 :   nsPresContext* presContext = PresContext();
     646               0 :   if (mListControlFrame) {
     647               0 :     nsIScrollableFrame* scrollable = do_QueryFrame(mListControlFrame);
     648               0 :     NS_ASSERTION(scrollable, "List must be a scrollable frame");
     649                 :     scrollbarWidth =
     650               0 :       scrollable->GetDesiredScrollbarSizes(presContext, aRenderingContext).LeftRight();
     651                 :   }
     652                 : 
     653               0 :   nscoord displayWidth = 0;
     654               0 :   if (NS_LIKELY(mDisplayFrame)) {
     655                 :     displayWidth = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
     656                 :                                                         mDisplayFrame,
     657               0 :                                                         aType);
     658                 :   }
     659                 : 
     660               0 :   if (mDropdownFrame) {
     661                 :     nscoord dropdownContentWidth;
     662               0 :     if (aType == nsLayoutUtils::MIN_WIDTH) {
     663               0 :       dropdownContentWidth = mDropdownFrame->GetMinWidth(aRenderingContext);
     664                 :     } else {
     665               0 :       NS_ASSERTION(aType == nsLayoutUtils::PREF_WIDTH, "Unexpected type");
     666               0 :       dropdownContentWidth = mDropdownFrame->GetPrefWidth(aRenderingContext);
     667                 :     }
     668                 :     dropdownContentWidth = NSCoordSaturatingSubtract(dropdownContentWidth, 
     669                 :                                                      scrollbarWidth,
     670               0 :                                                      nscoord_MAX);
     671                 :   
     672               0 :     displayWidth = NS_MAX(dropdownContentWidth, displayWidth);
     673                 :   }
     674                 : 
     675                 :   // add room for the dropmarker button if there is one
     676               0 :   if (!IsThemed() || presContext->GetTheme()->ThemeNeedsComboboxDropmarker())
     677               0 :     displayWidth += scrollbarWidth;
     678                 : 
     679               0 :   return displayWidth;
     680                 : 
     681                 : }
     682                 : 
     683                 : nscoord
     684               0 : nsComboboxControlFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
     685                 : {
     686                 :   nscoord minWidth;
     687               0 :   DISPLAY_MIN_WIDTH(this, minWidth);
     688               0 :   minWidth = GetIntrinsicWidth(aRenderingContext, nsLayoutUtils::MIN_WIDTH);
     689               0 :   return minWidth;
     690                 : }
     691                 : 
     692                 : nscoord
     693               0 : nsComboboxControlFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
     694                 : {
     695                 :   nscoord prefWidth;
     696               0 :   DISPLAY_PREF_WIDTH(this, prefWidth);
     697               0 :   prefWidth = GetIntrinsicWidth(aRenderingContext, nsLayoutUtils::PREF_WIDTH);
     698               0 :   return prefWidth;
     699                 : }
     700                 : 
     701                 : NS_IMETHODIMP 
     702               0 : nsComboboxControlFrame::Reflow(nsPresContext*          aPresContext, 
     703                 :                                nsHTMLReflowMetrics&     aDesiredSize,
     704                 :                                const nsHTMLReflowState& aReflowState, 
     705                 :                                nsReflowStatus&          aStatus)
     706                 : {
     707                 :   // Constraints we try to satisfy:
     708                 : 
     709                 :   // 1) Default width of button is the vertical scrollbar size
     710                 :   // 2) If the width of button is bigger than our width, set width of
     711                 :   //    button to 0.
     712                 :   // 3) Default height of button is height of display area
     713                 :   // 4) Width of display area is whatever is left over from our width after
     714                 :   //    allocating width for the button.
     715                 :   // 5) Height of display area is GetHeightOfARow() on the
     716                 :   //    mListControlFrame.
     717                 : 
     718               0 :   if (!mDisplayFrame || !mButtonFrame || !mDropdownFrame) {
     719               0 :     NS_ERROR("Why did the frame constructor allow this to happen?  Fix it!!");
     720               0 :     return NS_ERROR_UNEXPECTED;
     721                 :   }
     722                 : 
     723                 :   // Make sure the displayed text is the same as the selected option, bug 297389.
     724                 :   PRInt32 selectedIndex;
     725               0 :   nsAutoString selectedOptionText;
     726               0 :   if (!mDroppedDown) {
     727               0 :     selectedIndex = mListControlFrame->GetSelectedIndex();
     728                 :   }
     729                 :   else {
     730                 :     // In dropped down mode the "selected index" is the hovered menu item,
     731                 :     // we want the last selected item which is |mDisplayedIndex| in this case.
     732               0 :     selectedIndex = mDisplayedIndex;
     733                 :   }
     734               0 :   if (selectedIndex != -1) {
     735               0 :     mListControlFrame->GetOptionText(selectedIndex, selectedOptionText);
     736                 :   }
     737               0 :   if (mDisplayedOptionText != selectedOptionText) {
     738               0 :     RedisplayText(selectedIndex);
     739                 :   }
     740                 : 
     741                 :   // First reflow our dropdown so that we know how tall we should be.
     742               0 :   ReflowDropdown(aPresContext, aReflowState);
     743                 : 
     744                 :   // Get the width of the vertical scrollbar.  That will be the width of the
     745                 :   // dropdown button.
     746                 :   nscoord buttonWidth;
     747               0 :   const nsStyleDisplay *disp = GetStyleDisplay();
     748               0 :   if (IsThemed(disp) && !aPresContext->GetTheme()->ThemeNeedsComboboxDropmarker()) {
     749               0 :     buttonWidth = 0;
     750                 :   }
     751                 :   else {
     752               0 :     nsIScrollableFrame* scrollable = do_QueryFrame(mListControlFrame);
     753               0 :     NS_ASSERTION(scrollable, "List must be a scrollable frame");
     754                 :     buttonWidth =
     755                 :       scrollable->GetDesiredScrollbarSizes(PresContext(), 
     756               0 :                                            aReflowState.rendContext).LeftRight();
     757               0 :     if (buttonWidth > aReflowState.ComputedWidth()) {
     758               0 :       buttonWidth = 0;
     759                 :     }
     760                 :   }
     761                 : 
     762               0 :   mDisplayWidth = aReflowState.ComputedWidth() - buttonWidth;
     763                 : 
     764                 :   nsresult rv = nsBlockFrame::Reflow(aPresContext, aDesiredSize, aReflowState,
     765               0 :                                     aStatus);
     766               0 :   NS_ENSURE_SUCCESS(rv, rv);
     767                 : 
     768                 :   // Now set the correct width and height on our button.  The width we need to
     769                 :   // set always, the height only if we had an auto height.
     770               0 :   nsRect buttonRect = mButtonFrame->GetRect();
     771                 :   // If we have a non-intrinsic computed height, our kids should have sized
     772                 :   // themselves properly on their own.
     773               0 :   if (aReflowState.ComputedHeight() == NS_INTRINSICSIZE) {
     774                 :     // The display frame is going to be the right height and width at this
     775                 :     // point. Use its height as the button height.
     776               0 :     nsRect displayRect = mDisplayFrame->GetRect();
     777               0 :     buttonRect.height = displayRect.height;
     778               0 :     buttonRect.y = displayRect.y;
     779                 :   }
     780                 : #ifdef DEBUG
     781                 :   else {
     782               0 :     nscoord buttonHeight = mButtonFrame->GetSize().height;
     783               0 :     nscoord displayHeight = mDisplayFrame->GetSize().height;
     784                 : 
     785                 :     // The button and display area should be equal heights, unless the computed
     786                 :     // height on the combobox is too small to fit their borders and padding.
     787               0 :     NS_ASSERTION(buttonHeight == displayHeight ||
     788                 :                  (aReflowState.ComputedHeight() < buttonHeight &&
     789                 :                   buttonHeight ==
     790                 :                     mButtonFrame->GetUsedBorderAndPadding().TopBottom()) ||
     791                 :                  (aReflowState.ComputedHeight() < displayHeight &&
     792                 :                   displayHeight ==
     793                 :                     mDisplayFrame->GetUsedBorderAndPadding().TopBottom()),
     794                 :                  "Different heights?");
     795                 :   }
     796                 : #endif
     797                 :   
     798               0 :   if (GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
     799                 :     // Make sure the right edge of the button frame stays where it is now
     800               0 :     buttonRect.x -= buttonWidth - buttonRect.width;
     801                 :   }
     802               0 :   buttonRect.width = buttonWidth;
     803               0 :   mButtonFrame->SetRect(buttonRect);
     804                 :   
     805               0 :   return rv;
     806                 : }
     807                 : 
     808                 : //--------------------------------------------------------------
     809                 : 
     810                 : nsIAtom*
     811               0 : nsComboboxControlFrame::GetType() const
     812                 : {
     813               0 :   return nsGkAtoms::comboboxControlFrame; 
     814                 : }
     815                 : 
     816                 : #ifdef NS_DEBUG
     817                 : NS_IMETHODIMP
     818               0 : nsComboboxControlFrame::GetFrameName(nsAString& aResult) const
     819                 : {
     820               0 :   return MakeFrameName(NS_LITERAL_STRING("ComboboxControl"), aResult);
     821                 : }
     822                 : #endif
     823                 : 
     824                 : 
     825                 : //----------------------------------------------------------------------
     826                 : // nsIComboboxControlFrame
     827                 : //----------------------------------------------------------------------
     828                 : void
     829               0 : nsComboboxControlFrame::ShowDropDown(bool aDoDropDown) 
     830                 : {
     831               0 :   nsEventStates eventStates = mContent->AsElement()->State();
     832               0 :   if (eventStates.HasState(NS_EVENT_STATE_DISABLED)) {
     833               0 :     return;
     834                 :   }
     835                 : 
     836               0 :   if (!mDroppedDown && aDoDropDown) {
     837               0 :     if (mListControlFrame) {
     838               0 :       mListControlFrame->SyncViewWithFrame();
     839                 :     }
     840               0 :     ShowList(aDoDropDown); // might destroy us
     841               0 :   } else if (mDroppedDown && !aDoDropDown) {
     842               0 :     ShowList(aDoDropDown); // might destroy us
     843                 :   }
     844                 : }
     845                 : 
     846                 : void
     847               0 : nsComboboxControlFrame::SetDropDown(nsIFrame* aDropDownFrame)
     848                 : {
     849               0 :   mDropdownFrame = aDropDownFrame;
     850               0 :   mListControlFrame = do_QueryFrame(mDropdownFrame);
     851               0 : }
     852                 : 
     853                 : nsIFrame*
     854               0 : nsComboboxControlFrame::GetDropDown() 
     855                 : {
     856               0 :   return mDropdownFrame;
     857                 : }
     858                 : 
     859                 : ///////////////////////////////////////////////////////////////
     860                 : 
     861                 : NS_IMETHODIMP
     862               0 : nsComboboxControlFrame::RedisplaySelectedText()
     863                 : {
     864               0 :   nsAutoScriptBlocker scriptBlocker;
     865               0 :   return RedisplayText(mListControlFrame->GetSelectedIndex());
     866                 : }
     867                 : 
     868                 : nsresult
     869               0 : nsComboboxControlFrame::RedisplayText(PRInt32 aIndex)
     870                 : {
     871                 :   // Get the text to display
     872               0 :   if (aIndex != -1) {
     873               0 :     mListControlFrame->GetOptionText(aIndex, mDisplayedOptionText);
     874                 :   } else {
     875               0 :     mDisplayedOptionText.Truncate();
     876                 :   }
     877               0 :   mDisplayedIndex = aIndex;
     878                 : 
     879                 :   REFLOW_DEBUG_MSG2("RedisplayText \"%s\"\n",
     880                 :                     NS_LossyConvertUTF16toASCII(mDisplayedOptionText).get());
     881                 : 
     882                 :   // Send reflow command because the new text maybe larger
     883               0 :   nsresult rv = NS_OK;
     884               0 :   if (mDisplayContent) {
     885                 :     // Don't call ActuallyDisplayText(true) directly here since that
     886                 :     // could cause recursive frame construction. See bug 283117 and the comment in
     887                 :     // HandleRedisplayTextEvent() below.
     888                 : 
     889                 :     // Revoke outstanding events to avoid out-of-order events which could mean
     890                 :     // displaying the wrong text.
     891               0 :     mRedisplayTextEvent.Revoke();
     892                 : 
     893               0 :     NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
     894                 :                  "If we happen to run our redisplay event now, we might kill "
     895                 :                  "ourselves!");
     896                 : 
     897               0 :     nsRefPtr<RedisplayTextEvent> event = new RedisplayTextEvent(this);
     898               0 :     mRedisplayTextEvent = event;
     899               0 :     if (!nsContentUtils::AddScriptRunner(event))
     900               0 :       mRedisplayTextEvent.Forget();
     901                 :   }
     902               0 :   return rv;
     903                 : }
     904                 : 
     905                 : void
     906               0 : nsComboboxControlFrame::HandleRedisplayTextEvent()
     907                 : {
     908                 :   // First, make sure that the content model is up to date and we've
     909                 :   // constructed the frames for all our content in the right places.
     910                 :   // Otherwise they'll end up under the wrong insertion frame when we
     911                 :   // ActuallyDisplayText, since that flushes out the content sink by
     912                 :   // calling SetText on a DOM node with aNotify set to true.  See bug
     913                 :   // 289730.
     914               0 :   nsWeakFrame weakThis(this);
     915               0 :   PresContext()->Document()->
     916               0 :     FlushPendingNotifications(Flush_ContentAndNotify);
     917               0 :   if (!weakThis.IsAlive())
     918                 :     return;
     919                 : 
     920                 :   // Redirect frame insertions during this method (see GetContentInsertionFrame())
     921                 :   // so that any reframing that the frame constructor forces upon us is inserted
     922                 :   // into the correct parent (mDisplayFrame). See bug 282607.
     923               0 :   NS_PRECONDITION(!mInRedisplayText, "Nested RedisplayText");
     924               0 :   mInRedisplayText = true;
     925               0 :   mRedisplayTextEvent.Forget();
     926                 : 
     927               0 :   ActuallyDisplayText(true);
     928                 :   // XXXbz This should perhaps be eResize.  Check.
     929               0 :   PresContext()->PresShell()->FrameNeedsReflow(mDisplayFrame,
     930                 :                                                nsIPresShell::eStyleChange,
     931               0 :                                                NS_FRAME_IS_DIRTY);
     932                 : 
     933               0 :   mInRedisplayText = false;
     934                 : }
     935                 : 
     936                 : void
     937               0 : nsComboboxControlFrame::ActuallyDisplayText(bool aNotify)
     938                 : {
     939               0 :   if (mDisplayedOptionText.IsEmpty()) {
     940                 :     // Have to use a non-breaking space for line-height calculations
     941                 :     // to be right
     942                 :     static const PRUnichar space = 0xA0;
     943               0 :     mDisplayContent->SetText(&space, 1, aNotify);
     944                 :   } else {
     945               0 :     mDisplayContent->SetText(mDisplayedOptionText, aNotify);
     946                 :   }
     947               0 : }
     948                 : 
     949                 : PRInt32
     950               0 : nsComboboxControlFrame::GetIndexOfDisplayArea()
     951                 : {
     952               0 :   return mDisplayedIndex;
     953                 : }
     954                 : 
     955                 : //----------------------------------------------------------------------
     956                 : // nsISelectControlFrame
     957                 : //----------------------------------------------------------------------
     958                 : NS_IMETHODIMP
     959               0 : nsComboboxControlFrame::DoneAddingChildren(bool aIsDone)
     960                 : {
     961               0 :   nsISelectControlFrame* listFrame = do_QueryFrame(mDropdownFrame);
     962               0 :   if (!listFrame)
     963               0 :     return NS_ERROR_FAILURE;
     964                 : 
     965               0 :   return listFrame->DoneAddingChildren(aIsDone);
     966                 : }
     967                 : 
     968                 : NS_IMETHODIMP
     969               0 : nsComboboxControlFrame::AddOption(PRInt32 aIndex)
     970                 : {
     971               0 :   if (aIndex <= mDisplayedIndex) {
     972               0 :     ++mDisplayedIndex;
     973                 :   }
     974                 : 
     975               0 :   nsListControlFrame* lcf = static_cast<nsListControlFrame*>(mDropdownFrame);
     976               0 :   return lcf->AddOption(aIndex);
     977                 : }
     978                 :   
     979                 : 
     980                 : NS_IMETHODIMP
     981               0 : nsComboboxControlFrame::RemoveOption(PRInt32 aIndex)
     982                 : {
     983               0 :   nsWeakFrame weakThis(this);
     984               0 :   if (mListControlFrame->GetNumberOfOptions() > 0) {
     985               0 :     if (aIndex < mDisplayedIndex) {
     986               0 :       --mDisplayedIndex;
     987               0 :     } else if (aIndex == mDisplayedIndex) {
     988               0 :       mDisplayedIndex = 0; // IE6 compat
     989               0 :       RedisplayText(mDisplayedIndex);
     990                 :     }
     991                 :   }
     992                 :   else {
     993                 :     // If we removed the last option, we need to blank things out
     994               0 :     RedisplayText(-1);
     995                 :   }
     996                 : 
     997               0 :   if (!weakThis.IsAlive())
     998               0 :     return NS_OK;
     999                 : 
    1000               0 :   nsListControlFrame* lcf = static_cast<nsListControlFrame*>(mDropdownFrame);
    1001               0 :   return lcf->RemoveOption(aIndex);
    1002                 : }
    1003                 : 
    1004                 : NS_IMETHODIMP
    1005               0 : nsComboboxControlFrame::OnSetSelectedIndex(PRInt32 aOldIndex, PRInt32 aNewIndex)
    1006                 : {
    1007               0 :   nsAutoScriptBlocker scriptBlocker;
    1008               0 :   RedisplayText(aNewIndex);
    1009               0 :   NS_ASSERTION(mDropdownFrame, "No dropdown frame!");
    1010                 :   
    1011               0 :   nsISelectControlFrame* listFrame = do_QueryFrame(mDropdownFrame);
    1012               0 :   NS_ASSERTION(listFrame, "No list frame!");
    1013                 : 
    1014               0 :   return listFrame->OnSetSelectedIndex(aOldIndex, aNewIndex);
    1015                 : }
    1016                 : 
    1017                 : // End nsISelectControlFrame
    1018                 : //----------------------------------------------------------------------
    1019                 : 
    1020                 : NS_IMETHODIMP 
    1021               0 : nsComboboxControlFrame::HandleEvent(nsPresContext* aPresContext, 
    1022                 :                                        nsGUIEvent*     aEvent,
    1023                 :                                        nsEventStatus*  aEventStatus)
    1024                 : {
    1025               0 :   NS_ENSURE_ARG_POINTER(aEventStatus);
    1026                 : 
    1027               0 :   if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
    1028               0 :     return NS_OK;
    1029                 :   }
    1030                 : 
    1031               0 :   nsEventStates eventStates = mContent->AsElement()->State();
    1032               0 :   if (eventStates.HasState(NS_EVENT_STATE_DISABLED)) {
    1033               0 :     return NS_OK;
    1034                 :   }
    1035                 : 
    1036                 :   // If we have style that affects how we are selected, feed event down to
    1037                 :   // nsFrame::HandleEvent so that selection takes place when appropriate.
    1038               0 :   const nsStyleUserInterface* uiStyle = GetStyleUserInterface();
    1039               0 :   if (uiStyle->mUserInput == NS_STYLE_USER_INPUT_NONE || uiStyle->mUserInput == NS_STYLE_USER_INPUT_DISABLED)
    1040               0 :     return nsBlockFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
    1041                 :     
    1042               0 :   return NS_OK;
    1043                 : }
    1044                 : 
    1045                 : 
    1046                 : nsresult
    1047               0 : nsComboboxControlFrame::SetFormProperty(nsIAtom* aName, const nsAString& aValue)
    1048                 : {
    1049               0 :   nsIFormControlFrame* fcFrame = do_QueryFrame(mDropdownFrame);
    1050               0 :   if (!fcFrame) {
    1051               0 :     return NS_NOINTERFACE;
    1052                 :   }
    1053                 : 
    1054               0 :   return fcFrame->SetFormProperty(aName, aValue);
    1055                 : }
    1056                 : 
    1057                 : nsresult 
    1058               0 : nsComboboxControlFrame::GetFormProperty(nsIAtom* aName, nsAString& aValue) const
    1059                 : {
    1060               0 :   nsIFormControlFrame* fcFrame = do_QueryFrame(mDropdownFrame);
    1061               0 :   if (!fcFrame) {
    1062               0 :     return NS_ERROR_FAILURE;
    1063                 :   }
    1064                 : 
    1065               0 :   return fcFrame->GetFormProperty(aName, aValue);
    1066                 : }
    1067                 : 
    1068                 : nsIFrame*
    1069               0 : nsComboboxControlFrame::GetContentInsertionFrame() {
    1070               0 :   return mInRedisplayText ? mDisplayFrame : mDropdownFrame->GetContentInsertionFrame();
    1071                 : }
    1072                 : 
    1073                 : nsresult
    1074               0 : nsComboboxControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
    1075                 : {
    1076                 :   // The frames used to display the combo box and the button used to popup the dropdown list
    1077                 :   // are created through anonymous content. The dropdown list is not created through anonymous
    1078                 :   // content because it's frame is initialized specifically for the drop-down case and it is placed
    1079                 :   // a special list referenced through NS_COMBO_FRAME_POPUP_LIST_INDEX to keep separate from the
    1080                 :   // layout of the display and button. 
    1081                 :   //
    1082                 :   // Note: The value attribute of the display content is set when an item is selected in the dropdown list.
    1083                 :   // If the content specified below does not honor the value attribute than nothing will be displayed.
    1084                 : 
    1085                 :   // For now the content that is created corresponds to two input buttons. It would be better to create the
    1086                 :   // tag as something other than input, but then there isn't any way to create a button frame since it
    1087                 :   // isn't possible to set the display type in CSS2 to create a button frame.
    1088                 : 
    1089                 :     // create content used for display
    1090                 :   //nsIAtom* tag = NS_NewAtom("mozcombodisplay");
    1091                 : 
    1092                 :   // Add a child text content node for the label
    1093                 : 
    1094               0 :   nsNodeInfoManager *nimgr = mContent->NodeInfo()->NodeInfoManager();
    1095                 : 
    1096               0 :   NS_NewTextNode(getter_AddRefs(mDisplayContent), nimgr);
    1097               0 :   if (!mDisplayContent)
    1098               0 :     return NS_ERROR_OUT_OF_MEMORY;
    1099                 : 
    1100                 :   // set the value of the text node
    1101               0 :   mDisplayedIndex = mListControlFrame->GetSelectedIndex();
    1102               0 :   if (mDisplayedIndex != -1) {
    1103               0 :     mListControlFrame->GetOptionText(mDisplayedIndex, mDisplayedOptionText);
    1104                 :   }
    1105               0 :   ActuallyDisplayText(false);
    1106                 : 
    1107               0 :   if (!aElements.AppendElement(mDisplayContent))
    1108               0 :     return NS_ERROR_OUT_OF_MEMORY;
    1109                 : 
    1110               0 :   nsCOMPtr<nsINodeInfo> nodeInfo;
    1111                 :   nodeInfo = nimgr->GetNodeInfo(nsGkAtoms::button, nsnull, kNameSpaceID_XHTML,
    1112               0 :                                 nsIDOMNode::ELEMENT_NODE);
    1113                 : 
    1114                 :   // create button which drops the list down
    1115               0 :   NS_NewHTMLElement(getter_AddRefs(mButtonContent), nodeInfo.forget(),
    1116               0 :                     dom::NOT_FROM_PARSER);
    1117               0 :   if (!mButtonContent)
    1118               0 :     return NS_ERROR_OUT_OF_MEMORY;
    1119                 : 
    1120                 :   // make someone to listen to the button. If its pressed by someone like Accessibility
    1121                 :   // then open or close the combo box.
    1122               0 :   mButtonListener = new nsComboButtonListener(this);
    1123               0 :   mButtonContent->AddEventListener(NS_LITERAL_STRING("click"), mButtonListener,
    1124               0 :                                    false, false);
    1125                 : 
    1126                 :   mButtonContent->SetAttr(kNameSpaceID_None, nsGkAtoms::type,
    1127               0 :                           NS_LITERAL_STRING("button"), false);
    1128                 :   // Set tabindex="-1" so that the button is not tabbable
    1129                 :   mButtonContent->SetAttr(kNameSpaceID_None, nsGkAtoms::tabindex,
    1130               0 :                           NS_LITERAL_STRING("-1"), false);
    1131                 : 
    1132               0 :   if (!aElements.AppendElement(mButtonContent))
    1133               0 :     return NS_ERROR_OUT_OF_MEMORY;
    1134                 : 
    1135               0 :   return NS_OK;
    1136                 : }
    1137                 : 
    1138                 : void
    1139               0 : nsComboboxControlFrame::AppendAnonymousContentTo(nsBaseContentList& aElements,
    1140                 :                                                  PRUint32 aFilter)
    1141                 : {
    1142               0 :   aElements.MaybeAppendElement(mDisplayContent);
    1143               0 :   aElements.MaybeAppendElement(mButtonContent);
    1144               0 : }
    1145                 : 
    1146                 : // XXXbz this is a for-now hack.  Now that display:inline-block works,
    1147                 : // need to revisit this.
    1148               0 : class nsComboboxDisplayFrame : public nsBlockFrame {
    1149                 : public:
    1150                 :   NS_DECL_FRAMEARENA_HELPERS
    1151                 : 
    1152               0 :   nsComboboxDisplayFrame (nsStyleContext* aContext,
    1153                 :                           nsComboboxControlFrame* aComboBox)
    1154                 :     : nsBlockFrame(aContext),
    1155               0 :       mComboBox(aComboBox)
    1156               0 :   {}
    1157                 : 
    1158                 :   // Need this so that line layout knows that this block's width
    1159                 :   // depends on the available width.
    1160                 :   virtual nsIAtom* GetType() const;
    1161                 : 
    1162               0 :   virtual bool IsFrameOfType(PRUint32 aFlags) const
    1163                 :   {
    1164                 :     return nsBlockFrame::IsFrameOfType(aFlags &
    1165               0 :       ~(nsIFrame::eReplacedContainsBlock));
    1166                 :   }
    1167                 : 
    1168                 :   NS_IMETHOD Reflow(nsPresContext*           aPresContext,
    1169                 :                     nsHTMLReflowMetrics&     aDesiredSize,
    1170                 :                     const nsHTMLReflowState& aReflowState,
    1171                 :                     nsReflowStatus&          aStatus);
    1172                 : 
    1173                 :   NS_IMETHOD BuildDisplayList(nsDisplayListBuilder*   aBuilder,
    1174                 :                               const nsRect&           aDirtyRect,
    1175                 :                               const nsDisplayListSet& aLists);
    1176                 : 
    1177                 : protected:
    1178                 :   nsComboboxControlFrame* mComboBox;
    1179                 : };
    1180                 : 
    1181               0 : NS_IMPL_FRAMEARENA_HELPERS(nsComboboxDisplayFrame)
    1182                 : 
    1183                 : nsIAtom*
    1184               0 : nsComboboxDisplayFrame::GetType() const
    1185                 : {
    1186               0 :   return nsGkAtoms::comboboxDisplayFrame;
    1187                 : }
    1188                 : 
    1189                 : NS_IMETHODIMP
    1190               0 : nsComboboxDisplayFrame::Reflow(nsPresContext*           aPresContext,
    1191                 :                                nsHTMLReflowMetrics&     aDesiredSize,
    1192                 :                                const nsHTMLReflowState& aReflowState,
    1193                 :                                nsReflowStatus&          aStatus)
    1194                 : {
    1195               0 :   nsHTMLReflowState state(aReflowState);
    1196               0 :   if (state.ComputedHeight() == NS_INTRINSICSIZE) {
    1197                 :     // Note that the only way we can have a computed height here is if the
    1198                 :     // combobox had a specified height.  If it didn't, size based on what our
    1199                 :     // rows look like, for lack of anything better.
    1200               0 :     state.SetComputedHeight(mComboBox->mListControlFrame->GetHeightOfARow());
    1201                 :   }
    1202                 :   nscoord computedWidth = mComboBox->mDisplayWidth -
    1203               0 :     state.mComputedBorderPadding.LeftRight(); 
    1204               0 :   if (computedWidth < 0) {
    1205               0 :     computedWidth = 0;
    1206                 :   }
    1207               0 :   state.SetComputedWidth(computedWidth);
    1208                 : 
    1209               0 :   return nsBlockFrame::Reflow(aPresContext, aDesiredSize, state, aStatus);
    1210                 : }
    1211                 : 
    1212                 : NS_IMETHODIMP
    1213               0 : nsComboboxDisplayFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
    1214                 :                                          const nsRect&           aDirtyRect,
    1215                 :                                          const nsDisplayListSet& aLists)
    1216                 : {
    1217               0 :   nsDisplayListCollection set;
    1218               0 :   nsresult rv = nsBlockFrame::BuildDisplayList(aBuilder, aDirtyRect, set);
    1219               0 :   if (NS_FAILED(rv))
    1220               0 :     return rv;
    1221                 : 
    1222                 :   // remove background items if parent frame is themed
    1223               0 :   if (mComboBox->IsThemed()) {
    1224               0 :     set.BorderBackground()->DeleteAll();
    1225                 :   }
    1226                 : 
    1227               0 :   set.MoveTo(aLists);
    1228                 : 
    1229               0 :   return NS_OK;
    1230                 : }
    1231                 : 
    1232                 : nsIFrame*
    1233               0 : nsComboboxControlFrame::CreateFrameFor(nsIContent*      aContent)
    1234                 : { 
    1235               0 :   NS_PRECONDITION(nsnull != aContent, "null ptr");
    1236                 : 
    1237               0 :   NS_ASSERTION(mDisplayContent, "mDisplayContent can't be null!");
    1238                 : 
    1239               0 :   if (mDisplayContent != aContent) {
    1240                 :     // We only handle the frames for mDisplayContent here
    1241               0 :     return nsnull;
    1242                 :   }
    1243                 :   
    1244                 :   // Get PresShell
    1245               0 :   nsIPresShell *shell = PresContext()->PresShell();
    1246               0 :   nsStyleSet *styleSet = shell->StyleSet();
    1247                 : 
    1248                 :   // create the style contexts for the anonymous block frame and text frame
    1249               0 :   nsRefPtr<nsStyleContext> styleContext;
    1250                 :   styleContext = styleSet->
    1251                 :     ResolveAnonymousBoxStyle(nsCSSAnonBoxes::mozDisplayComboboxControlFrame,
    1252               0 :                              mStyleContext);
    1253               0 :   if (NS_UNLIKELY(!styleContext)) {
    1254               0 :     return nsnull;
    1255                 :   }
    1256                 : 
    1257               0 :   nsRefPtr<nsStyleContext> textStyleContext;
    1258               0 :   textStyleContext = styleSet->ResolveStyleForNonElement(mStyleContext);
    1259               0 :   if (NS_UNLIKELY(!textStyleContext)) {
    1260               0 :     return nsnull;
    1261                 :   }
    1262                 : 
    1263                 :   // Start by by creating our anonymous block frame
    1264               0 :   mDisplayFrame = new (shell) nsComboboxDisplayFrame(styleContext, this);
    1265               0 :   if (NS_UNLIKELY(!mDisplayFrame)) {
    1266               0 :     return nsnull;
    1267                 :   }
    1268                 : 
    1269               0 :   nsresult rv = mDisplayFrame->Init(mContent, this, nsnull);
    1270               0 :   if (NS_FAILED(rv)) {
    1271               0 :     mDisplayFrame->Destroy();
    1272               0 :     mDisplayFrame = nsnull;
    1273               0 :     return nsnull;
    1274                 :   }
    1275                 : 
    1276                 :   // Create a text frame and put it inside the block frame
    1277               0 :   nsIFrame* textFrame = NS_NewTextFrame(shell, textStyleContext);
    1278               0 :   if (NS_UNLIKELY(!textFrame)) {
    1279               0 :     return nsnull;
    1280                 :   }
    1281                 : 
    1282                 :   // initialize the text frame
    1283               0 :   rv = textFrame->Init(aContent, mDisplayFrame, nsnull);
    1284               0 :   if (NS_FAILED(rv)) {
    1285               0 :     mDisplayFrame->Destroy();
    1286               0 :     mDisplayFrame = nsnull;
    1287               0 :     textFrame->Destroy();
    1288               0 :     textFrame = nsnull;
    1289               0 :     return nsnull;
    1290                 :   }
    1291               0 :   mDisplayContent->SetPrimaryFrame(textFrame);
    1292                 : 
    1293               0 :   nsFrameList textList(textFrame, textFrame);
    1294               0 :   mDisplayFrame->SetInitialChildList(kPrincipalList, textList);
    1295               0 :   return mDisplayFrame;
    1296                 : }
    1297                 : 
    1298                 : void
    1299               0 : nsComboboxControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
    1300                 : {
    1301                 :   // Revoke any pending RedisplayTextEvent
    1302               0 :   mRedisplayTextEvent.Revoke();
    1303                 : 
    1304               0 :   nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), false);
    1305                 : 
    1306               0 :   if (mDroppedDown) {
    1307                 :     // Get parent view
    1308               0 :     nsIFrame * listFrame = do_QueryFrame(mListControlFrame);
    1309               0 :     if (listFrame) {
    1310               0 :       nsIView* view = listFrame->GetView();
    1311               0 :       NS_ASSERTION(view, "nsComboboxControlFrame view is null");
    1312               0 :       if (view) {
    1313               0 :         nsIWidget* widget = view->GetWidget();
    1314               0 :         if (widget)
    1315               0 :           widget->CaptureRollupEvents(this, false, true);
    1316                 :       }
    1317                 :     }
    1318                 :   }
    1319                 : 
    1320                 :   // Cleanup frames in popup child list
    1321               0 :   mPopupFrames.DestroyFramesFrom(aDestructRoot);
    1322               0 :   nsContentUtils::DestroyAnonymousContent(&mDisplayContent);
    1323               0 :   nsContentUtils::DestroyAnonymousContent(&mButtonContent);
    1324               0 :   nsBlockFrame::DestroyFrom(aDestructRoot);
    1325               0 : }
    1326                 : 
    1327                 : const nsFrameList&
    1328               0 : nsComboboxControlFrame::GetChildList(ChildListID aListID) const
    1329                 : {
    1330               0 :   if (kSelectPopupList == aListID) {
    1331               0 :     return mPopupFrames;
    1332                 :   }
    1333               0 :   return nsBlockFrame::GetChildList(aListID);
    1334                 : }
    1335                 : 
    1336                 : void
    1337               0 : nsComboboxControlFrame::GetChildLists(nsTArray<ChildList>* aLists) const
    1338                 : {
    1339               0 :   nsBlockFrame::GetChildLists(aLists);
    1340               0 :   mPopupFrames.AppendIfNonempty(aLists, kSelectPopupList);
    1341               0 : }
    1342                 : 
    1343                 : NS_IMETHODIMP
    1344               0 : nsComboboxControlFrame::SetInitialChildList(ChildListID     aListID,
    1345                 :                                             nsFrameList&    aChildList)
    1346                 : {
    1347               0 :   nsresult rv = NS_OK;
    1348               0 :   if (kSelectPopupList == aListID) {
    1349               0 :     mPopupFrames.SetFrames(aChildList);
    1350                 :   } else {
    1351               0 :     for (nsFrameList::Enumerator e(aChildList); !e.AtEnd(); e.Next()) {
    1352                 :       nsCOMPtr<nsIFormControl> formControl =
    1353               0 :         do_QueryInterface(e.get()->GetContent());
    1354               0 :       if (formControl && formControl->GetType() == NS_FORM_BUTTON_BUTTON) {
    1355               0 :         mButtonFrame = e.get();
    1356                 :         break;
    1357                 :       }
    1358                 :     }
    1359               0 :     NS_ASSERTION(mButtonFrame, "missing button frame in initial child list");
    1360               0 :     rv = nsBlockFrame::SetInitialChildList(aListID, aChildList);
    1361                 :   }
    1362               0 :   return rv;
    1363                 : }
    1364                 : 
    1365                 : //----------------------------------------------------------------------
    1366                 :   //nsIRollupListener
    1367                 : //----------------------------------------------------------------------
    1368                 : nsIContent*
    1369               0 : nsComboboxControlFrame::Rollup(PRUint32 aCount, bool aGetLastRolledUp)
    1370                 : {
    1371               0 :   if (mDroppedDown) {
    1372               0 :     nsWeakFrame weakFrame(this);
    1373               0 :     mListControlFrame->AboutToRollup(); // might destroy us
    1374               0 :     if (!weakFrame.IsAlive())
    1375               0 :       return nsnull;
    1376               0 :     ShowDropDown(false); // might destroy us
    1377               0 :     if (!weakFrame.IsAlive())
    1378               0 :       return nsnull;
    1379               0 :     mListControlFrame->CaptureMouseEvents(false);
    1380                 :   }
    1381                 : 
    1382               0 :   return nsnull;
    1383                 : }
    1384                 : 
    1385                 : void
    1386               0 : nsComboboxControlFrame::RollupFromList()
    1387                 : {
    1388               0 :   if (ShowList(false))
    1389               0 :     mListControlFrame->CaptureMouseEvents(false);
    1390               0 : }
    1391                 : 
    1392                 : PRInt32
    1393               0 : nsComboboxControlFrame::UpdateRecentIndex(PRInt32 aIndex)
    1394                 : {
    1395               0 :   PRInt32 index = mRecentSelectedIndex;
    1396               0 :   if (mRecentSelectedIndex == NS_SKIP_NOTIFY_INDEX || aIndex == NS_SKIP_NOTIFY_INDEX)
    1397               0 :     mRecentSelectedIndex = aIndex;
    1398               0 :   return index;
    1399                 : }
    1400                 : 
    1401                 : class nsDisplayComboboxFocus : public nsDisplayItem {
    1402                 : public:
    1403               0 :   nsDisplayComboboxFocus(nsDisplayListBuilder* aBuilder,
    1404                 :                          nsComboboxControlFrame* aFrame)
    1405               0 :     : nsDisplayItem(aBuilder, aFrame) {
    1406               0 :     MOZ_COUNT_CTOR(nsDisplayComboboxFocus);
    1407               0 :   }
    1408                 : #ifdef NS_BUILD_REFCNT_LOGGING
    1409               0 :   virtual ~nsDisplayComboboxFocus() {
    1410               0 :     MOZ_COUNT_DTOR(nsDisplayComboboxFocus);
    1411               0 :   }
    1412                 : #endif
    1413                 : 
    1414                 :   virtual void Paint(nsDisplayListBuilder* aBuilder,
    1415                 :                      nsRenderingContext* aCtx);
    1416               0 :   NS_DISPLAY_DECL_NAME("ComboboxFocus", TYPE_COMBOBOX_FOCUS)
    1417                 : };
    1418                 : 
    1419               0 : void nsDisplayComboboxFocus::Paint(nsDisplayListBuilder* aBuilder,
    1420                 :                                    nsRenderingContext* aCtx)
    1421                 : {
    1422                 :   static_cast<nsComboboxControlFrame*>(mFrame)
    1423               0 :     ->PaintFocus(*aCtx, ToReferenceFrame());
    1424               0 : }
    1425                 : 
    1426                 : NS_IMETHODIMP
    1427               0 : nsComboboxControlFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
    1428                 :                                          const nsRect&           aDirtyRect,
    1429                 :                                          const nsDisplayListSet& aLists)
    1430                 : {
    1431                 : #ifdef NOISY
    1432                 :   printf("%p paint at (%d, %d, %d, %d)\n", this,
    1433                 :     aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height);
    1434                 : #endif
    1435                 : 
    1436               0 :   if (aBuilder->IsForEventDelivery()) {
    1437                 :     // Don't allow children to receive events.
    1438                 :     // REVIEW: following old GetFrameForPoint
    1439               0 :     nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
    1440               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1441                 :   } else {
    1442                 :     // REVIEW: Our in-flow child frames are inline-level so they will paint in our
    1443                 :     // content list, so we don't need to mess with layers.
    1444               0 :     nsresult rv = nsBlockFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
    1445               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1446                 :   }
    1447                 : 
    1448                 :   // draw a focus indicator only when focus rings should be drawn
    1449               0 :   nsIDocument* doc = mContent->GetCurrentDoc();
    1450               0 :   if (doc) {
    1451               0 :     nsPIDOMWindow* window = doc->GetWindow();
    1452               0 :     if (window && window->ShouldShowFocusRing()) {
    1453               0 :       nsPresContext *presContext = PresContext();
    1454               0 :       const nsStyleDisplay *disp = GetStyleDisplay();
    1455               0 :       if ((!IsThemed(disp) ||
    1456               0 :            !presContext->GetTheme()->ThemeDrawsFocusForWidget(presContext, this, disp->mAppearance)) &&
    1457               0 :           mDisplayFrame && IsVisibleForPainting(aBuilder)) {
    1458                 :         nsresult rv = aLists.Content()->AppendNewToTop(
    1459               0 :             new (aBuilder) nsDisplayComboboxFocus(aBuilder, this));
    1460               0 :         NS_ENSURE_SUCCESS(rv, rv);
    1461                 :       }
    1462                 :     }
    1463                 :   }
    1464                 : 
    1465               0 :   return DisplaySelectionOverlay(aBuilder, aLists.Content());
    1466                 : }
    1467                 : 
    1468               0 : void nsComboboxControlFrame::PaintFocus(nsRenderingContext& aRenderingContext,
    1469                 :                                         nsPoint aPt)
    1470                 : {
    1471                 :   /* Do we need to do anything? */
    1472               0 :   nsEventStates eventStates = mContent->AsElement()->State();
    1473               0 :   if (eventStates.HasState(NS_EVENT_STATE_DISABLED) || mFocused != this)
    1474               0 :     return;
    1475                 : 
    1476               0 :   aRenderingContext.PushState();
    1477               0 :   nsRect clipRect = mDisplayFrame->GetRect() + aPt;
    1478               0 :   aRenderingContext.IntersectClip(clipRect);
    1479                 : 
    1480                 :   // REVIEW: Why does the old code paint mDisplayFrame again? We've
    1481                 :   // already painted it in the children above. So clipping it here won't do
    1482                 :   // us much good.
    1483                 : 
    1484                 :   /////////////////////
    1485                 :   // draw focus
    1486                 : 
    1487               0 :   aRenderingContext.SetLineStyle(nsLineStyle_kDotted);
    1488               0 :   aRenderingContext.SetColor(GetStyleColor()->mColor);
    1489                 : 
    1490                 :   //aRenderingContext.DrawRect(clipRect);
    1491                 : 
    1492               0 :   nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
    1493               0 :   clipRect.width -= onePixel;
    1494               0 :   clipRect.height -= onePixel;
    1495               0 :   aRenderingContext.DrawLine(clipRect.TopLeft(), clipRect.TopRight());
    1496               0 :   aRenderingContext.DrawLine(clipRect.TopRight(), clipRect.BottomRight());
    1497               0 :   aRenderingContext.DrawLine(clipRect.BottomRight(), clipRect.BottomLeft());
    1498               0 :   aRenderingContext.DrawLine(clipRect.BottomLeft(), clipRect.TopLeft());
    1499                 : 
    1500               0 :   aRenderingContext.PopState();
    1501                 : }
    1502                 : 
    1503                 : //---------------------------------------------------------
    1504                 : // gets the content (an option) by index and then set it as
    1505                 : // being selected or not selected
    1506                 : //---------------------------------------------------------
    1507                 : NS_IMETHODIMP
    1508               0 : nsComboboxControlFrame::OnOptionSelected(PRInt32 aIndex, bool aSelected)
    1509                 : {
    1510               0 :   if (mDroppedDown) {
    1511               0 :     nsISelectControlFrame *selectFrame = do_QueryFrame(mListControlFrame);
    1512               0 :     if (selectFrame) {
    1513               0 :       selectFrame->OnOptionSelected(aIndex, aSelected);
    1514                 :     }
    1515                 :   } else {
    1516               0 :     if (aSelected) {
    1517               0 :       nsAutoScriptBlocker blocker;
    1518               0 :       RedisplayText(aIndex);
    1519                 :     } else {
    1520               0 :       nsWeakFrame weakFrame(this);
    1521               0 :       RedisplaySelectedText();
    1522               0 :       if (weakFrame.IsAlive()) {
    1523               0 :         FireValueChangeEvent(); // Fire after old option is unselected
    1524                 :       }
    1525                 :     }
    1526                 :   }
    1527                 : 
    1528               0 :   return NS_OK;
    1529                 : }
    1530                 : 
    1531               0 : void nsComboboxControlFrame::FireValueChangeEvent()
    1532                 : {
    1533                 :   // Fire ValueChange event to indicate data value of combo box has changed
    1534                 :   nsContentUtils::AddScriptRunner(
    1535               0 :     new nsAsyncDOMEvent(mContent, NS_LITERAL_STRING("ValueChange"), true,
    1536               0 :                         false));
    1537               0 : }
    1538                 : 
    1539                 : void
    1540               0 : nsComboboxControlFrame::OnContentReset()
    1541                 : {
    1542               0 :   if (mListControlFrame) {
    1543               0 :     mListControlFrame->OnContentReset();
    1544                 :   }
    1545               0 : }
    1546                 : 
    1547                 : 
    1548                 : //--------------------------------------------------------
    1549                 : // nsIStatefulFrame
    1550                 : //--------------------------------------------------------
    1551                 : NS_IMETHODIMP
    1552               0 : nsComboboxControlFrame::SaveState(SpecialStateID aStateID,
    1553                 :                                   nsPresState** aState)
    1554                 : {
    1555               0 :   if (!mListControlFrame)
    1556               0 :     return NS_ERROR_FAILURE;
    1557                 : 
    1558               0 :   nsIStatefulFrame* stateful = do_QueryFrame(mListControlFrame);
    1559               0 :   return stateful->SaveState(aStateID, aState);
    1560                 : }
    1561                 : 
    1562                 : NS_IMETHODIMP
    1563               0 : nsComboboxControlFrame::RestoreState(nsPresState* aState)
    1564                 : {
    1565               0 :   if (!mListControlFrame)
    1566               0 :     return NS_ERROR_FAILURE;
    1567                 : 
    1568               0 :   nsIStatefulFrame* stateful = do_QueryFrame(mListControlFrame);
    1569               0 :   NS_ASSERTION(stateful, "Must implement nsIStatefulFrame");
    1570               0 :   return stateful->RestoreState(aState);
    1571                 : }
    1572                 : 
    1573                 : 
    1574                 : //
    1575                 : // Camino uses a native widget for the combobox
    1576                 : // popup, which affects drawing and event
    1577                 : // handling here and in nsListControlFrame.
    1578                 : //
    1579                 : // Also, Fennec use a custom combobox built-in widget
    1580                 : // 
    1581                 : 
    1582                 : /* static */
    1583                 : bool
    1584               0 : nsComboboxControlFrame::ToolkitHasNativePopup()
    1585                 : {
    1586                 : #ifdef MOZ_USE_NATIVE_POPUP_WINDOWS
    1587                 :   return true;
    1588                 : #else
    1589               0 :   return false;
    1590                 : #endif /* MOZ_USE_NATIVE_POPUP_WINDOWS */
    1591                 : }
    1592                 : 

Generated by: LCOV version 1.7