LCOV - code coverage report
Current view: top level - layout/xul - nsXULPopupManager.h (source / functions) Hit Total Coverage
Test: output.info Lines: 2 55 3.6 %
Date: 2017-07-14 16:53:18 Functions: 1 31 3.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : /**
       7             :  * The XUL Popup Manager keeps track of all open popups.
       8             :  */
       9             : 
      10             : #ifndef nsXULPopupManager_h__
      11             : #define nsXULPopupManager_h__
      12             : 
      13             : #include "mozilla/Logging.h"
      14             : #include "nsIContent.h"
      15             : #include "nsIRollupListener.h"
      16             : #include "nsIDOMEventListener.h"
      17             : #include "nsPoint.h"
      18             : #include "nsCOMPtr.h"
      19             : #include "nsTArray.h"
      20             : #include "nsIObserver.h"
      21             : #include "nsITimer.h"
      22             : #include "nsIReflowCallback.h"
      23             : #include "nsThreadUtils.h"
      24             : #include "nsStyleConsts.h"
      25             : #include "nsWidgetInitData.h"
      26             : #include "mozilla/Attributes.h"
      27             : #include "Units.h"
      28             : 
      29             : // X.h defines KeyPress
      30             : #ifdef KeyPress
      31             : #undef KeyPress
      32             : #endif
      33             : 
      34             : /**
      35             :  * There are two types that are used:
      36             :  *   - dismissable popups such as menus, which should close up when there is a
      37             :  *     click outside the popup. In this situation, the entire chain of menus
      38             :  *     above should also be closed.
      39             :  *   - panels, which stay open until a request is made to close them. This
      40             :  *     type is used by tooltips.
      41             :  *
      42             :  * When a new popup is opened, it is appended to the popup chain, stored in a
      43             :  * linked list in mPopups.
      44             :  * Popups are stored in this list linked from newest to oldest. When a click
      45             :  * occurs outside one of the open dismissable popups, the chain is closed by
      46             :  * calling Rollup.
      47             :  */
      48             : 
      49             : class nsContainerFrame;
      50             : class nsMenuFrame;
      51             : class nsMenuPopupFrame;
      52             : class nsMenuBarFrame;
      53             : class nsMenuParent;
      54             : class nsIDOMKeyEvent;
      55             : class nsIDocShellTreeItem;
      56             : class nsPIDOMWindowOuter;
      57             : class nsRefreshDriver;
      58             : 
      59             : // when a menu command is executed, the closemenu attribute may be used
      60             : // to define how the menu should be closed up
      61             : enum CloseMenuMode {
      62             :   CloseMenuMode_Auto, // close up the chain of menus, default value
      63             :   CloseMenuMode_None, // don't close up any menus
      64             :   CloseMenuMode_Single // close up only the menu the command is inside
      65             : };
      66             : 
      67             : /**
      68             :  * nsNavigationDirection: an enum expressing navigation through the menus in
      69             :  * terms which are independent of the directionality of the chrome. The
      70             :  * terminology, derived from XSL-FO and CSS3 (e.g.
      71             :  * http://www.w3.org/TR/css3-text/#TextLayout), is BASE (Before, After, Start,
      72             :  * End), with the addition of First and Last (mapped to Home and End
      73             :  * respectively).
      74             :  *
      75             :  * In languages such as English where the inline progression is left-to-right
      76             :  * and the block progression is top-to-bottom (lr-tb), these terms will map out
      77             :  * as in the following diagram
      78             :  *
      79             :  *  --- inline progression --->
      80             :  *
      81             :  *           First              |
      82             :  *           ...                |
      83             :  *           Before             |
      84             :  *         +--------+         block
      85             :  *   Start |        | End  progression
      86             :  *         +--------+           |
      87             :  *           After              |
      88             :  *           ...                |
      89             :  *           Last               V
      90             :  *
      91             :  */
      92             : 
      93             : enum nsNavigationDirection {
      94             :   eNavigationDirection_Last,
      95             :   eNavigationDirection_First,
      96             :   eNavigationDirection_Start,
      97             :   eNavigationDirection_Before,
      98             :   eNavigationDirection_End,
      99             :   eNavigationDirection_After
     100             : };
     101             : 
     102             : enum nsIgnoreKeys {
     103             :   eIgnoreKeys_False,
     104             :   eIgnoreKeys_True,
     105             :   eIgnoreKeys_Shortcuts,
     106             : };
     107             : 
     108             : #define NS_DIRECTION_IS_INLINE(dir) (dir == eNavigationDirection_Start ||     \
     109             :                                      dir == eNavigationDirection_End)
     110             : #define NS_DIRECTION_IS_BLOCK(dir) (dir == eNavigationDirection_Before || \
     111             :                                     dir == eNavigationDirection_After)
     112             : #define NS_DIRECTION_IS_BLOCK_TO_EDGE(dir) (dir == eNavigationDirection_First ||    \
     113             :                                             dir == eNavigationDirection_Last)
     114             : 
     115             : static_assert(NS_STYLE_DIRECTION_LTR == 0 && NS_STYLE_DIRECTION_RTL == 1,
     116             :               "Left to Right should be 0 and Right to Left should be 1");
     117             : 
     118             : /**
     119             :  * DirectionFromKeyCodeTable: two arrays, the first for left-to-right and the
     120             :  * other for right-to-left, that map keycodes to values of
     121             :  * nsNavigationDirection.
     122             :  */
     123             : extern const nsNavigationDirection DirectionFromKeyCodeTable[2][6];
     124             : 
     125             : #define NS_DIRECTION_FROM_KEY_CODE(frame, keycode)                     \
     126             :   (DirectionFromKeyCodeTable[frame->StyleVisibility()->mDirection]  \
     127             :                             [keycode - nsIDOMKeyEvent::DOM_VK_END])
     128             : 
     129             : // nsMenuChainItem holds info about an open popup. Items are stored in a
     130             : // doubly linked list. Note that the linked list is stored beginning from
     131             : // the lowest child in a chain of menus, as this is the active submenu.
     132             : class nsMenuChainItem
     133             : {
     134             : private:
     135             :   nsMenuPopupFrame* mFrame; // the popup frame
     136             :   nsPopupType mPopupType; // the popup type of the frame
     137             :   bool mNoAutoHide; // true for noautohide panels
     138             :   bool mIsContext; // true for context menus
     139             :   bool mOnMenuBar; // true if the menu is on a menu bar
     140             :   nsIgnoreKeys mIgnoreKeys; // indicates how keyboard listeners should be used
     141             : 
     142             :   // True if the popup should maintain its position relative to the anchor when
     143             :   // the anchor moves.
     144             :   bool mFollowAnchor;
     145             : 
     146             :   // The last seen position of the anchor, relative to the screen.
     147             :   nsRect mCurrentRect;
     148             : 
     149             :   nsMenuChainItem* mParent;
     150             :   nsMenuChainItem* mChild;
     151             : 
     152             : public:
     153           0 :   nsMenuChainItem(nsMenuPopupFrame* aFrame, bool aNoAutoHide, bool aIsContext,
     154             :                   nsPopupType aPopupType)
     155           0 :     : mFrame(aFrame),
     156             :       mPopupType(aPopupType),
     157             :       mNoAutoHide(aNoAutoHide),
     158             :       mIsContext(aIsContext),
     159             :       mOnMenuBar(false),
     160             :       mIgnoreKeys(eIgnoreKeys_False),
     161             :       mFollowAnchor(false),
     162             :       mParent(nullptr),
     163           0 :       mChild(nullptr)
     164             :   {
     165           0 :     NS_ASSERTION(aFrame, "null frame passed to nsMenuChainItem constructor");
     166           0 :     MOZ_COUNT_CTOR(nsMenuChainItem);
     167           0 :   }
     168             : 
     169           0 :   ~nsMenuChainItem()
     170           0 :   {
     171           0 :     MOZ_COUNT_DTOR(nsMenuChainItem);
     172           0 :   }
     173             : 
     174             :   nsIContent* Content();
     175           0 :   nsMenuPopupFrame* Frame() { return mFrame; }
     176           0 :   nsPopupType PopupType() { return mPopupType; }
     177           0 :   bool IsNoAutoHide() { return mNoAutoHide; }
     178           0 :   void SetNoAutoHide(bool aNoAutoHide) { mNoAutoHide = aNoAutoHide; }
     179           0 :   bool IsMenu() { return mPopupType == ePopupTypeMenu; }
     180           0 :   bool IsContextMenu() { return mIsContext; }
     181           0 :   nsIgnoreKeys IgnoreKeys() { return mIgnoreKeys; }
     182           0 :   void SetIgnoreKeys(nsIgnoreKeys aIgnoreKeys) { mIgnoreKeys = aIgnoreKeys; }
     183             :   bool IsOnMenuBar() { return mOnMenuBar; }
     184           0 :   void SetOnMenuBar(bool aOnMenuBar) { mOnMenuBar = aOnMenuBar; }
     185           0 :   nsMenuChainItem* GetParent() { return mParent; }
     186           0 :   nsMenuChainItem* GetChild() { return mChild; }
     187             :   bool FollowsAnchor() { return mFollowAnchor; }
     188             :   void UpdateFollowAnchor();
     189             :   void CheckForAnchorChange();
     190             : 
     191             :   // set the parent of this item to aParent, also changing the parent
     192             :   // to have this as a child.
     193             :   void SetParent(nsMenuChainItem* aParent);
     194             : 
     195             :   // Removes an item from the chain. The root pointer must be supplied in case
     196             :   // the item is the first item in the chain in which case the pointer will be
     197             :   // set to the next item, or null if there isn't another item. After detaching,
     198             :   // this item will not have a parent or a child.
     199             :   void Detach(nsMenuChainItem** aRoot);
     200             : };
     201             : 
     202             : // this class is used for dispatching popupshowing events asynchronously.
     203           0 : class nsXULPopupShowingEvent : public mozilla::Runnable
     204             : {
     205             : public:
     206           0 :   nsXULPopupShowingEvent(nsIContent* aPopup,
     207             :                          bool aIsContextMenu,
     208             :                          bool aSelectFirstItem)
     209           0 :     : mozilla::Runnable("nsXULPopupShowingEvent")
     210             :     , mPopup(aPopup)
     211             :     , mIsContextMenu(aIsContextMenu)
     212           0 :     , mSelectFirstItem(aSelectFirstItem)
     213             :   {
     214           0 :     NS_ASSERTION(aPopup, "null popup supplied to nsXULPopupShowingEvent constructor");
     215           0 :   }
     216             : 
     217             :   NS_IMETHOD Run() override;
     218             : 
     219             : private:
     220             :   nsCOMPtr<nsIContent> mPopup;
     221             :   bool mIsContextMenu;
     222             :   bool mSelectFirstItem;
     223             : };
     224             : 
     225             : // this class is used for dispatching popuphiding events asynchronously.
     226           0 : class nsXULPopupHidingEvent : public mozilla::Runnable
     227             : {
     228             : public:
     229           0 :   nsXULPopupHidingEvent(nsIContent* aPopup,
     230             :                         nsIContent* aNextPopup,
     231             :                         nsIContent* aLastPopup,
     232             :                         nsPopupType aPopupType,
     233             :                         bool aDeselectMenu,
     234             :                         bool aIsCancel)
     235           0 :     : mozilla::Runnable("nsXULPopupHidingEvent")
     236             :     , mPopup(aPopup)
     237             :     , mNextPopup(aNextPopup)
     238             :     , mLastPopup(aLastPopup)
     239             :     , mPopupType(aPopupType)
     240             :     , mDeselectMenu(aDeselectMenu)
     241           0 :     , mIsRollup(aIsCancel)
     242             :   {
     243           0 :     NS_ASSERTION(aPopup, "null popup supplied to nsXULPopupHidingEvent constructor");
     244             :     // aNextPopup and aLastPopup may be null
     245           0 :   }
     246             : 
     247             :   NS_IMETHOD Run() override;
     248             : 
     249             : private:
     250             :   nsCOMPtr<nsIContent> mPopup;
     251             :   nsCOMPtr<nsIContent> mNextPopup;
     252             :   nsCOMPtr<nsIContent> mLastPopup;
     253             :   nsPopupType mPopupType;
     254             :   bool mDeselectMenu;
     255             :   bool mIsRollup;
     256             : };
     257             : 
     258             : // this class is used for dispatching popuppositioned events asynchronously.
     259           0 : class nsXULPopupPositionedEvent : public mozilla::Runnable
     260             : {
     261             : public:
     262           0 :   explicit nsXULPopupPositionedEvent(nsIContent* aPopup,
     263             :                                      bool aIsContextMenu,
     264             :                                      bool aSelectFirstItem)
     265           0 :     : mozilla::Runnable("nsXULPopupPositionedEvent")
     266             :     , mPopup(aPopup)
     267             :     , mIsContextMenu(aIsContextMenu)
     268           0 :     , mSelectFirstItem(aSelectFirstItem)
     269             :   {
     270           0 :     NS_ASSERTION(aPopup, "null popup supplied to nsXULPopupShowingEvent constructor");
     271           0 :   }
     272             : 
     273             :   NS_IMETHOD Run() override;
     274             : 
     275             :   // Asynchronously dispatch a popuppositioned event at aPopup if this is a
     276             :   // panel that should receieve such events. Return true if the event was sent.
     277             :   static bool DispatchIfNeeded(nsIContent *aPopup,
     278             :                                bool aIsContextMenu,
     279             :                                bool aSelectFirstItem);
     280             : 
     281             : private:
     282             :   nsCOMPtr<nsIContent> mPopup;
     283             :   bool mIsContextMenu;
     284             :   bool mSelectFirstItem;
     285             : };
     286             : 
     287             : // this class is used for dispatching menu command events asynchronously.
     288           0 : class nsXULMenuCommandEvent : public mozilla::Runnable
     289             : {
     290             : public:
     291           0 :   nsXULMenuCommandEvent(nsIContent* aMenu,
     292             :                         bool aIsTrusted,
     293             :                         bool aShift,
     294             :                         bool aControl,
     295             :                         bool aAlt,
     296             :                         bool aMeta,
     297             :                         bool aUserInput,
     298             :                         bool aFlipChecked)
     299           0 :     : mozilla::Runnable("nsXULMenuCommandEvent")
     300             :     , mMenu(aMenu)
     301             :     , mIsTrusted(aIsTrusted)
     302             :     , mShift(aShift)
     303             :     , mControl(aControl)
     304             :     , mAlt(aAlt)
     305             :     , mMeta(aMeta)
     306             :     , mUserInput(aUserInput)
     307             :     , mFlipChecked(aFlipChecked)
     308           0 :     , mCloseMenuMode(CloseMenuMode_Auto)
     309             :   {
     310           0 :     NS_ASSERTION(aMenu, "null menu supplied to nsXULMenuCommandEvent constructor");
     311           0 :   }
     312             : 
     313             :   NS_IMETHOD Run() override;
     314             : 
     315           0 :   void SetCloseMenuMode(CloseMenuMode aCloseMenuMode) { mCloseMenuMode = aCloseMenuMode; }
     316             : 
     317             : private:
     318             :   nsCOMPtr<nsIContent> mMenu;
     319             :   bool mIsTrusted;
     320             :   bool mShift;
     321             :   bool mControl;
     322             :   bool mAlt;
     323             :   bool mMeta;
     324             :   bool mUserInput;
     325             :   bool mFlipChecked;
     326             :   CloseMenuMode mCloseMenuMode;
     327             : };
     328             : 
     329             : class nsXULPopupManager final : public nsIDOMEventListener,
     330             :                                 public nsIRollupListener,
     331             :                                 public nsIObserver
     332             : {
     333             : 
     334             : public:
     335             :   friend class nsXULPopupShowingEvent;
     336             :   friend class nsXULPopupHidingEvent;
     337             :   friend class nsXULPopupPositionedEvent;
     338             :   friend class nsXULMenuCommandEvent;
     339             :   friend class TransitionEnder;
     340             : 
     341             :   NS_DECL_ISUPPORTS
     342             :   NS_DECL_NSIOBSERVER
     343             :   NS_DECL_NSIDOMEVENTLISTENER
     344             : 
     345             :   // nsIRollupListener
     346             :   virtual bool Rollup(uint32_t aCount, bool aFlush,
     347             :                       const nsIntPoint* pos, nsIContent** aLastRolledUp) override;
     348             :   virtual bool ShouldRollupOnMouseWheelEvent() override;
     349             :   virtual bool ShouldConsumeOnMouseWheelEvent() override;
     350             :   virtual bool ShouldRollupOnMouseActivate() override;
     351             :   virtual uint32_t GetSubmenuWidgetChain(nsTArray<nsIWidget*> *aWidgetChain) override;
     352           0 :   virtual void NotifyGeometryChange() override {}
     353             :   virtual nsIWidget* GetRollupWidget() override;
     354             : 
     355             :   static nsXULPopupManager* sInstance;
     356             : 
     357             :   // initialize and shutdown methods called by nsLayoutStatics
     358             :   static nsresult Init();
     359             :   static void Shutdown();
     360             : 
     361             :   // returns a weak reference to the popup manager instance, could return null
     362             :   // if a popup manager could not be allocated
     363             :   static nsXULPopupManager* GetInstance();
     364             : 
     365             :   // This should be called when a window is moved or resized to adjust the
     366             :   // popups accordingly.
     367             :   void AdjustPopupsOnWindowChange(nsPIDOMWindowOuter* aWindow);
     368             :   void AdjustPopupsOnWindowChange(nsIPresShell* aPresShell);
     369             : 
     370             :   // given a menu frame, find the prevous or next menu frame. If aPopup is
     371             :   // true then navigate a menupopup, from one item on the menu to the previous
     372             :   // or next one. This is used for cursor navigation between items in a popup
     373             :   // menu. If aIsPopup is false, the navigation is on a menubar, so navigate
     374             :   // between menus on the menubar. This is used for left/right cursor navigation.
     375             :   //
     376             :   // Items that are not valid, such as non-menu or non-menuitem elements are
     377             :   // skipped, and the next or previous item after that is checked.
     378             :   //
     379             :   // If aStart is null, the first valid item is retrieved by GetNextMenuItem
     380             :   // and the last valid item is retrieved by GetPreviousMenuItem.
     381             :   //
     382             :   // Both methods will loop around the beginning or end if needed.
     383             :   //
     384             :   // aParent - the parent menubar or menupopup
     385             :   // aStart - the menu/menuitem to start navigation from. GetPreviousMenuItem
     386             :   //          returns the item before it, while GetNextMenuItem returns the
     387             :   //          item after it.
     388             :   // aIsPopup - true for menupopups, false for menubars
     389             :   // aWrap - true to wrap around to the beginning and continue searching if not
     390             :   //         found. False to end at the beginning or end of the menu.
     391             :   static nsMenuFrame* GetPreviousMenuItem(nsContainerFrame* aParent,
     392             :                                           nsMenuFrame* aStart,
     393             :                                           bool aIsPopup,
     394             :                                           bool aWrap);
     395             :   static nsMenuFrame* GetNextMenuItem(nsContainerFrame* aParent,
     396             :                                       nsMenuFrame* aStart,
     397             :                                       bool aIsPopup,
     398             :                                       bool aWrap);
     399             : 
     400             :   // returns true if the menu item aContent is a valid menuitem which may
     401             :   // be navigated to. aIsPopup should be true for items on a popup, or false
     402             :   // for items on a menubar.
     403             :   static bool IsValidMenuItem(nsIContent* aContent, bool aOnPopup);
     404             : 
     405             :   // inform the popup manager that a menu bar has been activated or deactivated,
     406             :   // either because one of its menus has opened or closed, or that the menubar
     407             :   // has been focused such that its menus may be navigated with the keyboard.
     408             :   // aActivate should be true when the menubar should be focused, and false
     409             :   // when the active menu bar should be defocused. In the latter case, if
     410             :   // aMenuBar isn't currently active, yet another menu bar is, that menu bar
     411             :   // will remain active.
     412             :   void SetActiveMenuBar(nsMenuBarFrame* aMenuBar, bool aActivate);
     413             : 
     414             :   // retrieve the node and offset of the last mouse event used to open a
     415             :   // context menu. This information is determined from the rangeParent and
     416             :   // the rangeOffset of the event supplied to ShowPopup or ShowPopupAtScreen.
     417             :   // This is used by the implementation of nsIDOMXULDocument::GetPopupRangeParent
     418             :   // and nsIDOMXULDocument::GetPopupRangeOffset.
     419             :   void GetMouseLocation(nsIDOMNode** aNode, int32_t* aOffset);
     420             : 
     421             :   /**
     422             :    * Open a <menu> given its content node. If aSelectFirstItem is
     423             :    * set to true, the first item on the menu will automatically be
     424             :    * selected. If aAsynchronous is true, the event will be dispatched
     425             :    * asynchronously. This should be true when called from frame code.
     426             :    */
     427             :   void ShowMenu(nsIContent *aMenu, bool aSelectFirstItem, bool aAsynchronous);
     428             : 
     429             :   /**
     430             :    * Open a popup, either anchored or unanchored. If aSelectFirstItem is
     431             :    * true, then the first item in the menu is selected. The arguments are
     432             :    * similar to those for nsIPopupBoxObject::OpenPopup.
     433             :    *
     434             :    * aTriggerEvent should be the event that triggered the event. This is used
     435             :    * to determine the coordinates and trigger node for the popup. This may be
     436             :    * null if the popup was not triggered by an event.
     437             :    *
     438             :    * This fires the popupshowing event synchronously.
     439             :    */
     440             :   void ShowPopup(nsIContent* aPopup,
     441             :                  nsIContent* aAnchorContent,
     442             :                  const nsAString& aPosition,
     443             :                  int32_t aXPos, int32_t aYPos,
     444             :                  bool aIsContextMenu,
     445             :                  bool aAttributesOverride,
     446             :                  bool aSelectFirstItem,
     447             :                  nsIDOMEvent* aTriggerEvent);
     448             : 
     449             :   /**
     450             :    * Open a popup at a specific screen position specified by aXPos and aYPos,
     451             :    * measured in CSS pixels.
     452             :    *
     453             :    * This fires the popupshowing event synchronously.
     454             :    *
     455             :    * If aIsContextMenu is true, the popup is positioned at a slight
     456             :    * offset from aXPos/aYPos to ensure that it is not under the mouse
     457             :    * cursor.
     458             :    */
     459             :   void ShowPopupAtScreen(nsIContent* aPopup,
     460             :                          int32_t aXPos, int32_t aYPos,
     461             :                          bool aIsContextMenu,
     462             :                          nsIDOMEvent* aTriggerEvent);
     463             : 
     464             :   /* Open a popup anchored at a screen rectangle specified by aRect.
     465             :    * The remaining arguments are similar to ShowPopup.
     466             :    */
     467             :   void ShowPopupAtScreenRect(nsIContent* aPopup,
     468             :                              const nsAString& aPosition,
     469             :                              const nsIntRect& aRect,
     470             :                              bool aIsContextMenu,
     471             :                              bool aAttributesOverride,
     472             :                              nsIDOMEvent* aTriggerEvent);
     473             : 
     474             :   /**
     475             :    * Open a tooltip at a specific screen position specified by aXPos and aYPos,
     476             :    * measured in CSS pixels.
     477             :    *
     478             :    * This fires the popupshowing event synchronously.
     479             :    */
     480             :   void ShowTooltipAtScreen(nsIContent* aPopup,
     481             :                            nsIContent* aTriggerContent,
     482             :                            int32_t aXPos, int32_t aYPos);
     483             : 
     484             :   /**
     485             :    * This method is provided only for compatibility with an older popup API.
     486             :    * New code should not call this function and should call ShowPopup instead.
     487             :    *
     488             :    * This fires the popupshowing event synchronously.
     489             :    */
     490             :   void ShowPopupWithAnchorAlign(nsIContent* aPopup,
     491             :                                 nsIContent* aAnchorContent,
     492             :                                 nsAString& aAnchor,
     493             :                                 nsAString& aAlign,
     494             :                                 int32_t aXPos, int32_t aYPos,
     495             :                                 bool aIsContextMenu);
     496             : 
     497             :   /*
     498             :    * Hide a popup aPopup. If the popup is in a <menu>, then also inform the
     499             :    * menu that the popup is being hidden.
     500             :    *
     501             :    * aHideChain - true if the entire chain of menus should be closed. If false,
     502             :    *              only this popup is closed.
     503             :    * aDeselectMenu - true if the parent <menu> of the popup should be deselected.
     504             :    *                 This will be false when the menu is closed by pressing the
     505             :    *                 Escape key.
     506             :    * aAsynchronous - true if the first popuphiding event should be sent
     507             :    *                 asynchrously. This should be true if HidePopup is called
     508             :    *                 from a frame.
     509             :    * aIsCancel - true if this popup is hiding due to being cancelled.
     510             :    * aLastPopup - optional popup to close last when hiding a chain of menus.
     511             :    *              If null, then all popups will be closed.
     512             :    */
     513             :   void HidePopup(nsIContent* aPopup,
     514             :                  bool aHideChain,
     515             :                  bool aDeselectMenu,
     516             :                  bool aAsynchronous,
     517             :                  bool aIsCancel,
     518             :                  nsIContent* aLastPopup = nullptr);
     519             : 
     520             :   /**
     521             :    * Hide a popup after a short delay. This is used when rolling over menu items.
     522             :    * This timer is stored in mCloseTimer. The timer may be cancelled and the popup
     523             :    * closed by calling KillMenuTimer.
     524             :    */
     525             :   void HidePopupAfterDelay(nsMenuPopupFrame* aPopup);
     526             : 
     527             :   /**
     528             :    * Hide all of the popups from a given docshell. This should be called when the
     529             :    * document is hidden.
     530             :    */
     531             :   void HidePopupsInDocShell(nsIDocShellTreeItem* aDocShellToHide);
     532             : 
     533             :   /**
     534             :    * Enable or disable the dynamic noautohide state of a panel.
     535             :    *
     536             :    * aPanel - the panel whose state is to change
     537             :    * aShouldRollup - whether the panel is no longer noautohide
     538             :    */
     539             :   void EnableRollup(nsIContent* aPopup, bool aShouldRollup);
     540             : 
     541             :   /**
     542             :    * Check if any popups need to be repositioned or hidden after a style or
     543             :    * layout change. This will update, for example, any arrow type panels when
     544             :    * the anchor that is is pointing to has moved, resized or gone away.
     545             :    * Only those popups that pertain to the supplied aRefreshDriver are updated.
     546             :    */
     547             :   void UpdatePopupPositions(nsRefreshDriver* aRefreshDriver);
     548             : 
     549             :   /**
     550             :    * Enable or disable anchor following on the popup if needed.
     551             :    */
     552             :   void UpdateFollowAnchor(nsMenuPopupFrame* aPopup);
     553             : 
     554             :   /**
     555             :    * Execute a menu command from the triggering event aEvent.
     556             :    *
     557             :    * aMenu - a menuitem to execute
     558             :    * aEvent - an nsXULMenuCommandEvent that contains all the info from the mouse
     559             :    *          event which triggered the menu to be executed, may not be null
     560             :    */
     561             :   void ExecuteMenu(nsIContent* aMenu, nsXULMenuCommandEvent* aEvent);
     562             : 
     563             :   /**
     564             :    * Return true if the popup for the supplied content node is open.
     565             :    */
     566             :   bool IsPopupOpen(nsIContent* aPopup);
     567             : 
     568             :   /**
     569             :    * Return true if the popup for the supplied menu parent is open.
     570             :    */
     571             :   bool IsPopupOpenForMenuParent(nsMenuParent* aMenuParent);
     572             : 
     573             :   /**
     574             :    * Return the frame for the topmost open popup of a given type, or null if
     575             :    * no popup of that type is open. If aType is ePopupTypeAny, a menu of any
     576             :    * type is returned.
     577             :    */
     578             :   nsIFrame* GetTopPopup(nsPopupType aType);
     579             : 
     580             :   /**
     581             :    * Return an array of all the open and visible popup frames for
     582             :    * menus, in order from top to bottom.
     583             :    */
     584             :   void GetVisiblePopups(nsTArray<nsIFrame *>& aPopups);
     585             : 
     586             :   /**
     587             :    * Get the node that last triggered a popup or tooltip in the document
     588             :    * aDocument. aDocument must be non-null and be a document contained within
     589             :    * the same window hierarchy as the popup to retrieve.
     590             :    */
     591          11 :   already_AddRefed<nsIDOMNode> GetLastTriggerPopupNode(nsIDocument* aDocument)
     592             :   {
     593          11 :     return GetLastTriggerNode(aDocument, false);
     594             :   }
     595             : 
     596           0 :   already_AddRefed<nsIDOMNode> GetLastTriggerTooltipNode(nsIDocument* aDocument)
     597             :   {
     598           0 :     return GetLastTriggerNode(aDocument, true);
     599             :   }
     600             : 
     601             :   /**
     602             :    * Return false if a popup may not be opened. This will return false if the
     603             :    * popup is already open, if the popup is in a content shell that is not
     604             :    * focused, or if it is a submenu of another menu that isn't open.
     605             :    */
     606             :   bool MayShowPopup(nsMenuPopupFrame* aFrame);
     607             : 
     608             :   /**
     609             :    * Indicate that the popup associated with aView has been moved to the
     610             :    * specified screen coordiates.
     611             :    */
     612             :   void PopupMoved(nsIFrame* aFrame, nsIntPoint aPoint);
     613             : 
     614             :   /**
     615             :    * Indicate that the popup associated with aView has been resized to the
     616             :    * given device pixel size aSize.
     617             :    */
     618             :   void PopupResized(nsIFrame* aFrame, mozilla::LayoutDeviceIntSize aSize);
     619             : 
     620             :   /**
     621             :    * Called when a popup frame is destroyed. In this case, just remove the
     622             :    * item and later popups from the list. No point going through HidePopup as
     623             :    * the frames have gone away.
     624             :    */
     625             :   void PopupDestroyed(nsMenuPopupFrame* aFrame);
     626             : 
     627             :   /**
     628             :    * Returns true if there is a context menu open. If aPopup is specified,
     629             :    * then the context menu must be later in the chain than aPopup. If aPopup
     630             :    * is null, returns true if any context menu at all is open.
     631             :    */
     632             :   bool HasContextMenu(nsMenuPopupFrame* aPopup);
     633             : 
     634             :   /**
     635             :    * Update the commands for the menus within the menu popup for a given
     636             :    * content node. aPopup should be a XUL menupopup element. This method
     637             :    * changes attributes on the children of aPopup, and deals only with the
     638             :    * content of the popup, not the frames.
     639             :    */
     640             :   void UpdateMenuItems(nsIContent* aPopup);
     641             : 
     642             :   /**
     643             :    * Stop the timer which hides a popup after a delay, started by a previous
     644             :    * call to HidePopupAfterDelay. In addition, the popup awaiting to be hidden
     645             :    * is closed asynchronously.
     646             :    */
     647             :   void KillMenuTimer();
     648             : 
     649             :   /**
     650             :    * Cancel the timer which closes menus after delay, but only if the menu to
     651             :    * close is aMenuParent. When a submenu is opened, the user might move the
     652             :    * mouse over a sibling menuitem which would normally close the menu. This
     653             :    * menu is closed via a timer. However, if the user moves the mouse over the
     654             :    * submenu before the timer fires, we should instead cancel the timer. This
     655             :    * ensures that the user can move the mouse diagonally over a menu.
     656             :    */
     657             :   void CancelMenuTimer(nsMenuParent* aMenuParent);
     658             : 
     659             :   /**
     660             :    * Handles navigation for menu accelkeys. If aFrame is specified, then the
     661             :    * key is handled by that popup, otherwise if aFrame is null, the key is
     662             :    * handled by the active popup or menubar.
     663             :    */
     664             :   bool HandleShortcutNavigation(nsIDOMKeyEvent* aKeyEvent,
     665             :                                 nsMenuPopupFrame* aFrame);
     666             : 
     667             :   /**
     668             :    * Handles cursor navigation within a menu. Returns true if the key has
     669             :    * been handled.
     670             :    */
     671             :   bool HandleKeyboardNavigation(uint32_t aKeyCode);
     672             : 
     673             :   /**
     674             :    * Handle keyboard navigation within a menu popup specified by aFrame.
     675             :    * Returns true if the key was handled and other default handling
     676             :    * should not occur.
     677             :    */
     678           0 :   bool HandleKeyboardNavigationInPopup(nsMenuPopupFrame* aFrame,
     679             :                                          nsNavigationDirection aDir)
     680             :   {
     681           0 :     return HandleKeyboardNavigationInPopup(nullptr, aFrame, aDir);
     682             :   }
     683             : 
     684             :   /**
     685             :    * Handles the keyboard event with keyCode value. Returns true if the event
     686             :    * has been handled.
     687             :    */
     688             :   bool HandleKeyboardEventWithKeyCode(nsIDOMKeyEvent* aKeyEvent,
     689             :                                       nsMenuChainItem* aTopVisibleMenuItem);
     690             : 
     691             :   // Sets mIgnoreKeys of the Top Visible Menu Item
     692             :   nsresult UpdateIgnoreKeys(bool aIgnoreKeys);
     693             : 
     694             :   nsresult KeyUp(nsIDOMKeyEvent* aKeyEvent);
     695             :   nsresult KeyDown(nsIDOMKeyEvent* aKeyEvent);
     696             :   nsresult KeyPress(nsIDOMKeyEvent* aKeyEvent);
     697             : 
     698             : protected:
     699             :   nsXULPopupManager();
     700             :   ~nsXULPopupManager();
     701             : 
     702             :   // get the nsMenuPopupFrame, if any, for the given content node
     703             :   nsMenuPopupFrame* GetPopupFrameForContent(nsIContent* aContent, bool aShouldFlush);
     704             : 
     705             :   // return the topmost menu, skipping over invisible popups
     706             :   nsMenuChainItem* GetTopVisibleMenu();
     707             : 
     708             :   // Hide all of the visible popups from the given list. This function can
     709             :   // cause style changes and frame destruction.
     710             :   void HidePopupsInList(const nsTArray<nsMenuPopupFrame *> &aFrames);
     711             : 
     712             :   // set the event that was used to trigger the popup, or null to clear the
     713             :   // event details. aTriggerContent will be set to the target of the event.
     714             :   void InitTriggerEvent(nsIDOMEvent* aEvent, nsIContent* aPopup, nsIContent** aTriggerContent);
     715             : 
     716             :   // callbacks for ShowPopup and HidePopup as events may be done asynchronously
     717             :   void ShowPopupCallback(nsIContent* aPopup,
     718             :                          nsMenuPopupFrame* aPopupFrame,
     719             :                          bool aIsContextMenu,
     720             :                          bool aSelectFirstItem);
     721             :   void HidePopupCallback(nsIContent* aPopup,
     722             :                          nsMenuPopupFrame* aPopupFrame,
     723             :                          nsIContent* aNextPopup,
     724             :                          nsIContent* aLastPopup,
     725             :                          nsPopupType aPopupType,
     726             :                          bool aDeselectMenu);
     727             : 
     728             :   /**
     729             :    * Fire a popupshowing event on the popup and then open the popup.
     730             :    *
     731             :    * aPopup - the popup to open
     732             :    * aIsContextMenu - true for context menus
     733             :    * aSelectFirstItem - true to select the first item in the menu
     734             :    * aTriggerEvent - the event that triggered the showing event.
     735             :    *                 This is currently used to propagate the
     736             :    *                 inputSource attribute. May be null.
     737             :    */
     738             :   void FirePopupShowingEvent(nsIContent* aPopup,
     739             :                              bool aIsContextMenu,
     740             :                              bool aSelectFirstItem,
     741             :                              nsIDOMEvent* aTriggerEvent);
     742             : 
     743             :   /**
     744             :    * Fire a popuphiding event and then hide the popup. This will be called
     745             :    * recursively if aNextPopup and aLastPopup are set in order to hide a chain
     746             :    * of open menus. If these are not set, only one popup is closed. However,
     747             :    * if the popup type indicates a menu, yet the next popup is not a menu,
     748             :    * then this ends the closing of popups. This allows a menulist inside a
     749             :    * non-menu to close up the menu but not close up the panel it is contained
     750             :    * within.
     751             :    *
     752             :    * The caller must keep a strong reference to aPopup, aNextPopup and aLastPopup.
     753             :    *
     754             :    * aPopup - the popup to hide
     755             :    * aNextPopup - the next popup to hide
     756             :    * aLastPopup - the last popup in the chain to hide
     757             :    * aPresContext - nsPresContext for the popup's frame
     758             :    * aPopupType - the PopupType of the frame.
     759             :    * aDeselectMenu - true to unhighlight the menu when hiding it
     760             :    * aIsCancel - true if this popup is hiding due to being cancelled.
     761             :    */
     762             :   void FirePopupHidingEvent(nsIContent* aPopup,
     763             :                             nsIContent* aNextPopup,
     764             :                             nsIContent* aLastPopup,
     765             :                             nsPresContext *aPresContext,
     766             :                             nsPopupType aPopupType,
     767             :                             bool aDeselectMenu,
     768             :                             bool aIsCancel);
     769             : 
     770             :   /**
     771             :    * Handle keyboard navigation within a menu popup specified by aItem.
     772             :    */
     773           0 :   bool HandleKeyboardNavigationInPopup(nsMenuChainItem* aItem,
     774             :                                          nsNavigationDirection aDir)
     775             :   {
     776           0 :     return HandleKeyboardNavigationInPopup(aItem, aItem->Frame(), aDir);
     777             :   }
     778             : 
     779             : private:
     780             :   /**
     781             :    * Handle keyboard navigation within a menu popup aFrame. If aItem is
     782             :    * supplied, then it is expected to have a frame equal to aFrame.
     783             :    * If aItem is non-null, then the navigation may be redirected to
     784             :    * an open submenu if one exists. Returns true if the key was
     785             :    * handled and other default handling should not occur.
     786             :    */
     787             :   bool HandleKeyboardNavigationInPopup(nsMenuChainItem* aItem,
     788             :                                          nsMenuPopupFrame* aFrame,
     789             :                                          nsNavigationDirection aDir);
     790             : 
     791             : protected:
     792             : 
     793             :   already_AddRefed<nsIDOMNode> GetLastTriggerNode(nsIDocument* aDocument, bool aIsTooltip);
     794             : 
     795             :   /**
     796             :    * Set mouse capturing for the current popup. This traps mouse clicks that
     797             :    * occur outside the popup so that it can be closed up. aOldPopup should be
     798             :    * set to the popup that was previously the current popup.
     799             :    */
     800             :   void SetCaptureState(nsIContent *aOldPopup);
     801             : 
     802             :   /**
     803             :    * Key event listeners are attached to the document containing the current
     804             :    * menu for menu and shortcut navigation. Only one listener is needed at a
     805             :    * time, stored in mKeyListener, so switch it only if the document changes.
     806             :    * Having menus in different documents is very rare, so the listeners will
     807             :    * usually only be attached when the first menu opens and removed when all
     808             :    * menus have closed.
     809             :    *
     810             :    * This is also used when only a menubar is active without any open menus,
     811             :    * so that keyboard navigation between menus on the menubar may be done.
     812             :    */
     813             :   void UpdateKeyboardListeners();
     814             : 
     815             :   /*
     816             :    * Returns true if the docshell for aDoc is aExpected or a child of aExpected.
     817             :    */
     818             :   bool IsChildOfDocShell(nsIDocument* aDoc, nsIDocShellTreeItem* aExpected);
     819             : 
     820             :   // the document the key event listener is attached to
     821             :   nsCOMPtr<mozilla::dom::EventTarget> mKeyListener;
     822             : 
     823             :   // widget that is currently listening to rollup events
     824             :   nsCOMPtr<nsIWidget> mWidget;
     825             : 
     826             :   // range parent and offset set in SetTriggerEvent
     827             :   nsCOMPtr<nsIDOMNode> mRangeParent;
     828             :   int32_t mRangeOffset;
     829             :   // Device pixels relative to the showing popup's presshell's
     830             :   // root prescontext's root frame.
     831             :   mozilla::LayoutDeviceIntPoint mCachedMousePoint;
     832             : 
     833             :   // cached modifiers
     834             :   mozilla::Modifiers mCachedModifiers;
     835             : 
     836             :   // set to the currently active menu bar, if any
     837             :   nsMenuBarFrame* mActiveMenuBar;
     838             : 
     839             :   // linked list of normal menus and panels.
     840             :   nsMenuChainItem* mPopups;
     841             : 
     842             :   // timer used for HidePopupAfterDelay
     843             :   nsCOMPtr<nsITimer> mCloseTimer;
     844             : 
     845             :   // a popup that is waiting on the timer
     846             :   nsMenuPopupFrame* mTimerMenu;
     847             : 
     848             :   // the popup that is currently being opened, stored only during the
     849             :   // popupshowing event
     850             :   nsCOMPtr<nsIContent> mOpeningPopup;
     851             : 
     852             :   // If true, all popups won't hide automatically on blur
     853             :   static bool sDevtoolsDisableAutoHide;
     854             : };
     855             : 
     856             : #endif

Generated by: LCOV version 1.13