LCOV - code coverage report
Current view: directory - layout/xul/base/src - nsMenuPopupFrame.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 881 0 0.0 %
Date: 2012-06-02 Functions: 54 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* vim: set ts=2 sw=2 et tw=78: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is mozilla.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Original Author: David W. Hyatt (hyatt@netscape.com)
      25                 :  *   Mike Pinkerton (pinkerton@netscape.com)
      26                 :  *   Dean Tessman <dean_tessman@hotmail.com>
      27                 :  *   Ben Goodger <ben@netscape.com>
      28                 :  *
      29                 :  * Alternatively, the contents of this file may be used under the terms of
      30                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      31                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      32                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      33                 :  * of those above. If you wish to allow use of your version of this file only
      34                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      35                 :  * use your version of this file under the terms of the MPL, indicate your
      36                 :  * decision by deleting the provisions above and replace them with the notice
      37                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      38                 :  * the provisions above, a recipient may use your version of this file under
      39                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      40                 :  *
      41                 :  * ***** END LICENSE BLOCK ***** */
      42                 : 
      43                 : #include "nsMenuPopupFrame.h"
      44                 : #include "nsGkAtoms.h"
      45                 : #include "nsIContent.h"
      46                 : #include "prtypes.h"
      47                 : #include "nsIAtom.h"
      48                 : #include "nsPresContext.h"
      49                 : #include "nsStyleContext.h"
      50                 : #include "nsCSSRendering.h"
      51                 : #include "nsINameSpaceManager.h"
      52                 : #include "nsIViewManager.h"
      53                 : #include "nsWidgetsCID.h"
      54                 : #include "nsMenuFrame.h"
      55                 : #include "nsMenuBarFrame.h"
      56                 : #include "nsPopupSetFrame.h"
      57                 : #include "nsEventDispatcher.h"
      58                 : #include "nsPIDOMWindow.h"
      59                 : #include "nsIDOMScreen.h"
      60                 : #include "nsIPresShell.h"
      61                 : #include "nsFrameManager.h"
      62                 : #include "nsIDocument.h"
      63                 : #include "nsRect.h"
      64                 : #include "nsIComponentManager.h"
      65                 : #include "nsBoxLayoutState.h"
      66                 : #include "nsIScrollableFrame.h"
      67                 : #include "nsGUIEvent.h"
      68                 : #include "nsIRootBox.h"
      69                 : #include "nsIDocShellTreeItem.h"
      70                 : #include "nsReadableUtils.h"
      71                 : #include "nsUnicharUtils.h"
      72                 : #include "nsLayoutUtils.h"
      73                 : #include "nsContentUtils.h"
      74                 : #include "nsCSSFrameConstructor.h"
      75                 : #include "nsEventStateManager.h"
      76                 : #include "nsIPopupBoxObject.h"
      77                 : #include "nsPIWindowRoot.h"
      78                 : #include "nsIReflowCallback.h"
      79                 : #include "nsBindingManager.h"
      80                 : #include "nsIDocShellTreeOwner.h"
      81                 : #include "nsIBaseWindow.h"
      82                 : #include "nsISound.h"
      83                 : #include "nsIScreenManager.h"
      84                 : #include "nsIServiceManager.h"
      85                 : #include "nsThemeConstants.h"
      86                 : #include "nsDisplayList.h"
      87                 : #include "mozilla/Preferences.h"
      88                 : #include "mozilla/LookAndFeel.h"
      89                 : 
      90                 : using namespace mozilla;
      91                 : 
      92                 : PRInt8 nsMenuPopupFrame::sDefaultLevelIsTop = -1;
      93                 : 
      94                 : // NS_NewMenuPopupFrame
      95                 : //
      96                 : // Wrapper for creating a new menu popup container
      97                 : //
      98                 : nsIFrame*
      99               0 : NS_NewMenuPopupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
     100                 : {
     101               0 :   return new (aPresShell) nsMenuPopupFrame (aPresShell, aContext);
     102                 : }
     103                 : 
     104               0 : NS_IMPL_FRAMEARENA_HELPERS(nsMenuPopupFrame)
     105                 : 
     106               0 : NS_QUERYFRAME_HEAD(nsMenuPopupFrame)
     107               0 :   NS_QUERYFRAME_ENTRY(nsMenuPopupFrame)
     108               0 : NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame)
     109                 : 
     110                 : //
     111                 : // nsMenuPopupFrame ctor
     112                 : //
     113               0 : nsMenuPopupFrame::nsMenuPopupFrame(nsIPresShell* aShell, nsStyleContext* aContext)
     114                 :   :nsBoxFrame(aShell, aContext),
     115                 :   mCurrentMenu(nsnull),
     116                 :   mPrefSize(-1, -1),
     117                 :   mLastClientOffset(0, 0),
     118                 :   mPopupType(ePopupTypePanel),
     119                 :   mPopupState(ePopupClosed),
     120                 :   mPopupAlignment(POPUPALIGNMENT_NONE),
     121                 :   mPopupAnchor(POPUPALIGNMENT_NONE),
     122                 :   mConsumeRollupEvent(nsIPopupBoxObject::ROLLUP_DEFAULT),
     123                 :   mFlipBoth(false),
     124                 :   mIsOpenChanged(false),
     125                 :   mIsContextMenu(false),
     126                 :   mAdjustOffsetForContextMenu(false),
     127                 :   mGeneratedChildren(false),
     128                 :   mMenuCanOverlapOSBar(false),
     129                 :   mShouldAutoPosition(true),
     130                 :   mInContentShell(true),
     131                 :   mIsMenuLocked(false),
     132                 :   mIsDragPopup(false),
     133                 :   mHFlip(false),
     134               0 :   mVFlip(false)
     135                 : {
     136                 :   // the preference name is backwards here. True means that the 'top' level is
     137                 :   // the default, and false means that the 'parent' level is the default.
     138               0 :   if (sDefaultLevelIsTop >= 0)
     139               0 :     return;
     140                 :   sDefaultLevelIsTop =
     141               0 :     Preferences::GetBool("ui.panel.default_level_parent", false);
     142                 : } // ctor
     143                 : 
     144                 : 
     145                 : NS_IMETHODIMP
     146               0 : nsMenuPopupFrame::Init(nsIContent*      aContent,
     147                 :                        nsIFrame*        aParent,
     148                 :                        nsIFrame*        aPrevInFlow)
     149                 : {
     150               0 :   nsresult rv = nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
     151               0 :   NS_ENSURE_SUCCESS(rv, rv);
     152                 : 
     153                 :   // lookup if we're allowed to overlap the OS bar (menubar/taskbar) from the
     154                 :   // look&feel object
     155                 :   mMenuCanOverlapOSBar =
     156               0 :     LookAndFeel::GetInt(LookAndFeel::eIntID_MenusCanOverlapOSBar) != 0;
     157                 : 
     158               0 :   rv = CreatePopupView();
     159               0 :   NS_ENSURE_SUCCESS(rv, rv);
     160                 : 
     161                 :   // XXX Hack. The popup's view should float above all other views,
     162                 :   // so we use the nsIView::SetFloating() to tell the view manager
     163                 :   // about that constraint.
     164               0 :   nsIView* ourView = GetView();
     165               0 :   nsIViewManager* viewManager = ourView->GetViewManager();
     166               0 :   viewManager->SetViewFloating(ourView, true);
     167                 : 
     168               0 :   mPopupType = ePopupTypePanel;
     169               0 :   nsIDocument* doc = aContent->OwnerDoc();
     170                 :   PRInt32 namespaceID;
     171               0 :   nsCOMPtr<nsIAtom> tag = doc->BindingManager()->ResolveTag(aContent, &namespaceID);
     172               0 :   if (namespaceID == kNameSpaceID_XUL) {
     173               0 :     if (tag == nsGkAtoms::menupopup || tag == nsGkAtoms::popup)
     174               0 :       mPopupType = ePopupTypeMenu;
     175               0 :     else if (tag == nsGkAtoms::tooltip)
     176               0 :       mPopupType = ePopupTypeTooltip;
     177                 :   }
     178                 : 
     179               0 :   if (mPopupType == ePopupTypePanel &&
     180                 :       aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
     181               0 :                             nsGkAtoms::drag, eIgnoreCase)) {
     182               0 :     mIsDragPopup = true;
     183                 :   }
     184                 : 
     185               0 :   nsCOMPtr<nsISupports> cont = PresContext()->GetContainer();
     186               0 :   nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(cont);
     187               0 :   PRInt32 type = -1;
     188               0 :   if (dsti && NS_SUCCEEDED(dsti->GetItemType(&type)) &&
     189                 :       type == nsIDocShellTreeItem::typeChrome)
     190               0 :     mInContentShell = false;
     191                 : 
     192                 :   // To improve performance, create the widget for the popup only if it is not
     193                 :   // a leaf. Leaf popups such as menus will create their widgets later when
     194                 :   // the popup opens.
     195               0 :   if (!IsLeaf() && !ourView->HasWidget()) {
     196               0 :     CreateWidgetForView(ourView);
     197                 :   }
     198                 : 
     199               0 :   if (aContent->NodeInfo()->Equals(nsGkAtoms::tooltip, kNameSpaceID_XUL) &&
     200                 :       aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::_default,
     201               0 :                             nsGkAtoms::_true, eIgnoreCase)) {
     202                 :     nsIRootBox* rootBox =
     203               0 :       nsIRootBox::GetRootBox(PresContext()->GetPresShell());
     204               0 :     if (rootBox) {
     205               0 :       rootBox->SetDefaultTooltip(aContent);
     206                 :     }
     207                 :   }
     208                 : 
     209               0 :   return rv;
     210                 : }
     211                 : 
     212                 : bool
     213               0 : nsMenuPopupFrame::IsNoAutoHide() const
     214                 : {
     215                 :   // Panels with noautohide="true" don't hide when the mouse is clicked
     216                 :   // outside of them, or when another application is made active. Non-autohide
     217                 :   // panels cannot be used in content windows.
     218               0 :   return (!mInContentShell && mPopupType == ePopupTypePanel &&
     219                 :            mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::noautohide,
     220               0 :                                  nsGkAtoms::_true, eIgnoreCase));
     221                 : }
     222                 : 
     223                 : nsPopupLevel
     224               0 : nsMenuPopupFrame::PopupLevel(bool aIsNoAutoHide) const
     225                 : {
     226                 :   // The popup level is determined as follows, in this order:
     227                 :   //   1. non-panels (menus and tooltips) are always topmost
     228                 :   //   2. any specified level attribute
     229                 :   //   3. if a titlebar attribute is set, use the 'floating' level
     230                 :   //   4. if this is a noautohide panel, use the 'parent' level
     231                 :   //   5. use the platform-specific default level
     232                 : 
     233                 :   // If this is not a panel, this is always a top-most popup.
     234               0 :   if (mPopupType != ePopupTypePanel)
     235               0 :     return ePopupLevelTop;
     236                 : 
     237                 :   // If the level attribute has been set, use that.
     238                 :   static nsIContent::AttrValuesArray strings[] =
     239                 :     {&nsGkAtoms::top, &nsGkAtoms::parent, &nsGkAtoms::floating, nsnull};
     240               0 :   switch (mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::level,
     241               0 :                                     strings, eCaseMatters)) {
     242                 :     case 0:
     243               0 :       return ePopupLevelTop;
     244                 :     case 1:
     245               0 :       return ePopupLevelParent;
     246                 :     case 2:
     247               0 :       return ePopupLevelFloating;
     248                 :   }
     249                 : 
     250                 :   // Panels with titlebars most likely want to be floating popups.
     251               0 :   if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::titlebar))
     252               0 :     return ePopupLevelFloating;
     253                 : 
     254                 :   // If this panel is a noautohide panel, the default is the parent level.
     255               0 :   if (aIsNoAutoHide)
     256               0 :     return ePopupLevelParent;
     257                 : 
     258                 :   // Otherwise, the result depends on the platform.
     259               0 :   return sDefaultLevelIsTop ? ePopupLevelTop : ePopupLevelParent;
     260                 : }
     261                 : 
     262                 : void
     263               0 : nsMenuPopupFrame::EnsureWidget()
     264                 : {
     265               0 :   nsIView* ourView = GetView();
     266               0 :   if (!ourView->HasWidget()) {
     267               0 :     NS_ASSERTION(!mGeneratedChildren && !GetFirstPrincipalChild(),
     268                 :                  "Creating widget for MenuPopupFrame with children");
     269               0 :     CreateWidgetForView(ourView);
     270                 :   }
     271               0 : }
     272                 : 
     273                 : nsresult
     274               0 : nsMenuPopupFrame::CreateWidgetForView(nsIView* aView)
     275                 : {
     276                 :   // Create a widget for ourselves.
     277               0 :   nsWidgetInitData widgetData;
     278               0 :   widgetData.mWindowType = eWindowType_popup;
     279               0 :   widgetData.mBorderStyle = eBorderStyle_default;
     280               0 :   widgetData.clipSiblings = true;
     281               0 :   widgetData.mPopupHint = mPopupType;
     282               0 :   widgetData.mNoAutoHide = IsNoAutoHide();
     283               0 :   widgetData.mIsDragPopup = mIsDragPopup;
     284                 : 
     285               0 :   nsAutoString title;
     286               0 :   if (mContent && widgetData.mNoAutoHide) {
     287               0 :     if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::titlebar,
     288               0 :                               nsGkAtoms::normal, eCaseMatters)) {
     289               0 :       widgetData.mBorderStyle = eBorderStyle_title;
     290                 : 
     291               0 :       mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::label, title);
     292                 : 
     293               0 :       if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::close,
     294               0 :                                 nsGkAtoms::_true, eCaseMatters)) {
     295                 :         widgetData.mBorderStyle =
     296               0 :           static_cast<enum nsBorderStyle>(widgetData.mBorderStyle | eBorderStyle_close);
     297                 :       }
     298                 :     }
     299                 :   }
     300                 : 
     301               0 :   nsTransparencyMode mode = nsLayoutUtils::GetFrameTransparency(this, this);
     302               0 :   bool viewHasTransparentContent = !mInContentShell &&
     303                 :                                      (eTransparencyTransparent ==
     304               0 :                                       mode);
     305               0 :   nsIContent* parentContent = GetContent()->GetParent();
     306               0 :   nsIAtom *tag = nsnull;
     307               0 :   if (parentContent)
     308               0 :     tag = parentContent->Tag();
     309               0 :   widgetData.mDropShadow = !(viewHasTransparentContent || tag == nsGkAtoms::menulist);
     310               0 :   widgetData.mPopupLevel = PopupLevel(widgetData.mNoAutoHide);
     311                 : 
     312                 :   // panels which have a parent level need a parent widget. This allows them to
     313                 :   // always appear in front of the parent window but behind other windows that
     314                 :   // should be in front of it.
     315               0 :   nsCOMPtr<nsIWidget> parentWidget;
     316               0 :   if (widgetData.mPopupLevel != ePopupLevelTop) {
     317               0 :     nsCOMPtr<nsISupports> cont = PresContext()->GetContainer();
     318               0 :     nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(cont);
     319               0 :     if (!dsti)
     320               0 :       return NS_ERROR_FAILURE;
     321                 : 
     322               0 :     nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
     323               0 :     dsti->GetTreeOwner(getter_AddRefs(treeOwner));
     324               0 :     if (!treeOwner) return NS_ERROR_FAILURE;
     325                 : 
     326               0 :     nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(treeOwner));
     327               0 :     if (baseWindow)
     328               0 :       baseWindow->GetMainWidget(getter_AddRefs(parentWidget));
     329                 :   }
     330                 : 
     331                 :   nsresult rv = aView->CreateWidgetForPopup(&widgetData, parentWidget,
     332               0 :                                             true, true);
     333               0 :   if (NS_FAILED(rv)) {
     334               0 :     return rv;
     335                 :   }
     336                 : 
     337               0 :   nsIWidget* widget = aView->GetWidget();
     338               0 :   widget->SetTransparencyMode(mode);
     339               0 :   widget->SetWindowShadowStyle(GetShadowStyle());
     340                 : 
     341                 :   // most popups don't have a title so avoid setting the title if there isn't one
     342               0 :   if (!title.IsEmpty()) {
     343               0 :     widget->SetTitle(title);
     344                 :   }
     345                 : 
     346               0 :   return NS_OK;
     347                 : }
     348                 : 
     349                 : PRUint8
     350               0 : nsMenuPopupFrame::GetShadowStyle()
     351                 : {
     352               0 :   PRUint8 shadow = GetStyleUIReset()->mWindowShadow;
     353               0 :   if (shadow != NS_STYLE_WINDOW_SHADOW_DEFAULT)
     354               0 :     return shadow;
     355                 : 
     356               0 :   switch (GetStyleDisplay()->mAppearance) {
     357                 :     case NS_THEME_TOOLTIP:
     358               0 :       return NS_STYLE_WINDOW_SHADOW_TOOLTIP;
     359                 :     case NS_THEME_MENUPOPUP:
     360               0 :       return NS_STYLE_WINDOW_SHADOW_MENU;
     361                 :   }
     362               0 :   return NS_STYLE_WINDOW_SHADOW_DEFAULT;
     363                 : }
     364                 : 
     365                 : // this class is used for dispatching popupshown events asynchronously.
     366                 : class nsXULPopupShownEvent : public nsRunnable
     367               0 : {
     368                 : public:
     369               0 :   nsXULPopupShownEvent(nsIContent *aPopup, nsPresContext* aPresContext)
     370               0 :     : mPopup(aPopup), mPresContext(aPresContext)
     371                 :   {
     372               0 :   }
     373                 : 
     374               0 :   NS_IMETHOD Run()
     375                 :   {
     376               0 :     nsMouseEvent event(true, NS_XUL_POPUP_SHOWN, nsnull, nsMouseEvent::eReal);
     377               0 :     return nsEventDispatcher::Dispatch(mPopup, mPresContext, &event);                 
     378                 :   }
     379                 : 
     380                 : private:
     381                 :   nsCOMPtr<nsIContent> mPopup;
     382                 :   nsRefPtr<nsPresContext> mPresContext;
     383                 : };
     384                 : 
     385                 : NS_IMETHODIMP
     386               0 : nsMenuPopupFrame::SetInitialChildList(ChildListID  aListID,
     387                 :                                       nsFrameList& aChildList)
     388                 : {
     389                 :   // unless the list is empty, indicate that children have been generated.
     390               0 :   if (aChildList.NotEmpty())
     391               0 :     mGeneratedChildren = true;
     392               0 :   return nsBoxFrame::SetInitialChildList(aListID, aChildList);
     393                 : }
     394                 : 
     395                 : bool
     396               0 : nsMenuPopupFrame::IsLeaf() const
     397                 : {
     398               0 :   if (mGeneratedChildren)
     399               0 :     return false;
     400                 : 
     401               0 :   if (mPopupType != ePopupTypeMenu) {
     402                 :     // any panel with a type attribute, such as the autocomplete popup,
     403                 :     // is always generated right away.
     404               0 :     return !mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::type);
     405                 :   }
     406                 : 
     407                 :   // menu popups generate their child frames lazily only when opened, so
     408                 :   // behave like a leaf frame. However, generate child frames normally if
     409                 :   // the parent menu has a sizetopopup attribute. In this case the size of
     410                 :   // the parent menu is dependent on the size of the popup, so the frames
     411                 :   // need to exist in order to calculate this size.
     412               0 :   nsIContent* parentContent = mContent->GetParent();
     413                 :   return (parentContent &&
     414               0 :           !parentContent->HasAttr(kNameSpaceID_None, nsGkAtoms::sizetopopup));
     415                 : }
     416                 : 
     417                 : void
     418               0 : nsMenuPopupFrame::LayoutPopup(nsBoxLayoutState& aState, nsIFrame* aParentMenu, bool aSizedToPopup)
     419                 : {
     420               0 :   if (!mGeneratedChildren)
     421               0 :     return;
     422                 : 
     423               0 :   bool shouldPosition = true;
     424               0 :   bool isOpen = IsOpen();
     425               0 :   if (!isOpen) {
     426                 :     // if the popup is not open, only do layout while showing or if the menu
     427                 :     // is sized to the popup
     428               0 :     shouldPosition = (mPopupState == ePopupShowing);
     429               0 :     if (!shouldPosition && !aSizedToPopup)
     430               0 :       return;
     431                 :   }
     432                 : 
     433                 :   // if the popup has just been opened, make sure the scrolled window is at 0,0
     434               0 :   if (mIsOpenChanged) {
     435               0 :     nsIScrollableFrame *scrollframe = do_QueryFrame(GetChildBox());
     436               0 :     if (scrollframe) {
     437               0 :       scrollframe->ScrollTo(nsPoint(0,0), nsIScrollableFrame::INSTANT);
     438                 :     }
     439                 :   }
     440                 : 
     441                 :   // get the preferred, minimum and maximum size. If the menu is sized to the
     442                 :   // popup, then the popup's width is the menu's width.
     443               0 :   nsSize prefSize = GetPrefSize(aState);
     444               0 :   nsSize minSize = GetMinSize(aState); 
     445               0 :   nsSize maxSize = GetMaxSize(aState);
     446                 : 
     447               0 :   if (aSizedToPopup) {
     448               0 :     prefSize.width = aParentMenu->GetRect().width;
     449                 :   }
     450               0 :   prefSize = BoundsCheck(minSize, prefSize, maxSize);
     451                 : 
     452                 :   // if the size changed then set the bounds to be the preferred size
     453               0 :   bool sizeChanged = (mPrefSize != prefSize);
     454               0 :   if (sizeChanged) {
     455               0 :     SetBounds(aState, nsRect(0, 0, prefSize.width, prefSize.height), false);
     456               0 :     mPrefSize = prefSize;
     457                 :   }
     458                 : 
     459               0 :   if (shouldPosition) {
     460               0 :     SetPopupPosition(aParentMenu, false);
     461                 :   }
     462                 : 
     463               0 :   nsRect bounds(GetRect());
     464               0 :   Layout(aState);
     465                 : 
     466                 :   // if the width or height changed, readjust the popup position. This is a
     467                 :   // special case for tooltips where the preferred height doesn't include the
     468                 :   // real height for its inline element, but does once it is laid out.
     469                 :   // This is bug 228673 which doesn't have a simple fix.
     470               0 :   if (!aParentMenu) {
     471               0 :     nsSize newsize = GetSize();
     472               0 :     if (newsize.width > bounds.width || newsize.height > bounds.height) {
     473                 :       // the size after layout was larger than the preferred size,
     474                 :       // so set the preferred size accordingly
     475               0 :       mPrefSize = newsize;
     476               0 :       if (isOpen) {
     477               0 :         SetPopupPosition(nsnull, false);
     478                 :       }
     479                 :     }
     480                 :   }
     481                 : 
     482               0 :   nsPresContext* pc = PresContext();
     483               0 :   if (isOpen) {
     484               0 :     nsIView* view = GetView();
     485               0 :     nsIViewManager* viewManager = view->GetViewManager();
     486               0 :     nsRect rect = GetRect();
     487               0 :     rect.x = rect.y = 0;
     488                 : 
     489               0 :     viewManager->ResizeView(view, rect);
     490                 : 
     491               0 :     viewManager->SetViewVisibility(view, nsViewVisibility_kShow);
     492               0 :     mPopupState = ePopupOpenAndVisible;
     493               0 :     nsContainerFrame::SyncFrameViewProperties(pc, this, nsnull, view, 0);
     494                 :   }
     495                 : 
     496                 :   // finally, if the popup just opened, send a popupshown event
     497               0 :   if (mIsOpenChanged) {
     498               0 :     mIsOpenChanged = false;
     499               0 :     nsCOMPtr<nsIRunnable> event = new nsXULPopupShownEvent(GetContent(), pc);
     500               0 :     NS_DispatchToCurrentThread(event);
     501                 :   }
     502                 : }
     503                 : 
     504                 : nsIContent*
     505               0 : nsMenuPopupFrame::GetTriggerContent(nsMenuPopupFrame* aMenuPopupFrame)
     506                 : {
     507               0 :   while (aMenuPopupFrame) {
     508               0 :     if (aMenuPopupFrame->mTriggerContent)
     509               0 :       return aMenuPopupFrame->mTriggerContent;
     510                 : 
     511                 :     // check up the menu hierarchy until a popup with a trigger node is found
     512               0 :     nsMenuFrame* menuFrame = aMenuPopupFrame->GetParentMenu();
     513               0 :     if (!menuFrame)
     514               0 :       break;
     515                 : 
     516               0 :     nsMenuParent* parentPopup = menuFrame->GetMenuParent();
     517               0 :     if (!parentPopup || !parentPopup->IsMenu())
     518               0 :       break;
     519                 : 
     520               0 :     aMenuPopupFrame = static_cast<nsMenuPopupFrame *>(parentPopup);
     521                 :   }
     522                 : 
     523               0 :   return nsnull;
     524                 : }
     525                 : 
     526                 : void
     527               0 : nsMenuPopupFrame::InitPositionFromAnchorAlign(const nsAString& aAnchor,
     528                 :                                               const nsAString& aAlign)
     529                 : {
     530               0 :   mTriggerContent = nsnull;
     531                 : 
     532               0 :   if (aAnchor.EqualsLiteral("topleft"))
     533               0 :     mPopupAnchor = POPUPALIGNMENT_TOPLEFT;
     534               0 :   else if (aAnchor.EqualsLiteral("topright"))
     535               0 :     mPopupAnchor = POPUPALIGNMENT_TOPRIGHT;
     536               0 :   else if (aAnchor.EqualsLiteral("bottomleft"))
     537               0 :     mPopupAnchor = POPUPALIGNMENT_BOTTOMLEFT;
     538               0 :   else if (aAnchor.EqualsLiteral("bottomright"))
     539               0 :     mPopupAnchor = POPUPALIGNMENT_BOTTOMRIGHT;
     540               0 :   else if (aAnchor.EqualsLiteral("leftcenter"))
     541               0 :     mPopupAnchor = POPUPALIGNMENT_LEFTCENTER;
     542               0 :   else if (aAnchor.EqualsLiteral("rightcenter"))
     543               0 :     mPopupAnchor = POPUPALIGNMENT_RIGHTCENTER;
     544               0 :   else if (aAnchor.EqualsLiteral("topcenter"))
     545               0 :     mPopupAnchor = POPUPALIGNMENT_TOPCENTER;
     546               0 :   else if (aAnchor.EqualsLiteral("bottomcenter"))
     547               0 :     mPopupAnchor = POPUPALIGNMENT_BOTTOMCENTER;
     548                 :   else
     549               0 :     mPopupAnchor = POPUPALIGNMENT_NONE;
     550                 : 
     551               0 :   if (aAlign.EqualsLiteral("topleft"))
     552               0 :     mPopupAlignment = POPUPALIGNMENT_TOPLEFT;
     553               0 :   else if (aAlign.EqualsLiteral("topright"))
     554               0 :     mPopupAlignment = POPUPALIGNMENT_TOPRIGHT;
     555               0 :   else if (aAlign.EqualsLiteral("bottomleft"))
     556               0 :     mPopupAlignment = POPUPALIGNMENT_BOTTOMLEFT;
     557               0 :   else if (aAlign.EqualsLiteral("bottomright"))
     558               0 :     mPopupAlignment = POPUPALIGNMENT_BOTTOMRIGHT;
     559                 :   else
     560               0 :     mPopupAlignment = POPUPALIGNMENT_NONE;
     561               0 : }
     562                 : 
     563                 : void
     564               0 : nsMenuPopupFrame::InitializePopup(nsIContent* aAnchorContent,
     565                 :                                   nsIContent* aTriggerContent,
     566                 :                                   const nsAString& aPosition,
     567                 :                                   PRInt32 aXPos, PRInt32 aYPos,
     568                 :                                   bool aAttributesOverride)
     569                 : {
     570               0 :   EnsureWidget();
     571                 : 
     572               0 :   mPopupState = ePopupShowing;
     573               0 :   mAnchorContent = aAnchorContent;
     574               0 :   mTriggerContent = aTriggerContent;
     575               0 :   mXPos = aXPos;
     576               0 :   mYPos = aYPos;
     577               0 :   mAdjustOffsetForContextMenu = false;
     578                 : 
     579                 :   // if aAttributesOverride is true, then the popupanchor, popupalign and
     580                 :   // position attributes on the <popup> override those values passed in.
     581                 :   // If false, those attributes are only used if the values passed in are empty
     582               0 :   if (aAnchorContent) {
     583               0 :     nsAutoString anchor, align, position, flip;
     584               0 :     mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::popupanchor, anchor);
     585               0 :     mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::popupalign, align);
     586               0 :     mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::position, position);
     587               0 :     mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::flip, flip);
     588                 : 
     589               0 :     if (aAttributesOverride) {
     590                 :       // if the attributes are set, clear the offset position. Otherwise,
     591                 :       // the offset is used to adjust the position from the anchor point
     592               0 :       if (anchor.IsEmpty() && align.IsEmpty() && position.IsEmpty())
     593               0 :         position.Assign(aPosition);
     594                 :       else
     595               0 :         mXPos = mYPos = 0;
     596                 :     }
     597               0 :     else if (!aPosition.IsEmpty()) {
     598               0 :       position.Assign(aPosition);
     599                 :     }
     600                 : 
     601               0 :     mFlipBoth = flip.EqualsLiteral("both");
     602                 : 
     603               0 :     position.CompressWhitespace();
     604               0 :     PRInt32 spaceIdx = position.FindChar(' ');
     605                 :     // if there is a space in the position, assume it is the anchor and
     606                 :     // alignment as two separate tokens.
     607               0 :     if (spaceIdx >= 0) {
     608               0 :       InitPositionFromAnchorAlign(Substring(position, 0, spaceIdx), Substring(position, spaceIdx + 1));
     609                 :     }
     610               0 :     else if (position.EqualsLiteral("before_start")) {
     611               0 :       mPopupAnchor = POPUPALIGNMENT_TOPLEFT;
     612               0 :       mPopupAlignment = POPUPALIGNMENT_BOTTOMLEFT;
     613                 :     }
     614               0 :     else if (position.EqualsLiteral("before_end")) {
     615               0 :       mPopupAnchor = POPUPALIGNMENT_TOPRIGHT;
     616               0 :       mPopupAlignment = POPUPALIGNMENT_BOTTOMRIGHT;
     617                 :     }
     618               0 :     else if (position.EqualsLiteral("after_start")) {
     619               0 :       mPopupAnchor = POPUPALIGNMENT_BOTTOMLEFT;
     620               0 :       mPopupAlignment = POPUPALIGNMENT_TOPLEFT;
     621                 :     }
     622               0 :     else if (position.EqualsLiteral("after_end")) {
     623               0 :       mPopupAnchor = POPUPALIGNMENT_BOTTOMRIGHT;
     624               0 :       mPopupAlignment = POPUPALIGNMENT_TOPRIGHT;
     625                 :     }
     626               0 :     else if (position.EqualsLiteral("start_before")) {
     627               0 :       mPopupAnchor = POPUPALIGNMENT_TOPLEFT;
     628               0 :       mPopupAlignment = POPUPALIGNMENT_TOPRIGHT;
     629                 :     }
     630               0 :     else if (position.EqualsLiteral("start_after")) {
     631               0 :       mPopupAnchor = POPUPALIGNMENT_BOTTOMLEFT;
     632               0 :       mPopupAlignment = POPUPALIGNMENT_BOTTOMRIGHT;
     633                 :     }
     634               0 :     else if (position.EqualsLiteral("end_before")) {
     635               0 :       mPopupAnchor = POPUPALIGNMENT_TOPRIGHT;
     636               0 :       mPopupAlignment = POPUPALIGNMENT_TOPLEFT;
     637                 :     }
     638               0 :     else if (position.EqualsLiteral("end_after")) {
     639               0 :       mPopupAnchor = POPUPALIGNMENT_BOTTOMRIGHT;
     640               0 :       mPopupAlignment = POPUPALIGNMENT_BOTTOMLEFT;
     641                 :     }
     642               0 :     else if (position.EqualsLiteral("overlap")) {
     643               0 :       mPopupAnchor = POPUPALIGNMENT_TOPLEFT;
     644               0 :       mPopupAlignment = POPUPALIGNMENT_TOPLEFT;
     645                 :     }
     646               0 :     else if (position.EqualsLiteral("after_pointer")) {
     647               0 :       mPopupAnchor = POPUPALIGNMENT_TOPLEFT;
     648               0 :       mPopupAlignment = POPUPALIGNMENT_TOPLEFT;
     649                 :       // XXXndeakin this is supposed to anchor vertically after, but with the
     650                 :       // horizontal position as the mouse pointer.
     651               0 :       mYPos += 21;
     652                 :     }
     653                 :     else {
     654               0 :       InitPositionFromAnchorAlign(anchor, align);
     655                 :     }
     656                 :   }
     657                 : 
     658               0 :   mScreenXPos = -1;
     659               0 :   mScreenYPos = -1;
     660                 : 
     661               0 :   if (aAttributesOverride) {
     662                 :     // Use |left| and |top| dimension attributes to position the popup if
     663                 :     // present, as they may have been persisted. 
     664               0 :     nsAutoString left, top;
     665               0 :     mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::left, left);
     666               0 :     mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::top, top);
     667                 : 
     668                 :     PRInt32 err;
     669               0 :     if (!left.IsEmpty()) {
     670               0 :       PRInt32 x = left.ToInteger(&err);
     671               0 :       if (NS_SUCCEEDED(err))
     672               0 :         mScreenXPos = x;
     673                 :     }
     674               0 :     if (!top.IsEmpty()) {
     675               0 :       PRInt32 y = top.ToInteger(&err);
     676               0 :       if (NS_SUCCEEDED(err))
     677               0 :         mScreenYPos = y;
     678                 :     }
     679                 :   }
     680               0 : }
     681                 : 
     682                 : void
     683               0 : nsMenuPopupFrame::InitializePopupAtScreen(nsIContent* aTriggerContent,
     684                 :                                           PRInt32 aXPos, PRInt32 aYPos,
     685                 :                                           bool aIsContextMenu)
     686                 : {
     687               0 :   EnsureWidget();
     688                 : 
     689               0 :   mPopupState = ePopupShowing;
     690               0 :   mAnchorContent = nsnull;
     691               0 :   mTriggerContent = aTriggerContent;
     692               0 :   mScreenXPos = aXPos;
     693               0 :   mScreenYPos = aYPos;
     694               0 :   mFlipBoth = false;
     695               0 :   mPopupAnchor = POPUPALIGNMENT_NONE;
     696               0 :   mPopupAlignment = POPUPALIGNMENT_NONE;
     697               0 :   mIsContextMenu = aIsContextMenu;
     698               0 :   mAdjustOffsetForContextMenu = aIsContextMenu;
     699               0 : }
     700                 : 
     701                 : void
     702               0 : nsMenuPopupFrame::InitializePopupWithAnchorAlign(nsIContent* aAnchorContent,
     703                 :                                                  nsAString& aAnchor,
     704                 :                                                  nsAString& aAlign,
     705                 :                                                  PRInt32 aXPos, PRInt32 aYPos)
     706                 : {
     707               0 :   EnsureWidget();
     708                 : 
     709               0 :   mPopupState = ePopupShowing;
     710               0 :   mAdjustOffsetForContextMenu = false;
     711               0 :   mFlipBoth = false;
     712                 : 
     713                 :   // this popup opening function is provided for backwards compatibility
     714                 :   // only. It accepts either coordinates or an anchor and alignment value
     715                 :   // but doesn't use both together.
     716               0 :   if (aXPos == -1 && aYPos == -1) {
     717               0 :     mAnchorContent = aAnchorContent;
     718               0 :     mScreenXPos = -1;
     719               0 :     mScreenYPos = -1;
     720               0 :     mXPos = 0;
     721               0 :     mYPos = 0;
     722               0 :     InitPositionFromAnchorAlign(aAnchor, aAlign);
     723                 :   }
     724                 :   else {
     725               0 :     mAnchorContent = nsnull;
     726               0 :     mPopupAnchor = POPUPALIGNMENT_NONE;
     727               0 :     mPopupAlignment = POPUPALIGNMENT_NONE;
     728               0 :     mScreenXPos = aXPos;
     729               0 :     mScreenYPos = aYPos;
     730               0 :     mXPos = aXPos;
     731               0 :     mYPos = aYPos;
     732                 :   }
     733               0 : }
     734                 : 
     735                 : void
     736               0 : nsMenuPopupFrame::ShowPopup(bool aIsContextMenu, bool aSelectFirstItem)
     737                 : {
     738               0 :   mIsContextMenu = aIsContextMenu;
     739                 : 
     740               0 :   if (mPopupState == ePopupShowing) {
     741               0 :     mPopupState = ePopupOpen;
     742               0 :     mIsOpenChanged = true;
     743                 : 
     744               0 :     nsMenuFrame* menuFrame = GetParentMenu();
     745               0 :     if (menuFrame) {
     746               0 :       nsWeakFrame weakFrame(this);
     747               0 :       menuFrame->PopupOpened();
     748               0 :       if (!weakFrame.IsAlive())
     749                 :         return;
     750                 :     }
     751                 : 
     752                 :     // do we need an actual reflow here?
     753                 :     // is SetPopupPosition all that is needed?
     754               0 :     PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange,
     755               0 :                                                  NS_FRAME_HAS_DIRTY_CHILDREN);
     756                 : 
     757               0 :     if (mPopupType == ePopupTypeMenu) {
     758               0 :       nsCOMPtr<nsISound> sound(do_CreateInstance("@mozilla.org/sound;1"));
     759               0 :       if (sound)
     760               0 :         sound->PlayEventSound(nsISound::EVENT_MENU_POPUP);
     761                 :     }
     762                 :   }
     763                 : 
     764               0 :   mShouldAutoPosition = true;
     765                 : }
     766                 : 
     767                 : void
     768               0 : nsMenuPopupFrame::HidePopup(bool aDeselectMenu, nsPopupState aNewState)
     769                 : {
     770               0 :   NS_ASSERTION(aNewState == ePopupClosed || aNewState == ePopupInvisible,
     771                 :                "popup being set to unexpected state");
     772                 : 
     773                 :   // don't hide the popup when it isn't open
     774               0 :   if (mPopupState == ePopupClosed || mPopupState == ePopupShowing)
     775               0 :     return;
     776                 : 
     777                 :   // clear the trigger content if the popup is being closed. But don't clear
     778                 :   // it if the popup is just being made invisible as a popuphiding or command
     779                 :   // event may want to retrieve it.
     780               0 :   if (aNewState == ePopupClosed) {
     781                 :     // if the popup had a trigger node set, clear the global window popup node
     782                 :     // as well
     783               0 :     if (mTriggerContent) {
     784               0 :       nsIDocument* doc = mContent->GetCurrentDoc();
     785               0 :       if (doc) {
     786               0 :         nsPIDOMWindow* win = doc->GetWindow();
     787               0 :         if (win) {
     788               0 :           nsCOMPtr<nsPIWindowRoot> root = win->GetTopWindowRoot();
     789               0 :           if (root) {
     790               0 :             root->SetPopupNode(nsnull);
     791                 :           }
     792                 :         }
     793                 :       }
     794                 :     }
     795               0 :     mTriggerContent = nsnull;
     796               0 :     mAnchorContent = nsnull;
     797                 :   }
     798                 : 
     799                 :   // when invisible and about to be closed, HidePopup has already been called,
     800                 :   // so just set the new state to closed and return
     801               0 :   if (mPopupState == ePopupInvisible) {
     802               0 :     if (aNewState == ePopupClosed)
     803               0 :       mPopupState = ePopupClosed;
     804               0 :     return;
     805                 :   }
     806                 : 
     807               0 :   mPopupState = aNewState;
     808                 : 
     809               0 :   if (IsMenu())
     810               0 :     SetCurrentMenuItem(nsnull);
     811                 : 
     812               0 :   mIncrementalString.Truncate();
     813                 : 
     814               0 :   LockMenuUntilClosed(false);
     815                 : 
     816               0 :   mIsOpenChanged = false;
     817               0 :   mCurrentMenu = nsnull; // make sure no current menu is set
     818               0 :   mHFlip = mVFlip = false;
     819                 : 
     820               0 :   nsIView* view = GetView();
     821               0 :   nsIViewManager* viewManager = view->GetViewManager();
     822               0 :   viewManager->SetViewVisibility(view, nsViewVisibility_kHide);
     823               0 :   viewManager->ResizeView(view, nsRect(0, 0, 0, 0));
     824                 : 
     825               0 :   FireDOMEvent(NS_LITERAL_STRING("DOMMenuInactive"), mContent);
     826                 : 
     827                 :   // XXX, bug 137033, In Windows, if mouse is outside the window when the menupopup closes, no
     828                 :   // mouse_enter/mouse_exit event will be fired to clear current hover state, we should clear it manually.
     829                 :   // This code may not the best solution, but we can leave it here until we find the better approach.
     830               0 :   NS_ASSERTION(mContent->IsElement(), "How do we have a non-element?");
     831               0 :   nsEventStates state = mContent->AsElement()->State();
     832                 : 
     833               0 :   if (state.HasState(NS_EVENT_STATE_HOVER)) {
     834               0 :     nsEventStateManager *esm = PresContext()->EventStateManager();
     835               0 :     esm->SetContentState(nsnull, NS_EVENT_STATE_HOVER);
     836                 :   }
     837                 : 
     838               0 :   nsMenuFrame* menuFrame = GetParentMenu();
     839               0 :   if (menuFrame) {
     840               0 :     menuFrame->PopupClosed(aDeselectMenu);
     841                 :   }
     842                 : }
     843                 : 
     844                 : void
     845               0 : nsMenuPopupFrame::InvalidateInternal(const nsRect& aDamageRect,
     846                 :                                      nscoord aX, nscoord aY, nsIFrame* aForChild,
     847                 :                                      PRUint32 aFlags)
     848                 : {
     849               0 :   InvalidateRoot(aDamageRect + nsPoint(aX, aY), aFlags);
     850               0 : }
     851                 : 
     852                 : void
     853               0 : nsMenuPopupFrame::GetLayoutFlags(PRUint32& aFlags)
     854                 : {
     855               0 :   aFlags = NS_FRAME_NO_SIZE_VIEW | NS_FRAME_NO_MOVE_VIEW | NS_FRAME_NO_VISIBILITY;
     856               0 : }
     857                 : 
     858                 : ///////////////////////////////////////////////////////////////////////////////
     859                 : // GetRootViewForPopup
     860                 : //   Retrieves the view for the popup widget that contains the given frame. 
     861                 : //   If the given frame is not contained by a popup widget, return the
     862                 : //   root view of the root viewmanager.
     863                 : nsIView*
     864               0 : nsMenuPopupFrame::GetRootViewForPopup(nsIFrame* aStartFrame)
     865                 : {
     866               0 :   nsIView* view = aStartFrame->GetClosestView();
     867               0 :   NS_ASSERTION(view, "frame must have a closest view!");
     868               0 :   while (view) {
     869                 :     // Walk up the view hierarchy looking for a view whose widget has a 
     870                 :     // window type of eWindowType_popup - in other words a popup window
     871                 :     // widget. If we find one, this is the view we want. 
     872               0 :     nsIWidget* widget = view->GetWidget();
     873               0 :     if (widget) {
     874                 :       nsWindowType wtype;
     875               0 :       widget->GetWindowType(wtype);
     876               0 :       if (wtype == eWindowType_popup) {
     877               0 :         return view;
     878                 :       }
     879                 :     }
     880                 : 
     881               0 :     nsIView* temp = view->GetParent();
     882               0 :     if (!temp) {
     883                 :       // Otherwise, we've walked all the way up to the root view and not
     884                 :       // found a view for a popup window widget. Just return the root view.
     885               0 :       return view;
     886                 :     }
     887               0 :     view = temp;
     888                 :   }
     889                 : 
     890               0 :   return nsnull;
     891                 : }
     892                 : 
     893                 : nsPoint
     894               0 : nsMenuPopupFrame::AdjustPositionForAnchorAlign(nsRect& anchorRect,
     895                 :                                                FlipStyle& aHFlip, FlipStyle& aVFlip)
     896                 : {
     897                 :   // flip the anchor and alignment for right-to-left
     898               0 :   PRInt8 popupAnchor(mPopupAnchor);
     899               0 :   PRInt8 popupAlign(mPopupAlignment);
     900               0 :   if (IsDirectionRTL()) {
     901                 :     // no need to flip the centered anchor types
     902               0 :     if (popupAnchor < POPUPALIGNMENT_LEFTCENTER) {
     903               0 :       popupAnchor = -popupAnchor;
     904                 :     }
     905               0 :     popupAlign = -popupAlign;
     906                 :   }
     907                 : 
     908                 :   // first, determine at which corner of the anchor the popup should appear
     909               0 :   nsPoint pnt;
     910               0 :   switch (popupAnchor) {
     911                 :     case POPUPALIGNMENT_LEFTCENTER:
     912               0 :       pnt = nsPoint(anchorRect.x, anchorRect.y + anchorRect.height / 2);
     913               0 :       anchorRect.y = pnt.y;
     914               0 :       anchorRect.height = 0;
     915               0 :       break;
     916                 :     case POPUPALIGNMENT_RIGHTCENTER:
     917               0 :       pnt = nsPoint(anchorRect.XMost(), anchorRect.y + anchorRect.height / 2);
     918               0 :       anchorRect.y = pnt.y;
     919               0 :       anchorRect.height = 0;
     920               0 :       break;
     921                 :     case POPUPALIGNMENT_TOPCENTER:
     922               0 :       pnt = nsPoint(anchorRect.x + anchorRect.width / 2, anchorRect.y);
     923               0 :       anchorRect.x = pnt.x;
     924               0 :       anchorRect.width = 0;
     925               0 :       break;
     926                 :     case POPUPALIGNMENT_BOTTOMCENTER:
     927               0 :       pnt = nsPoint(anchorRect.x + anchorRect.width / 2, anchorRect.YMost());
     928               0 :       anchorRect.x = pnt.x;
     929               0 :       anchorRect.width = 0;
     930               0 :       break;
     931                 :     case POPUPALIGNMENT_TOPRIGHT:
     932               0 :       pnt = anchorRect.TopRight();
     933               0 :       break;
     934                 :     case POPUPALIGNMENT_BOTTOMLEFT:
     935               0 :       pnt = anchorRect.BottomLeft();
     936               0 :       break;
     937                 :     case POPUPALIGNMENT_BOTTOMRIGHT:
     938               0 :       pnt = anchorRect.BottomRight();
     939               0 :       break;
     940                 :     case POPUPALIGNMENT_TOPLEFT:
     941                 :     default:
     942               0 :       pnt = anchorRect.TopLeft();
     943               0 :       break;
     944                 :   }
     945                 : 
     946                 :   // If the alignment is on the right edge of the popup, move the popup left
     947                 :   // by the width. Similarly, if the alignment is on the bottom edge of the
     948                 :   // popup, move the popup up by the height. In addition, account for the
     949                 :   // margins of the popup on the edge on which it is aligned.
     950               0 :   nsMargin margin(0, 0, 0, 0);
     951               0 :   GetStyleMargin()->GetMargin(margin);
     952               0 :   switch (popupAlign) {
     953                 :     case POPUPALIGNMENT_TOPRIGHT:
     954               0 :       pnt.MoveBy(-mRect.width - margin.right, margin.top);
     955               0 :       break;
     956                 :     case POPUPALIGNMENT_BOTTOMLEFT:
     957               0 :       pnt.MoveBy(margin.left, -mRect.height - margin.bottom);
     958               0 :       break;
     959                 :     case POPUPALIGNMENT_BOTTOMRIGHT:
     960               0 :       pnt.MoveBy(-mRect.width - margin.right, -mRect.height - margin.bottom);
     961               0 :       break;
     962                 :     case POPUPALIGNMENT_TOPLEFT:
     963                 :     default:
     964               0 :       pnt.MoveBy(margin.left, margin.top);
     965               0 :       break;
     966                 :   }
     967                 : 
     968                 :   // Flipping horizontally is allowed as long as the popup is above or below
     969                 :   // the anchor. This will happen if both the anchor and alignment are top or
     970                 :   // both are bottom, but different values. Similarly, flipping vertically is
     971                 :   // allowed if the popup is to the left or right of the anchor. In this case,
     972                 :   // the values of the constants are such that both must be positive or both
     973                 :   // must be negative. A special case, used for overlap, allows flipping
     974                 :   // vertically as well.
     975                 :   // If we are flipping in both directions, we want to set a flip style both
     976                 :   // horizontally and vertically. However, we want to flip on the inside edge
     977                 :   // of the anchor. Consider the example of a typical dropdown menu.
     978                 :   // Vertically, we flip the popup on the outside edges of the anchor menu,
     979                 :   // however horizontally, we want to to use the inside edges so the popup
     980                 :   // still appears underneath the anchor menu instead of floating off the
     981                 :   // side of the menu.
     982               0 :   if (popupAnchor >= POPUPALIGNMENT_LEFTCENTER) {
     983               0 :     if (popupAnchor == POPUPALIGNMENT_LEFTCENTER ||
     984                 :         popupAnchor == POPUPALIGNMENT_RIGHTCENTER) {
     985               0 :       aHFlip = FlipStyle_Outside;
     986               0 :       aVFlip = FlipStyle_Inside;
     987                 :     }
     988                 :     else {
     989               0 :       aHFlip = FlipStyle_Inside;
     990               0 :       aVFlip = FlipStyle_Outside;
     991                 :     }
     992                 :   }
     993                 :   else {
     994               0 :     FlipStyle anchorEdge = mFlipBoth ? FlipStyle_Inside : FlipStyle_None;
     995               0 :     aHFlip = (popupAnchor == -popupAlign) ? FlipStyle_Outside : anchorEdge;
     996               0 :     if (((popupAnchor > 0) == (popupAlign > 0)) ||
     997                 :         (popupAnchor == POPUPALIGNMENT_TOPLEFT && popupAlign == POPUPALIGNMENT_TOPLEFT))
     998               0 :       aVFlip = FlipStyle_Outside;
     999                 :     else
    1000               0 :       aVFlip = anchorEdge;
    1001                 :   }
    1002                 : 
    1003                 :   return pnt;
    1004                 : }
    1005                 : 
    1006                 : nscoord
    1007               0 : nsMenuPopupFrame::FlipOrResize(nscoord& aScreenPoint, nscoord aSize, 
    1008                 :                                nscoord aScreenBegin, nscoord aScreenEnd,
    1009                 :                                nscoord aAnchorBegin, nscoord aAnchorEnd,
    1010                 :                                nscoord aMarginBegin, nscoord aMarginEnd,
    1011                 :                                nscoord aOffsetForContextMenu, FlipStyle aFlip,
    1012                 :                                bool* aFlipSide)
    1013                 : {
    1014                 :   // all of the coordinates used here are in app units relative to the screen
    1015               0 :   nscoord popupSize = aSize;
    1016               0 :   if (aScreenPoint < aScreenBegin) {
    1017                 :     // at its current position, the popup would extend past the left or top
    1018                 :     // edge of the screen, so it will have to be moved or resized.
    1019               0 :     if (aFlip) {
    1020                 :       // for inside flips, we flip on the opposite side of the anchor
    1021               0 :       nscoord startpos = aFlip == FlipStyle_Outside ? aAnchorBegin : aAnchorEnd;
    1022               0 :       nscoord endpos = aFlip == FlipStyle_Outside ? aAnchorEnd : aAnchorBegin;
    1023                 : 
    1024                 :       // check whether there is more room to the left and right (or top and
    1025                 :       // bottom) of the anchor and put the popup on the side with more room.
    1026               0 :       if (startpos - aScreenBegin >= aScreenEnd - endpos) {
    1027               0 :         aScreenPoint = aScreenBegin;
    1028               0 :         popupSize = startpos - aScreenPoint - aMarginEnd;
    1029                 :       }
    1030                 :       else {
    1031                 :         // flip such that the popup is to the right or bottom of the anchor
    1032                 :         // point instead. However, when flipping use the same margin size.
    1033               0 :         *aFlipSide = true;
    1034               0 :         aScreenPoint = endpos + aMarginEnd;
    1035                 :         // check if the new position is still off the right or bottom edge of
    1036                 :         // the screen. If so, resize the popup.
    1037               0 :         if (aScreenPoint + aSize > aScreenEnd) {
    1038               0 :           popupSize = aScreenEnd - aScreenPoint;
    1039                 :         }
    1040                 :       }
    1041                 :     }
    1042                 :     else {
    1043               0 :       aScreenPoint = aScreenBegin;
    1044                 :     }
    1045                 :   }
    1046               0 :   else if (aScreenPoint + aSize > aScreenEnd) {
    1047                 :     // at its current position, the popup would extend past the right or
    1048                 :     // bottom edge of the screen, so it will have to be moved or resized.
    1049               0 :     if (aFlip) {
    1050                 :       // for inside flips, we flip on the opposite side of the anchor
    1051               0 :       nscoord startpos = aFlip == FlipStyle_Outside ? aAnchorBegin : aAnchorEnd;
    1052               0 :       nscoord endpos = aFlip == FlipStyle_Outside ? aAnchorEnd : aAnchorBegin;
    1053                 : 
    1054                 :       // check whether there is more room to the left and right (or top and
    1055                 :       // bottom) of the anchor and put the popup on the side with more room.
    1056               0 :       if (aScreenEnd - endpos >= startpos - aScreenBegin) {
    1057               0 :         if (mIsContextMenu) {
    1058               0 :           aScreenPoint = aScreenEnd - aSize;
    1059                 :         }
    1060                 :         else {
    1061               0 :           aScreenPoint = endpos + aMarginBegin;
    1062               0 :           popupSize = aScreenEnd - aScreenPoint;
    1063                 :         }
    1064                 :       }
    1065                 :       else {
    1066                 :         // flip such that the popup is to the left or top of the anchor point
    1067                 :         // instead.
    1068               0 :         *aFlipSide = true;
    1069               0 :         aScreenPoint = startpos - aSize - aMarginBegin - aOffsetForContextMenu;
    1070                 : 
    1071                 :         // check if the new position is still off the left or top edge of the
    1072                 :         // screen. If so, resize the popup.
    1073               0 :         if (aScreenPoint < aScreenBegin) {
    1074               0 :           aScreenPoint = aScreenBegin;
    1075               0 :           if (!mIsContextMenu) {
    1076               0 :             popupSize = startpos - aScreenPoint - aMarginBegin;
    1077                 :           }
    1078                 :         }
    1079                 :       }
    1080                 :     }
    1081                 :     else {
    1082               0 :       aScreenPoint = aScreenEnd - aSize;
    1083                 :     }
    1084                 :   }
    1085                 : 
    1086                 :   // Make sure that the point is within the screen boundaries and that the
    1087                 :   // size isn't off the edge of the screen. This can happen when a large
    1088                 :   // positive or negative margin is used.
    1089               0 :   if (aScreenPoint < aScreenBegin) {
    1090               0 :     aScreenPoint = aScreenBegin;
    1091                 :   }
    1092               0 :   if (aScreenPoint > aScreenEnd) {
    1093               0 :     aScreenPoint = aScreenEnd - aSize;
    1094                 :   }
    1095                 : 
    1096                 :   // If popupSize ended up being negative, or the original size was actually
    1097                 :   // smaller than the calculated popup size, just use the original size instead.
    1098               0 :   if (popupSize <= 0 || aSize < popupSize) {
    1099               0 :     popupSize = aSize;
    1100                 :   }
    1101               0 :   return NS_MIN(popupSize, aScreenEnd - aScreenPoint);
    1102                 : }
    1103                 : 
    1104                 : nsresult
    1105               0 : nsMenuPopupFrame::SetPopupPosition(nsIFrame* aAnchorFrame, bool aIsMove)
    1106                 : {
    1107               0 :   if (!mShouldAutoPosition)
    1108               0 :     return NS_OK;
    1109                 : 
    1110                 :   // If this is due to a move, return early if the popup hasn't been laid out
    1111                 :   // yet. On Windows, this can happen when using a drag popup before it opens.
    1112               0 :   if (aIsMove && (mPrefSize.width == -1 || mPrefSize.height == -1)) {
    1113               0 :     return NS_OK;
    1114                 :   }
    1115                 : 
    1116               0 :   nsPresContext* presContext = PresContext();
    1117               0 :   nsIFrame* rootFrame = presContext->PresShell()->FrameManager()->GetRootFrame();
    1118               0 :   NS_ASSERTION(rootFrame->GetView() && GetView() &&
    1119                 :                rootFrame->GetView() == GetView()->GetParent(),
    1120                 :                "rootFrame's view is not our view's parent???");
    1121                 : 
    1122                 :   // if the frame is not specified, use the anchor node passed to OpenPopup. If
    1123                 :   // that wasn't specified either, use the root frame. Note that mAnchorContent
    1124                 :   // might be a different document so its presshell must be used.
    1125               0 :   if (!aAnchorFrame) {
    1126               0 :     if (mAnchorContent) {
    1127               0 :       aAnchorFrame = mAnchorContent->GetPrimaryFrame();
    1128                 :     }
    1129                 : 
    1130               0 :     if (!aAnchorFrame) {
    1131               0 :       aAnchorFrame = rootFrame;
    1132               0 :       if (!aAnchorFrame)
    1133               0 :         return NS_OK;
    1134                 :     }
    1135                 :   }
    1136                 : 
    1137               0 :   bool sizedToPopup = false;
    1138               0 :   if (aAnchorFrame->GetContent()) {
    1139                 :     // the popup should be the same size as the anchor menu, for example, a menulist.
    1140               0 :     sizedToPopup = nsMenuFrame::IsSizedToPopup(aAnchorFrame->GetContent(), false);
    1141                 :   }
    1142                 : 
    1143                 :   // the dimensions of the anchor in its app units
    1144               0 :   nsRect parentRect = aAnchorFrame->GetScreenRectInAppUnits();
    1145                 : 
    1146                 :   // the anchor may be in a different document with a different scale,
    1147                 :   // so adjust the size so that it is in the app units of the popup instead
    1148                 :   // of the anchor.
    1149                 :   parentRect = parentRect.ConvertAppUnitsRoundOut(
    1150               0 :     aAnchorFrame->PresContext()->AppUnitsPerDevPixel(),
    1151               0 :     presContext->AppUnitsPerDevPixel());
    1152                 : 
    1153                 :   // Set the popup's size to the preferred size. Below, this size will be
    1154                 :   // adjusted to fit on the screen or within the content area. If the anchor
    1155                 :   // is sized to the popup, use the anchor's width instead of the preferred
    1156                 :   // width. The preferred size should already be set by the parent frame.
    1157               0 :   NS_ASSERTION(mPrefSize.width >= 0 || mPrefSize.height >= 0,
    1158                 :                "preferred size of popup not set");
    1159               0 :   mRect.width = sizedToPopup ? parentRect.width : mPrefSize.width;
    1160               0 :   mRect.height = mPrefSize.height;
    1161                 : 
    1162                 :   // the screen position in app units where the popup should appear
    1163               0 :   nsPoint screenPoint;
    1164                 : 
    1165                 :   // For anchored popups, the anchor rectangle. For non-anchored popups, the
    1166                 :   // size will be 0.
    1167               0 :   nsRect anchorRect = parentRect;
    1168                 : 
    1169                 :   // indicators of whether the popup should be flipped or resized.
    1170               0 :   FlipStyle hFlip = FlipStyle_None, vFlip = FlipStyle_None;
    1171                 : 
    1172               0 :   nsMargin margin(0, 0, 0, 0);
    1173               0 :   GetStyleMargin()->GetMargin(margin);
    1174                 : 
    1175                 :   // the screen rectangle of the root frame, in dev pixels.
    1176               0 :   nsRect rootScreenRect = rootFrame->GetScreenRectInAppUnits();
    1177                 : 
    1178               0 :   nsDeviceContext* devContext = presContext->DeviceContext();
    1179               0 :   nscoord offsetForContextMenu = 0;
    1180                 : 
    1181               0 :   if (IsAnchored()) {
    1182                 :     // if we are anchored, there are certain things we don't want to do when
    1183                 :     // repositioning the popup to fit on the screen, such as end up positioned
    1184                 :     // over the anchor, for instance a popup appearing over the menu label.
    1185                 :     // When doing this reposition, we want to move the popup to the side with
    1186                 :     // the most room. The combination of anchor and alignment dictate if we 
    1187                 :     // readjust above/below or to the left/right.
    1188               0 :     if (mAnchorContent) {
    1189                 :       // move the popup according to the anchor and alignment. This will also
    1190                 :       // tell us which axis the popup is flush against in case we have to move
    1191                 :       // it around later. The AdjustPositionForAnchorAlign method accounts for
    1192                 :       // the popup's margin.
    1193               0 :       screenPoint = AdjustPositionForAnchorAlign(anchorRect, hFlip, vFlip);
    1194                 :     }
    1195                 :     else {
    1196                 :       // with no anchor, the popup is positioned relative to the root frame
    1197               0 :       anchorRect = rootScreenRect;
    1198               0 :       screenPoint = anchorRect.TopLeft() + nsPoint(margin.left, margin.top);
    1199                 :     }
    1200                 : 
    1201                 :     // mXPos and mYPos specify an additonal offset passed to OpenPopup that
    1202                 :     // should be added to the position
    1203               0 :     if (IsDirectionRTL())
    1204               0 :       screenPoint.x -= presContext->CSSPixelsToAppUnits(mXPos);
    1205                 :     else
    1206               0 :       screenPoint.x += presContext->CSSPixelsToAppUnits(mXPos);
    1207               0 :     screenPoint.y += presContext->CSSPixelsToAppUnits(mYPos);
    1208                 : 
    1209                 :     // If this is a noautohide popup, set the screen coordinates of the popup.
    1210                 :     // This way, the popup stays at the location where it was opened even when
    1211                 :     // the window is moved. Popups at the parent level follow the parent
    1212                 :     // window as it is moved and remained anchored, so we want to maintain the
    1213                 :     // anchoring instead.
    1214               0 :     if (IsNoAutoHide() && PopupLevel(true) != ePopupLevelParent) {
    1215                 :       // Account for the margin that will end up being added to the screen coordinate
    1216                 :       // the next time SetPopupPosition is called.
    1217               0 :       mScreenXPos = presContext->AppUnitsToIntCSSPixels(screenPoint.x - margin.left);
    1218               0 :       mScreenYPos = presContext->AppUnitsToIntCSSPixels(screenPoint.y - margin.top);
    1219                 :     }
    1220                 :   }
    1221                 :   else {
    1222                 :     // the popup is positioned at a screen coordinate.
    1223                 :     // first convert the screen position in mScreenXPos and mScreenYPos from
    1224                 :     // CSS pixels into device pixels, ignoring any scaling as mScreenXPos and
    1225                 :     // mScreenYPos are unscaled screen coordinates.
    1226               0 :     PRInt32 factor = devContext->UnscaledAppUnitsPerDevPixel();
    1227                 : 
    1228                 :     // context menus should be offset by two pixels so that they don't appear
    1229                 :     // directly where the cursor is. Otherwise, it is too easy to have the
    1230                 :     // context menu close up again.
    1231               0 :     if (mAdjustOffsetForContextMenu) {
    1232                 :       PRInt32 offsetForContextMenuDev =
    1233               0 :         nsPresContext::CSSPixelsToAppUnits(2) / factor;
    1234               0 :       offsetForContextMenu = presContext->DevPixelsToAppUnits(offsetForContextMenuDev);
    1235                 :     }
    1236                 : 
    1237                 :     // next, convert into app units accounting for the scaling
    1238                 :     screenPoint.x = presContext->DevPixelsToAppUnits(
    1239               0 :                       nsPresContext::CSSPixelsToAppUnits(mScreenXPos) / factor);
    1240                 :     screenPoint.y = presContext->DevPixelsToAppUnits(
    1241               0 :                       nsPresContext::CSSPixelsToAppUnits(mScreenYPos) / factor);
    1242               0 :     anchorRect = nsRect(screenPoint, nsSize(0, 0));
    1243                 : 
    1244                 :     // add the margins on the popup
    1245                 :     screenPoint.MoveBy(margin.left + offsetForContextMenu,
    1246               0 :                        margin.top + offsetForContextMenu);
    1247                 : 
    1248                 :     // screen positioned popups can be flipped vertically but never horizontally
    1249               0 :     vFlip = FlipStyle_Outside;
    1250                 :   }
    1251                 : 
    1252                 :   // If a panel is being moved, don't constrain or flip it. But always do this for
    1253                 :   // content shells, so that the popup doesn't extend outside the containing frame.
    1254               0 :   if (mInContentShell || !aIsMove || mPopupType != ePopupTypePanel) {
    1255               0 :     nsRect screenRect = GetConstraintRect(anchorRect, rootScreenRect);
    1256                 : 
    1257                 :     // ensure that anchorRect is on screen
    1258               0 :     if (!anchorRect.IntersectRect(anchorRect, screenRect)) {
    1259               0 :       anchorRect.width = anchorRect.height = 0;
    1260                 :       // if the anchor isn't within the screen, move it to the edge of the screen.
    1261               0 :       if (anchorRect.x < screenRect.x)
    1262               0 :         anchorRect.x = screenRect.x;
    1263               0 :       if (anchorRect.XMost() > screenRect.XMost())
    1264               0 :         anchorRect.x = screenRect.XMost();
    1265               0 :       if (anchorRect.y < screenRect.y)
    1266               0 :         anchorRect.y = screenRect.y;
    1267               0 :       if (anchorRect.YMost() > screenRect.YMost())
    1268               0 :         anchorRect.y = screenRect.YMost();
    1269                 :     }
    1270                 : 
    1271                 :     // shrink the the popup down if it is larger than the screen size
    1272               0 :     if (mRect.width > screenRect.width)
    1273               0 :       mRect.width = screenRect.width;
    1274               0 :     if (mRect.height > screenRect.height)
    1275               0 :       mRect.height = screenRect.height;
    1276                 : 
    1277                 :     // at this point the anchor (anchorRect) is within the available screen
    1278                 :     // area (screenRect) and the popup is known to be no larger than the screen.
    1279                 :     // Next, check if there is enough space to show the popup at full size when
    1280                 :     // positioned at screenPoint. If not, flip the popups to the opposite side
    1281                 :     // of their anchor point, or resize them as necessary.
    1282                 :     mRect.width = FlipOrResize(screenPoint.x, mRect.width, screenRect.x,
    1283                 :                                screenRect.XMost(), anchorRect.x, anchorRect.XMost(),
    1284               0 :                                margin.left, margin.right, offsetForContextMenu, hFlip, &mHFlip);
    1285                 : 
    1286                 :     mRect.height = FlipOrResize(screenPoint.y, mRect.height, screenRect.y,
    1287                 :                                 screenRect.YMost(), anchorRect.y, anchorRect.YMost(),
    1288               0 :                                 margin.top, margin.bottom, offsetForContextMenu, vFlip, &mVFlip);
    1289                 : 
    1290               0 :     NS_ASSERTION(screenPoint.x >= screenRect.x && screenPoint.y >= screenRect.y &&
    1291                 :                  screenPoint.x + mRect.width <= screenRect.XMost() &&
    1292                 :                  screenPoint.y + mRect.height <= screenRect.YMost(),
    1293                 :                  "Popup is offscreen");
    1294                 :   }
    1295                 : 
    1296                 :   // determine the x and y position of the view by subtracting the desired
    1297                 :   // screen position from the screen position of the root frame.
    1298               0 :   nsPoint viewPoint = screenPoint - rootScreenRect.TopLeft();
    1299                 : 
    1300                 :   // snap the view's position to device pixels, see bug 622507
    1301               0 :   viewPoint.x = presContext->RoundAppUnitsToNearestDevPixels(viewPoint.x);
    1302               0 :   viewPoint.y = presContext->RoundAppUnitsToNearestDevPixels(viewPoint.y);
    1303                 : 
    1304               0 :   nsIView* view = GetView();
    1305               0 :   NS_ASSERTION(view, "popup with no view");
    1306                 : 
    1307                 :   // Offset the position by the width and height of the borders and titlebar.
    1308                 :   // Even though GetClientOffset should return (0, 0) when there is no
    1309                 :   // titlebar or borders, we skip these calculations anyway for non-panels
    1310                 :   // to save time since they will never have a titlebar.
    1311               0 :   nsIWidget* widget = view->GetWidget();
    1312               0 :   if (mPopupType == ePopupTypePanel && widget) {
    1313               0 :     mLastClientOffset = widget->GetClientOffset();
    1314               0 :     viewPoint.x += presContext->DevPixelsToAppUnits(mLastClientOffset.x);
    1315               0 :     viewPoint.y += presContext->DevPixelsToAppUnits(mLastClientOffset.y);
    1316                 :   }
    1317                 : 
    1318               0 :   presContext->GetPresShell()->GetViewManager()->
    1319               0 :     MoveViewTo(view, viewPoint.x, viewPoint.y);
    1320                 : 
    1321                 :   // Now that we've positioned the view, sync up the frame's origin.
    1322               0 :   nsBoxFrame::SetPosition(viewPoint - GetParent()->GetOffsetTo(rootFrame));
    1323                 : 
    1324               0 :   if (sizedToPopup) {
    1325               0 :     nsBoxLayoutState state(PresContext());
    1326                 :     // XXXndeakin can parentSize.width still extend outside?
    1327               0 :     SetBounds(state, nsRect(mRect.x, mRect.y, parentRect.width, mRect.height));
    1328                 :   }
    1329                 : 
    1330               0 :   return NS_OK;
    1331                 : }
    1332                 : 
    1333                 : /* virtual */ nsMenuFrame*
    1334               0 : nsMenuPopupFrame::GetCurrentMenuItem()
    1335                 : {
    1336               0 :   return mCurrentMenu;
    1337                 : }
    1338                 : 
    1339                 : nsRect
    1340               0 : nsMenuPopupFrame::GetConstraintRect(const nsRect& aAnchorRect,
    1341                 :                                     const nsRect& aRootScreenRect)
    1342                 : {
    1343               0 :   nsIntRect screenRectPixels;
    1344               0 :   nsPresContext* presContext = PresContext();
    1345                 : 
    1346                 :   // determine the available screen space. It will be reduced by the OS chrome
    1347                 :   // such as menubars. It addition, for content shells, it will be the area of
    1348                 :   // the content rather than the screen.
    1349               0 :   nsCOMPtr<nsIScreen> screen;
    1350               0 :   nsCOMPtr<nsIScreenManager> sm(do_GetService("@mozilla.org/gfx/screenmanager;1"));
    1351               0 :   if (sm) {
    1352                 :     // for content shells, get the screen where the root frame is located.
    1353                 :     // This is because we need to constrain the content to this content area,
    1354                 :     // so we should use the same screen. Otherwise, use the screen where the
    1355                 :     // anchor is located.
    1356               0 :     nsRect rect = mInContentShell ? aRootScreenRect : aAnchorRect;
    1357               0 :     PRInt32 width = rect.width > 0 ? presContext->AppUnitsToDevPixels(rect.width) : 1;
    1358               0 :     PRInt32 height = rect.height > 0 ? presContext->AppUnitsToDevPixels(rect.height) : 1;
    1359               0 :     sm->ScreenForRect(presContext->AppUnitsToDevPixels(rect.x),
    1360                 :                       presContext->AppUnitsToDevPixels(rect.y),
    1361               0 :                       width, height, getter_AddRefs(screen));
    1362               0 :     if (screen) {
    1363                 :       // get the total screen area if the popup is allowed to overlap it.
    1364               0 :       if (mMenuCanOverlapOSBar && !mInContentShell)
    1365               0 :         screen->GetRect(&screenRectPixels.x, &screenRectPixels.y,
    1366               0 :                         &screenRectPixels.width, &screenRectPixels.height);
    1367                 :       else
    1368               0 :         screen->GetAvailRect(&screenRectPixels.x, &screenRectPixels.y,
    1369               0 :                              &screenRectPixels.width, &screenRectPixels.height);
    1370                 :     }
    1371                 :   }
    1372                 : 
    1373                 :   // keep a 3 pixel margin to the right and bottom of the screen for the WinXP dropshadow
    1374               0 :   screenRectPixels.SizeTo(screenRectPixels.width - 3, screenRectPixels.height - 3);
    1375                 : 
    1376               0 :   nsRect screenRect = screenRectPixels.ToAppUnits(presContext->AppUnitsPerDevPixel());
    1377               0 :   if (mInContentShell) {
    1378                 :     // for content shells, clip to the client area rather than the screen area
    1379               0 :     screenRect.IntersectRect(screenRect, aRootScreenRect);
    1380                 :   }
    1381                 : 
    1382                 :   return screenRect;
    1383                 : }
    1384                 : 
    1385               0 : void nsMenuPopupFrame::CanAdjustEdges(PRInt8 aHorizontalSide, PRInt8 aVerticalSide, nsIntPoint& aChange)
    1386                 : {
    1387               0 :   PRInt8 popupAlign(mPopupAlignment);
    1388               0 :   if (IsDirectionRTL()) {
    1389               0 :     popupAlign = -popupAlign;
    1390                 :   }
    1391                 : 
    1392               0 :   if (aHorizontalSide == (mHFlip ? NS_SIDE_RIGHT : NS_SIDE_LEFT)) {
    1393               0 :     if (popupAlign == POPUPALIGNMENT_TOPLEFT || popupAlign == POPUPALIGNMENT_BOTTOMLEFT) {
    1394               0 :       aChange.x = 0;
    1395                 :     }
    1396                 :   }
    1397               0 :   else if (aHorizontalSide == (mHFlip ? NS_SIDE_LEFT : NS_SIDE_RIGHT)) {
    1398               0 :     if (popupAlign == POPUPALIGNMENT_TOPRIGHT || popupAlign == POPUPALIGNMENT_BOTTOMRIGHT) {
    1399               0 :       aChange.x = 0;
    1400                 :     }
    1401                 :   }
    1402                 : 
    1403               0 :   if (aVerticalSide == (mVFlip ? NS_SIDE_BOTTOM : NS_SIDE_TOP)) {
    1404               0 :     if (popupAlign == POPUPALIGNMENT_TOPLEFT || popupAlign == POPUPALIGNMENT_TOPRIGHT) {
    1405               0 :       aChange.y = 0;
    1406                 :     }
    1407                 :   }
    1408               0 :   else if (aVerticalSide == (mVFlip ? NS_SIDE_TOP : NS_SIDE_BOTTOM)) {
    1409               0 :     if (popupAlign == POPUPALIGNMENT_BOTTOMLEFT || popupAlign == POPUPALIGNMENT_BOTTOMRIGHT) {
    1410               0 :       aChange.y = 0;
    1411                 :     }
    1412                 :   }
    1413               0 : }
    1414                 : 
    1415               0 : bool nsMenuPopupFrame::ConsumeOutsideClicks()
    1416                 : {
    1417                 :   // If the popup has explicitly set a consume mode, honor that.
    1418               0 :   if (mConsumeRollupEvent != nsIPopupBoxObject::ROLLUP_DEFAULT)
    1419               0 :     return (mConsumeRollupEvent == nsIPopupBoxObject::ROLLUP_CONSUME);
    1420                 : 
    1421               0 :   nsCOMPtr<nsIContent> parentContent = mContent->GetParent();
    1422               0 :   if (parentContent) {
    1423               0 :     nsINodeInfo *ni = parentContent->NodeInfo();
    1424               0 :     if (ni->Equals(nsGkAtoms::menulist, kNameSpaceID_XUL))
    1425               0 :       return true;  // Consume outside clicks for combo boxes on all platforms
    1426                 : #if defined(XP_WIN) || defined(XP_OS2)
    1427                 :     // Don't consume outside clicks for menus in Windows
    1428                 :     if (ni->Equals(nsGkAtoms::menu, kNameSpaceID_XUL) ||
    1429                 :         ni->Equals(nsGkAtoms::splitmenu, kNameSpaceID_XUL) ||
    1430                 :         ni->Equals(nsGkAtoms::popupset, kNameSpaceID_XUL) ||
    1431                 :         ((ni->Equals(nsGkAtoms::button, kNameSpaceID_XUL) ||
    1432                 :           ni->Equals(nsGkAtoms::toolbarbutton, kNameSpaceID_XUL)) &&
    1433                 :          (parentContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
    1434                 :                                      nsGkAtoms::menu, eCaseMatters) ||
    1435                 :           parentContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
    1436                 :                                      nsGkAtoms::menuButton, eCaseMatters)))) {
    1437                 :       return false;
    1438                 :     }
    1439                 : #endif
    1440               0 :     if (ni->Equals(nsGkAtoms::textbox, kNameSpaceID_XUL)) {
    1441                 :       // Don't consume outside clicks for autocomplete widget
    1442               0 :       if (parentContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
    1443               0 :                                      nsGkAtoms::autocomplete, eCaseMatters))
    1444               0 :         return false;
    1445                 :     }
    1446                 :   }
    1447                 : 
    1448               0 :   return true;
    1449                 : }
    1450                 : 
    1451                 : // XXXroc this is megalame. Fossicking around for a frame of the right
    1452                 : // type is a recipe for disaster in the long term.
    1453               0 : nsIScrollableFrame* nsMenuPopupFrame::GetScrollFrame(nsIFrame* aStart)
    1454                 : {
    1455               0 :   if (!aStart)
    1456               0 :     return nsnull;  
    1457                 : 
    1458                 :   // try start frame and siblings
    1459               0 :   nsIFrame* currFrame = aStart;
    1460               0 :   do {
    1461               0 :     nsIScrollableFrame* sf = do_QueryFrame(currFrame);
    1462               0 :     if (sf)
    1463               0 :       return sf;
    1464               0 :     currFrame = currFrame->GetNextSibling();
    1465                 :   } while (currFrame);
    1466                 : 
    1467                 :   // try children
    1468               0 :   currFrame = aStart;
    1469               0 :   do {
    1470               0 :     nsIFrame* childFrame = currFrame->GetFirstPrincipalChild();
    1471               0 :     nsIScrollableFrame* sf = GetScrollFrame(childFrame);
    1472               0 :     if (sf)
    1473               0 :       return sf;
    1474               0 :     currFrame = currFrame->GetNextSibling();
    1475                 :   } while (currFrame);
    1476                 : 
    1477               0 :   return nsnull;
    1478                 : }
    1479                 : 
    1480               0 : void nsMenuPopupFrame::EnsureMenuItemIsVisible(nsMenuFrame* aMenuItem)
    1481                 : {
    1482               0 :   if (aMenuItem) {
    1483               0 :     aMenuItem->PresContext()->PresShell()->
    1484                 :       ScrollFrameRectIntoView(aMenuItem,
    1485               0 :                               nsRect(nsPoint(0,0), aMenuItem->GetRect().Size()),
    1486                 :                               NS_PRESSHELL_SCROLL_ANYWHERE,
    1487                 :                               NS_PRESSHELL_SCROLL_ANYWHERE,
    1488                 :                               nsIPresShell::SCROLL_OVERFLOW_HIDDEN |
    1489               0 :                               nsIPresShell::SCROLL_FIRST_ANCESTOR_ONLY);
    1490                 :   }
    1491               0 : }
    1492                 : 
    1493               0 : NS_IMETHODIMP nsMenuPopupFrame::SetCurrentMenuItem(nsMenuFrame* aMenuItem)
    1494                 : {
    1495               0 :   if (mCurrentMenu == aMenuItem)
    1496               0 :     return NS_OK;
    1497                 : 
    1498               0 :   if (mCurrentMenu) {
    1499               0 :     mCurrentMenu->SelectMenu(false);
    1500                 :   }
    1501                 : 
    1502               0 :   if (aMenuItem) {
    1503               0 :     EnsureMenuItemIsVisible(aMenuItem);
    1504               0 :     aMenuItem->SelectMenu(true);
    1505                 :   }
    1506                 : 
    1507               0 :   mCurrentMenu = aMenuItem;
    1508                 : 
    1509               0 :   return NS_OK;
    1510                 : }
    1511                 : 
    1512                 : void
    1513               0 : nsMenuPopupFrame::CurrentMenuIsBeingDestroyed()
    1514                 : {
    1515               0 :   mCurrentMenu = nsnull;
    1516               0 : }
    1517                 : 
    1518                 : NS_IMETHODIMP
    1519               0 : nsMenuPopupFrame::ChangeMenuItem(nsMenuFrame* aMenuItem,
    1520                 :                                  bool aSelectFirstItem)
    1521                 : {
    1522               0 :   if (mCurrentMenu == aMenuItem)
    1523               0 :     return NS_OK;
    1524                 : 
    1525                 :   // When a context menu is open, the current menu is locked, and no change
    1526                 :   // to the menu is allowed.
    1527               0 :   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
    1528               0 :   if (!mIsContextMenu && pm && pm->HasContextMenu(this))
    1529               0 :     return NS_OK;
    1530                 : 
    1531                 :   // Unset the current child.
    1532               0 :   if (mCurrentMenu) {
    1533               0 :     mCurrentMenu->SelectMenu(false);
    1534               0 :     nsMenuPopupFrame* popup = mCurrentMenu->GetPopup();
    1535               0 :     if (popup) {
    1536               0 :       if (mCurrentMenu->IsOpen()) {
    1537               0 :         if (pm)
    1538               0 :           pm->HidePopupAfterDelay(popup);
    1539                 :       }
    1540                 :     }
    1541                 :   }
    1542                 : 
    1543                 :   // Set the new child.
    1544               0 :   if (aMenuItem) {
    1545               0 :     EnsureMenuItemIsVisible(aMenuItem);
    1546               0 :     aMenuItem->SelectMenu(true);
    1547                 :   }
    1548                 : 
    1549               0 :   mCurrentMenu = aMenuItem;
    1550                 : 
    1551               0 :   return NS_OK;
    1552                 : }
    1553                 : 
    1554                 : nsMenuFrame*
    1555               0 : nsMenuPopupFrame::Enter(nsGUIEvent* aEvent)
    1556                 : {
    1557               0 :   mIncrementalString.Truncate();
    1558                 : 
    1559                 :   // Give it to the child.
    1560               0 :   if (mCurrentMenu)
    1561               0 :     return mCurrentMenu->Enter(aEvent);
    1562                 : 
    1563               0 :   return nsnull;
    1564                 : }
    1565                 : 
    1566                 : nsMenuFrame*
    1567               0 : nsMenuPopupFrame::FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent, bool& doAction)
    1568                 : {
    1569                 :   PRUint32 charCode, keyCode;
    1570               0 :   aKeyEvent->GetCharCode(&charCode);
    1571               0 :   aKeyEvent->GetKeyCode(&keyCode);
    1572                 : 
    1573               0 :   doAction = false;
    1574                 : 
    1575                 :   // Enumerate over our list of frames.
    1576               0 :   nsIFrame* immediateParent = nsnull;
    1577                 :   PresContext()->PresShell()->
    1578               0 :     FrameConstructor()->GetInsertionPoint(this, nsnull, &immediateParent);
    1579               0 :   if (!immediateParent)
    1580               0 :     immediateParent = this;
    1581                 : 
    1582               0 :   PRUint32 matchCount = 0, matchShortcutCount = 0;
    1583               0 :   bool foundActive = false;
    1584                 :   bool isShortcut;
    1585               0 :   nsMenuFrame* frameBefore = nsnull;
    1586               0 :   nsMenuFrame* frameAfter = nsnull;
    1587               0 :   nsMenuFrame* frameShortcut = nsnull;
    1588                 : 
    1589               0 :   nsIContent* parentContent = mContent->GetParent();
    1590                 : 
    1591                 :   bool isMenu = parentContent &&
    1592               0 :                   !parentContent->NodeInfo()->Equals(nsGkAtoms::menulist, kNameSpaceID_XUL);
    1593                 : 
    1594                 :   static DOMTimeStamp lastKeyTime = 0;
    1595                 :   DOMTimeStamp keyTime;
    1596               0 :   aKeyEvent->GetTimeStamp(&keyTime);
    1597                 : 
    1598               0 :   if (charCode == 0) {
    1599               0 :     if (keyCode == NS_VK_BACK) {
    1600               0 :       if (!isMenu && !mIncrementalString.IsEmpty()) {
    1601               0 :         mIncrementalString.SetLength(mIncrementalString.Length() - 1);
    1602               0 :         return nsnull;
    1603                 :       }
    1604                 :       else {
    1605                 : #ifdef XP_WIN
    1606                 :         nsCOMPtr<nsISound> soundInterface = do_CreateInstance("@mozilla.org/sound;1");
    1607                 :         if (soundInterface)
    1608                 :           soundInterface->Beep();
    1609                 : #endif  // #ifdef XP_WIN
    1610                 :       }
    1611                 :     }
    1612               0 :     return nsnull;
    1613                 :   }
    1614                 :   else {
    1615               0 :     PRUnichar uniChar = ToLowerCase(static_cast<PRUnichar>(charCode));
    1616               0 :     if (isMenu || // Menu supports only first-letter navigation
    1617                 :         keyTime - lastKeyTime > INC_TYP_INTERVAL) // Interval too long, treat as new typing
    1618               0 :       mIncrementalString = uniChar;
    1619                 :     else {
    1620               0 :       mIncrementalString.Append(uniChar);
    1621                 :     }
    1622                 :   }
    1623                 : 
    1624                 :   // See bug 188199 & 192346, if all letters in incremental string are same, just try to match the first one
    1625               0 :   nsAutoString incrementalString(mIncrementalString);
    1626               0 :   PRUint32 charIndex = 1, stringLength = incrementalString.Length();
    1627               0 :   while (charIndex < stringLength && incrementalString[charIndex] == incrementalString[charIndex - 1]) {
    1628               0 :     charIndex++;
    1629                 :   }
    1630               0 :   if (charIndex == stringLength) {
    1631               0 :     incrementalString.Truncate(1);
    1632               0 :     stringLength = 1;
    1633                 :   }
    1634                 : 
    1635               0 :   lastKeyTime = keyTime;
    1636                 : 
    1637                 :   nsIFrame* currFrame;
    1638                 :   // NOTE: If you crashed here due to a bogus |immediateParent| it is 
    1639                 :   //       possible that the menu whose shortcut is being looked up has 
    1640                 :   //       been destroyed already.  One strategy would be to 
    1641                 :   //       setTimeout(<func>,0) as detailed in:
    1642                 :   //       <http://bugzilla.mozilla.org/show_bug.cgi?id=126675#c32>
    1643               0 :   currFrame = immediateParent->GetFirstPrincipalChild();
    1644                 : 
    1645               0 :   PRInt32 menuAccessKey = -1;
    1646               0 :   nsMenuBarListener::GetMenuAccessKey(&menuAccessKey);
    1647                 : 
    1648                 :   // We start searching from first child. This process is divided into two parts
    1649                 :   //   -- before current and after current -- by the current item
    1650               0 :   while (currFrame) {
    1651               0 :     nsIContent* current = currFrame->GetContent();
    1652                 :     
    1653                 :     // See if it's a menu item.
    1654               0 :     if (nsXULPopupManager::IsValidMenuItem(PresContext(), current, true)) {
    1655               0 :       nsAutoString textKey;
    1656               0 :       if (menuAccessKey >= 0) {
    1657                 :         // Get the shortcut attribute.
    1658               0 :         current->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, textKey);
    1659                 :       }
    1660               0 :       if (textKey.IsEmpty()) { // No shortcut, try first letter
    1661               0 :         isShortcut = false;
    1662               0 :         current->GetAttr(kNameSpaceID_None, nsGkAtoms::label, textKey);
    1663               0 :         if (textKey.IsEmpty()) // No label, try another attribute (value)
    1664               0 :           current->GetAttr(kNameSpaceID_None, nsGkAtoms::value, textKey);
    1665                 :       }
    1666                 :       else
    1667               0 :         isShortcut = true;
    1668                 : 
    1669               0 :       if (StringBeginsWith(textKey, incrementalString,
    1670               0 :                            nsCaseInsensitiveStringComparator())) {
    1671                 :         // mIncrementalString is a prefix of textKey
    1672               0 :         if (currFrame->GetType() == nsGkAtoms::menuFrame) {
    1673                 :           // There is one match
    1674               0 :           matchCount++;
    1675               0 :           if (isShortcut) {
    1676                 :             // There is one shortcut-key match
    1677               0 :             matchShortcutCount++;
    1678                 :             // Record the matched item. If there is only one matched shortcut item, do it
    1679               0 :             frameShortcut = static_cast<nsMenuFrame *>(currFrame);
    1680                 :           }
    1681               0 :           if (!foundActive) {
    1682                 :             // It's a first candidate item located before/on the current item
    1683               0 :             if (!frameBefore)
    1684               0 :               frameBefore = static_cast<nsMenuFrame *>(currFrame);
    1685                 :           }
    1686                 :           else {
    1687                 :             // It's a first candidate item located after the current item
    1688               0 :             if (!frameAfter)
    1689               0 :               frameAfter = static_cast<nsMenuFrame *>(currFrame);
    1690                 :           }
    1691                 :         }
    1692                 :         else
    1693               0 :           return nsnull;
    1694                 :       }
    1695                 : 
    1696                 :       // Get the active status
    1697               0 :       if (current->AttrValueIs(kNameSpaceID_None, nsGkAtoms::menuactive,
    1698               0 :                                nsGkAtoms::_true, eCaseMatters)) {
    1699               0 :         foundActive = true;
    1700               0 :         if (stringLength > 1) {
    1701                 :           // If there is more than one char typed, the current item has highest priority,
    1702                 :           //   otherwise the item next to current has highest priority
    1703               0 :           if (currFrame == frameBefore)
    1704               0 :             return frameBefore;
    1705                 :         }
    1706                 :       }
    1707                 :     }
    1708               0 :     currFrame = currFrame->GetNextSibling();
    1709                 :   }
    1710                 : 
    1711               0 :   doAction = (isMenu && (matchCount == 1 || matchShortcutCount == 1));
    1712                 : 
    1713               0 :   if (matchShortcutCount == 1) // We have one matched shortcut item
    1714               0 :     return frameShortcut;
    1715               0 :   if (frameAfter) // If we have matched item after the current, use it
    1716               0 :     return frameAfter;
    1717               0 :   else if (frameBefore) // If we haven't, use the item before the current
    1718               0 :     return frameBefore;
    1719                 : 
    1720                 :   // If we don't match anything, rollback the last typing
    1721               0 :   mIncrementalString.SetLength(mIncrementalString.Length() - 1);
    1722                 : 
    1723                 :   // didn't find a matching menu item
    1724                 : #ifdef XP_WIN
    1725                 :   // behavior on Windows - this item is in a menu popup off of the
    1726                 :   // menu bar, so beep and do nothing else
    1727                 :   if (isMenu) {
    1728                 :     nsCOMPtr<nsISound> soundInterface = do_CreateInstance("@mozilla.org/sound;1");
    1729                 :     if (soundInterface)
    1730                 :       soundInterface->Beep();
    1731                 :   }
    1732                 : #endif  // #ifdef XP_WIN
    1733                 : 
    1734               0 :   return nsnull;
    1735                 : }
    1736                 : 
    1737                 : void
    1738               0 : nsMenuPopupFrame::LockMenuUntilClosed(bool aLock)
    1739                 : {
    1740               0 :   mIsMenuLocked = aLock;
    1741                 : 
    1742                 :   // Lock / unlock the parent, too.
    1743               0 :   nsIFrame* parent = GetParent();
    1744               0 :   if (parent && parent->GetType() == nsGkAtoms::menuFrame) {
    1745               0 :     nsMenuParent* parentParent = static_cast<nsMenuFrame*>(parent)->GetMenuParent();
    1746               0 :     if (parentParent) {
    1747               0 :       parentParent->LockMenuUntilClosed(aLock);
    1748                 :     }
    1749                 :   }
    1750               0 : }
    1751                 : 
    1752                 : nsIWidget*
    1753               0 : nsMenuPopupFrame::GetWidget()
    1754                 : {
    1755               0 :   nsIView * view = GetRootViewForPopup(this);
    1756               0 :   if (!view)
    1757               0 :     return nsnull;
    1758                 : 
    1759               0 :   return view->GetWidget();
    1760                 : }
    1761                 : 
    1762                 : void
    1763               0 : nsMenuPopupFrame::AttachedDismissalListener()
    1764                 : {
    1765               0 :   mConsumeRollupEvent = nsIPopupBoxObject::ROLLUP_DEFAULT;
    1766               0 : }
    1767                 : 
    1768                 : nsresult
    1769               0 : nsMenuPopupFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
    1770                 :                                    const nsRect&           aDirtyRect,
    1771                 :                                    const nsDisplayListSet& aLists)
    1772                 : {
    1773                 :   // don't pass events to drag popups
    1774               0 :   if (aBuilder->IsForEventDelivery() && mIsDragPopup) {
    1775               0 :     return NS_OK;
    1776                 :   }
    1777                 : 
    1778               0 :   return nsBoxFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
    1779                 : }
    1780                 : 
    1781                 : // helpers /////////////////////////////////////////////////////////////
    1782                 : 
    1783                 : NS_IMETHODIMP 
    1784               0 : nsMenuPopupFrame::AttributeChanged(PRInt32 aNameSpaceID,
    1785                 :                                    nsIAtom* aAttribute,
    1786                 :                                    PRInt32 aModType)
    1787                 : 
    1788                 : {
    1789                 :   nsresult rv = nsBoxFrame::AttributeChanged(aNameSpaceID, aAttribute,
    1790               0 :                                              aModType);
    1791                 :   
    1792               0 :   if (aAttribute == nsGkAtoms::left || aAttribute == nsGkAtoms::top)
    1793               0 :     MoveToAttributePosition();
    1794                 : 
    1795               0 :   if (aAttribute == nsGkAtoms::label) {
    1796                 :     // set the label for the titlebar
    1797               0 :     nsIView* view = GetView();
    1798               0 :     if (view) {
    1799               0 :       nsIWidget* widget = view->GetWidget();
    1800               0 :       if (widget) {
    1801               0 :         nsAutoString title;
    1802               0 :         mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::label, title);
    1803               0 :         if (!title.IsEmpty()) {
    1804               0 :           widget->SetTitle(title);
    1805                 :         }
    1806                 :       }
    1807                 :     }
    1808                 :   }
    1809                 : 
    1810               0 :   return rv;
    1811                 : }
    1812                 : 
    1813                 : void
    1814               0 : nsMenuPopupFrame::MoveToAttributePosition()
    1815                 : {
    1816                 :   // Move the widget around when the user sets the |left| and |top| attributes. 
    1817                 :   // Note that this is not the best way to move the widget, as it results in lots
    1818                 :   // of FE notifications and is likely to be slow as molasses. Use |moveTo| on
    1819                 :   // nsIPopupBoxObject if possible. 
    1820               0 :   nsAutoString left, top;
    1821               0 :   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::left, left);
    1822               0 :   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::top, top);
    1823                 :   PRInt32 err1, err2;
    1824               0 :   PRInt32 xpos = left.ToInteger(&err1);
    1825               0 :   PRInt32 ypos = top.ToInteger(&err2);
    1826                 : 
    1827               0 :   if (NS_SUCCEEDED(err1) && NS_SUCCEEDED(err2))
    1828               0 :     MoveTo(xpos, ypos, false);
    1829               0 : }
    1830                 : 
    1831                 : void
    1832               0 : nsMenuPopupFrame::DestroyFrom(nsIFrame* aDestructRoot)
    1833                 : {
    1834               0 :   nsIFrame* parent = GetParent();
    1835               0 :   if (parent && parent->GetType() == nsGkAtoms::menuFrame) {
    1836                 :     // clear the open attribute on the parent menu
    1837                 :     nsContentUtils::AddScriptRunner(
    1838               0 :       new nsUnsetAttrRunnable(parent->GetContent(), nsGkAtoms::open));
    1839                 :   }
    1840                 : 
    1841               0 :   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
    1842               0 :   if (pm)
    1843               0 :     pm->PopupDestroyed(this);
    1844                 : 
    1845                 :   nsIRootBox* rootBox =
    1846               0 :     nsIRootBox::GetRootBox(PresContext()->GetPresShell());
    1847               0 :   if (rootBox && rootBox->GetDefaultTooltip() == mContent) {
    1848               0 :     rootBox->SetDefaultTooltip(nsnull);
    1849                 :   }
    1850                 : 
    1851               0 :   nsBoxFrame::DestroyFrom(aDestructRoot);
    1852               0 : }
    1853                 : 
    1854                 : 
    1855                 : void
    1856               0 : nsMenuPopupFrame::MoveTo(PRInt32 aLeft, PRInt32 aTop, bool aUpdateAttrs)
    1857                 : {
    1858               0 :   nsIWidget* widget = GetWidget();
    1859               0 :   if ((mScreenXPos == aLeft && mScreenYPos == aTop) &&
    1860               0 :       (!widget || widget->GetClientOffset() == mLastClientOffset)) {
    1861               0 :     return;
    1862                 :   }
    1863                 : 
    1864                 :   // reposition the popup at the specified coordinates. Don't clear the anchor
    1865                 :   // and position, because the popup can be reset to its anchor position by
    1866                 :   // using (-1, -1) as coordinates. Subtract off the margin as it will be
    1867                 :   // added to the position when SetPopupPosition is called.
    1868               0 :   nsMargin margin(0, 0, 0, 0);
    1869               0 :   GetStyleMargin()->GetMargin(margin);
    1870               0 :   nsPresContext* presContext = PresContext();
    1871               0 :   mScreenXPos = aLeft - presContext->AppUnitsToIntCSSPixels(margin.left);
    1872               0 :   mScreenYPos = aTop - presContext->AppUnitsToIntCSSPixels(margin.top);
    1873                 : 
    1874               0 :   SetPopupPosition(nsnull, true);
    1875                 : 
    1876               0 :   nsCOMPtr<nsIContent> popup = mContent;
    1877               0 :   if (aUpdateAttrs && (popup->HasAttr(kNameSpaceID_None, nsGkAtoms::left) ||
    1878               0 :                        popup->HasAttr(kNameSpaceID_None, nsGkAtoms::top)))
    1879                 :   {
    1880               0 :     nsAutoString left, top;
    1881               0 :     left.AppendInt(aLeft);
    1882               0 :     top.AppendInt(aTop);
    1883               0 :     popup->SetAttr(kNameSpaceID_None, nsGkAtoms::left, left, false);
    1884               0 :     popup->SetAttr(kNameSpaceID_None, nsGkAtoms::top, top, false);
    1885                 :   }
    1886                 : }
    1887                 : 
    1888                 : bool
    1889               0 : nsMenuPopupFrame::GetAutoPosition()
    1890                 : {
    1891               0 :   return mShouldAutoPosition;
    1892                 : }
    1893                 : 
    1894                 : void
    1895               0 : nsMenuPopupFrame::SetAutoPosition(bool aShouldAutoPosition)
    1896                 : {
    1897               0 :   mShouldAutoPosition = aShouldAutoPosition;
    1898               0 : }
    1899                 : 
    1900                 : void
    1901               0 : nsMenuPopupFrame::SetConsumeRollupEvent(PRUint32 aConsumeMode)
    1902                 : {
    1903               0 :   mConsumeRollupEvent = aConsumeMode;
    1904               0 : }
    1905                 : 
    1906                 : /**
    1907                 :  * KEEP THIS IN SYNC WITH nsContainerFrame::CreateViewForFrame
    1908                 :  * as much as possible. Until we get rid of views finally...
    1909                 :  */
    1910                 : nsresult
    1911               0 : nsMenuPopupFrame::CreatePopupView()
    1912                 : {
    1913               0 :   if (HasView()) {
    1914               0 :     return NS_OK;
    1915                 :   }
    1916                 : 
    1917               0 :   nsIViewManager* viewManager = PresContext()->GetPresShell()->GetViewManager();
    1918               0 :   NS_ASSERTION(nsnull != viewManager, "null view manager");
    1919                 : 
    1920                 :   // Create a view
    1921               0 :   nsIView* parentView = viewManager->GetRootView();
    1922               0 :   nsViewVisibility visibility = nsViewVisibility_kHide;
    1923               0 :   PRInt32 zIndex = PR_INT32_MAX;
    1924               0 :   bool    autoZIndex = false;
    1925                 : 
    1926               0 :   NS_ASSERTION(parentView, "no parent view");
    1927                 : 
    1928                 :   // Create a view
    1929               0 :   nsIView *view = viewManager->CreateView(GetRect(), parentView, visibility);
    1930               0 :   if (view) {
    1931               0 :     viewManager->SetViewZIndex(view, autoZIndex, zIndex);
    1932                 :     // XXX put view last in document order until we can do better
    1933               0 :     viewManager->InsertChild(parentView, view, nsnull, true);
    1934                 :   }
    1935                 : 
    1936                 :   // Remember our view
    1937               0 :   SetView(view);
    1938                 : 
    1939               0 :   NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
    1940                 :     ("nsMenuPopupFrame::CreatePopupView: frame=%p view=%p", this, view));
    1941                 : 
    1942               0 :   if (!view)
    1943               0 :     return NS_ERROR_OUT_OF_MEMORY;
    1944                 : 
    1945               0 :   return NS_OK;
    1946                 : }

Generated by: LCOV version 1.7