diff options
Diffstat (limited to '')
-rw-r--r-- | layout/xul/nsMenuPopupFrame.h | 647 |
1 files changed, 647 insertions, 0 deletions
diff --git a/layout/xul/nsMenuPopupFrame.h b/layout/xul/nsMenuPopupFrame.h new file mode 100644 index 0000000000..c23f543d40 --- /dev/null +++ b/layout/xul/nsMenuPopupFrame.h @@ -0,0 +1,647 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// +// nsMenuPopupFrame +// + +#ifndef nsMenuPopupFrame_h__ +#define nsMenuPopupFrame_h__ + +#include "mozilla/Attributes.h" +#include "mozilla/gfx/Types.h" +#include "mozilla/StaticPrefs_ui.h" +#include "mozilla/TimeStamp.h" +#include "nsAtom.h" +#include "nsCOMPtr.h" +#include "nsIDOMEventListener.h" +#include "nsXULPopupManager.h" + +#include "nsBlockFrame.h" + +#include "Units.h" + +class nsIWidget; + +namespace mozilla { +class PresShell; +enum class WindowShadow : uint8_t; +namespace dom { +class KeyboardEvent; +class XULButtonElement; +class XULPopupElement; +} // namespace dom +namespace widget { +enum class PopupLevel : uint8_t; +} +} // namespace mozilla + +enum ConsumeOutsideClicksResult { + ConsumeOutsideClicks_ParentOnly = + 0, // Only consume clicks on the parent anchor + ConsumeOutsideClicks_True = 1, // Always consume clicks + ConsumeOutsideClicks_Never = 2 // Never consume clicks +}; + +// How a popup may be flipped. Flipping to the outside edge is like how +// a submenu would work. The entire popup is flipped to the opposite side +// of the anchor. +enum FlipStyle { + FlipStyle_None = 0, + FlipStyle_Outside = 1, + FlipStyle_Inside = 2 +}; + +// Values for the flip attribute +enum FlipType { + FlipType_Default = 0, + FlipType_None = 1, // don't try to flip or translate to stay onscreen + FlipType_Both = 2, // flip in both directions + FlipType_Slide = 3 // allow the arrow to "slide" instead of resizing +}; + +enum MenuPopupAnchorType { + MenuPopupAnchorType_Node = 0, // anchored to a node + MenuPopupAnchorType_Point = 1, // unanchored and positioned at a screen point + MenuPopupAnchorType_Rect = 2, // anchored at a screen rectangle +}; + +// values are selected so that the direction can be flipped just by +// changing the sign +#define POPUPALIGNMENT_NONE 0 +#define POPUPALIGNMENT_TOPLEFT 1 +#define POPUPALIGNMENT_TOPRIGHT -1 +#define POPUPALIGNMENT_BOTTOMLEFT 2 +#define POPUPALIGNMENT_BOTTOMRIGHT -2 + +#define POPUPALIGNMENT_LEFTCENTER 16 +#define POPUPALIGNMENT_RIGHTCENTER -16 +#define POPUPALIGNMENT_TOPCENTER 17 +#define POPUPALIGNMENT_BOTTOMCENTER 18 + +// The constants here are selected so that horizontally and vertically flipping +// can be easily handled using the two flip macros below. +#define POPUPPOSITION_UNKNOWN -1 +#define POPUPPOSITION_BEFORESTART 0 +#define POPUPPOSITION_BEFOREEND 1 +#define POPUPPOSITION_AFTERSTART 2 +#define POPUPPOSITION_AFTEREND 3 +#define POPUPPOSITION_STARTBEFORE 4 +#define POPUPPOSITION_ENDBEFORE 5 +#define POPUPPOSITION_STARTAFTER 6 +#define POPUPPOSITION_ENDAFTER 7 +#define POPUPPOSITION_OVERLAP 8 +#define POPUPPOSITION_AFTERPOINTER 9 +#define POPUPPOSITION_SELECTION 10 + +#define POPUPPOSITION_HFLIP(v) (v ^ 1) +#define POPUPPOSITION_VFLIP(v) (v ^ 2) + +nsIFrame* NS_NewMenuPopupFrame(mozilla::PresShell* aPresShell, + mozilla::ComputedStyle* aStyle); + +class nsView; +class nsMenuPopupFrame; + +// this class is used for dispatching popupshown events asynchronously. +class nsXULPopupShownEvent final : public mozilla::Runnable, + public nsIDOMEventListener { + public: + nsXULPopupShownEvent(nsIContent* aPopup, nsPresContext* aPresContext) + : mozilla::Runnable("nsXULPopupShownEvent"), + mPopup(aPopup), + mPresContext(aPresContext) {} + + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIRUNNABLE + NS_DECL_NSIDOMEVENTLISTENER + + void CancelListener(); + + protected: + virtual ~nsXULPopupShownEvent() = default; + + private: + const nsCOMPtr<nsIContent> mPopup; + const RefPtr<nsPresContext> mPresContext; +}; + +class nsMenuPopupFrame final : public nsBlockFrame { + using PopupLevel = mozilla::widget::PopupLevel; + using PopupType = mozilla::widget::PopupType; + + public: + NS_DECL_QUERYFRAME + NS_DECL_FRAMEARENA_HELPERS(nsMenuPopupFrame) + + explicit nsMenuPopupFrame(ComputedStyle* aStyle, nsPresContext* aPresContext); + ~nsMenuPopupFrame(); + + // as popups are opened asynchronously, the popup pending state is used to + // prevent multiple requests from attempting to open the same popup twice + nsPopupState PopupState() const { return mPopupState; } + void SetPopupState(nsPopupState); + + /* + * When this popup is open, should clicks outside of it be consumed? + * Return true if the popup should rollup on an outside click, + * but consume that click so it can't be used for anything else. + * Return false to allow clicks outside the popup to activate content + * even when the popup is open. + * --------------------------------------------------------------------- + * + * Should clicks outside of a popup be eaten? + * + * Menus Autocomplete Comboboxes + * Mac Eat No Eat + * Win No No Eat + * Unix Eat No Eat + * + */ + ConsumeOutsideClicksResult ConsumeOutsideClicks(); + + mozilla::dom::XULPopupElement& PopupElement() const; + + nscoord GetPrefISize(gfxContext*) final; + nscoord GetMinISize(gfxContext*) final; + void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, + const ReflowInput& aReflowInput, + nsReflowStatus& aStatus) override; + + nsIWidget* GetWidget() const; + + enum class WidgetStyle : uint8_t { + ColorScheme, + InputRegion, + Opacity, + Shadow, + Transform, + }; + using WidgetStyleFlags = mozilla::EnumSet<WidgetStyle>; + static constexpr WidgetStyleFlags AllWidgetStyleFlags() { + return {WidgetStyle::ColorScheme, WidgetStyle::InputRegion, + WidgetStyle::Opacity, WidgetStyle::Shadow, WidgetStyle::Transform}; + } + void PropagateStyleToWidget(WidgetStyleFlags = AllWidgetStyleFlags()) const; + + // Overridden methods + void Init(nsIContent* aContent, nsContainerFrame* aParent, + nsIFrame* aPrevInFlow) override; + + nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute, + int32_t aModType) override; + + // FIXME: This shouldn't run script (this can end up calling HidePopup). + MOZ_CAN_RUN_SCRIPT_BOUNDARY void Destroy(DestroyContext&) override; + + bool HasRemoteContent() const; + + // Whether we should create a widget on Init(). + bool ShouldCreateWidgetUpfront() const; + + // Whether we should expand the menu to take the size of the parent menulist. + bool ShouldExpandToInflowParentOrAnchor() const; + + // Returns true if the popup is a panel with the noautohide attribute set to + // true. These panels do not roll up automatically. + bool IsNoAutoHide() const; + + PopupLevel GetPopupLevel() const { return GetPopupLevel(IsNoAutoHide()); } + + // Ensure that a widget has already been created for this view, and create + // one if it hasn't. If aRecreate is true, destroys any existing widget and + // creates a new one, regardless of whether one has already been created. + void PrepareWidget(bool aRecreate = false); + + MOZ_CAN_RUN_SCRIPT void EnsureActiveMenuListItemIsVisible(); + + nsresult CreateWidgetForView(nsView* aView); + mozilla::WindowShadow GetShadowStyle() const; + + void DidSetComputedStyle(ComputedStyle* aOldStyle) override; + + // layout, position and display the popup as needed + MOZ_CAN_RUN_SCRIPT_BOUNDARY + void LayoutPopup(nsPresContext*, ReflowOutput&, const ReflowInput&, + nsReflowStatus&); + + // Set the position of the popup relative to the anchor content, anchored at a + // rectangle, or at a specific point if a screen position is set. The popup + // will be adjusted so that it is on screen. If aIsMove is true, then the + // popup is being moved, and should not be flipped. + void SetPopupPosition(bool aIsMove); + + // Called when the Enter key is pressed while the popup is open. This will + // just pass the call down to the current menu, if any. + // Also, calling Enter will reset the current incremental search string, + // calculated in FindMenuWithShortcut. + MOZ_CAN_RUN_SCRIPT void HandleEnterKeyPress(mozilla::WidgetEvent&); + + // Locate and return the menu frame that should be activated for the supplied + // key event. If aDoAction is set to true by this method, then the menu's + // action should be carried out, as if the user had pressed the Enter key. If + // aDoAction is false, the menu should just be highlighted. + // This method also handles incremental searching in menus so the user can + // type the first few letters of an item/s name to select it. + mozilla::dom::XULButtonElement* FindMenuWithShortcut( + mozilla::dom::KeyboardEvent& aKeyEvent, bool& aDoAction); + + mozilla::dom::XULButtonElement* GetCurrentMenuItem() const; + nsIFrame* GetCurrentMenuItemFrame() const; + + PopupType GetPopupType() const { return mPopupType; } + bool IsContextMenu() const { return mIsContextMenu; } + + bool IsOpen() const { + return mPopupState == ePopupOpening || mPopupState == ePopupVisible || + mPopupState == ePopupShown; + } + bool IsVisible() { + return mPopupState == ePopupVisible || mPopupState == ePopupShown; + } + bool IsVisibleOrShowing() { + return IsOpen() || mPopupState == ePopupPositioning || + mPopupState == ePopupShowing; + } + bool IsNativeMenu() const { return mIsNativeMenu; } + bool IsMouseTransparent() const; + + // Return true if the popup is for a menulist. + bool IsMenuList() const; + + bool IsDragSource() const { return mIsDragSource; } + void SetIsDragSource(bool aIsDragSource) { mIsDragSource = aIsDragSource; } + + static nsIContent* GetTriggerContent(nsMenuPopupFrame* aMenuPopupFrame); + void ClearTriggerContent() { mTriggerContent = nullptr; } + void ClearTriggerContentIncludingDocument(); + + // returns true if the popup is in a content shell, or false for a popup in + // a chrome shell + bool IsInContentShell() const { return mInContentShell; } + + // the Initialize methods are used to set the anchor position for + // each way of opening a popup. + void InitializePopup(nsIContent* aAnchorContent, nsIContent* aTriggerContent, + const nsAString& aPosition, int32_t aXPos, int32_t aYPos, + MenuPopupAnchorType aAnchorType, + bool aAttributesOverride); + + void InitializePopupAtRect(nsIContent* aTriggerContent, + const nsAString& aPosition, const nsIntRect& aRect, + bool aAttributesOverride); + + /** + * @param aIsContextMenu if true, then the popup is + * positioned at a slight offset from aXPos/aYPos to ensure the + * (presumed) mouse position is not over the menu. + */ + void InitializePopupAtScreen(nsIContent* aTriggerContent, int32_t aXPos, + int32_t aYPos, bool aIsContextMenu); + + // Called if this popup should be displayed as an OS-native context menu. + void InitializePopupAsNativeContextMenu(nsIContent* aTriggerContent, + int32_t aXPos, int32_t aYPos); + + // indicate that the popup should be opened + void ShowPopup(bool aIsContextMenu); + // indicate that the popup should be hidden. The new state should either be + // ePopupClosed or ePopupInvisible. + MOZ_CAN_RUN_SCRIPT void HidePopup(bool aDeselectMenu, nsPopupState aNewState, + bool aFromFrameDestruction = false); + + void ClearIncrementalString() { mIncrementalString.Truncate(); } + static bool IsWithinIncrementalTime(mozilla::TimeStamp time) { + return !sLastKeyTime.IsNull() && + ((time - sLastKeyTime).ToMilliseconds() <= + mozilla::StaticPrefs::ui_menu_incremental_search_timeout()); + } + +#ifdef DEBUG_FRAME_DUMP + virtual nsresult GetFrameName(nsAString& aResult) const override { + return MakeFrameName(u"MenuPopup"_ns, aResult); + } +#endif + + MOZ_CAN_RUN_SCRIPT void ChangeByPage(bool aIsUp); + + // Move the popup to the screen coordinate |aPos| in CSS pixels. + // If aUpdateAttrs is true, and the popup already has left or top attributes, + // then those attributes are updated to the new location. + // The frame may be destroyed by this method. + void MoveTo(const mozilla::CSSPoint& aPos, bool aUpdateAttrs, + bool aByMoveToRect = false); + + void MoveToAnchor(nsIContent* aAnchorContent, const nsAString& aPosition, + int32_t aXPos, int32_t aYPos, bool aAttributesOverride); + + nsIScrollableFrame* GetScrollFrame() const; + + void SetOverrideConstraintRect(const mozilla::CSSIntRect& aRect) { + mOverrideConstraintRect = mozilla::CSSIntRect::ToAppUnits(aRect); + } + + bool IsConstrainedByLayout() const { return mConstrainedByLayout; } + + struct Rects { + // For anchored popups, the anchor rectangle. For non-anchored popups, the + // size will be 0. + nsRect mAnchorRect; + // mAnchorRect before accounting for flipping / resizing / intersecting with + // the screen. This is needed for Wayland, which flips / resizes at the + // widget level. + nsRect mUntransformedAnchorRect; + // The final used rect we want to occupy. + nsRect mUsedRect; + // The alignment offset for sliding the panel, see + // nsMenuPopupFrame::mAlignmentOffset. + nscoord mAlignmentOffset = 0; + bool mHFlip = false; + bool mVFlip = false; + bool mConstrainedByLayout = false; + // The client offset of our widget. + mozilla::LayoutDeviceIntPoint mClientOffset; + nsPoint mViewPoint; + }; + + // For a popup that should appear anchored at the given rect, gets the anchor + // and constraint rects for that popup. + // This will be the available area of the screen the popup should be displayed + // on. Content popups, however, will also be constrained by the content area. + // + // For non-toplevel popups (which will always be panels), we will also + // constrain them to the available screen rect, ie they will not fall + // underneath the taskbar, dock or other fixed OS elements. + Rects GetRects(const nsSize& aPrefSize) const; + Maybe<nsRect> GetConstraintRect(const nsRect& aAnchorRect, + const nsRect& aRootScreenRect, + PopupLevel) const; + void PerformMove(const Rects&); + + // Return true if the popup is positioned relative to an anchor. + bool IsAnchored() const { return mAnchorType != MenuPopupAnchorType_Point; } + + // Return the anchor if there is one. + nsIContent* GetAnchor() const { return mAnchorContent; } + + // Return the screen coordinates in CSS pixels of the popup, + // or (-1, -1, 0, 0) if anchored. + mozilla::CSSIntRect GetScreenAnchorRect() const { + return mozilla::CSSRect::FromAppUnitsRounded(mScreenRect); + } + + mozilla::LayoutDeviceIntPoint GetLastClientOffset() const { + return mLastClientOffset; + } + + // Return the alignment of the popup + int8_t GetAlignmentPosition() const; + + // Return the offset applied to the alignment of the popup + nscoord GetAlignmentOffset() const { return mAlignmentOffset; } + + // Clear the mPopupShownDispatcher, remove the listener and return true if + // mPopupShownDispatcher was non-null. + bool ClearPopupShownDispatcher() { + if (mPopupShownDispatcher) { + mPopupShownDispatcher->CancelListener(); + mPopupShownDispatcher = nullptr; + return true; + } + + return false; + } + + void ShowWithPositionedEvent() { mPopupState = ePopupPositioning; } + + // Checks for the anchor to change and either moves or hides the popup + // accordingly. The original position of the anchor should be supplied as + // the argument. If the popup needs to be hidden, HidePopup will be called by + // CheckForAnchorChange. If the popup needs to be moved, aRect will be updated + // with the new rectangle. + void CheckForAnchorChange(nsRect& aRect); + + void WillDispatchPopupPositioned() { mPendingPositionedEvent = false; } + + protected: + // returns the popup's level. + PopupLevel GetPopupLevel(bool aIsNoAutoHide) const; + void TweakMinPrefISize(nscoord&); + + void InitPositionFromAnchorAlign(const nsAString& aAnchor, + const nsAString& aAlign); + + // return the position where the popup should be, when it should be + // anchored at anchorRect. aHFlip and aVFlip will be set if the popup may be + // flipped in that direction if there is not enough space available. + nsPoint AdjustPositionForAnchorAlign(nsRect& aAnchorRect, + const nsSize& aPrefSize, + FlipStyle& aHFlip, + FlipStyle& aVFlip) const; + + // For popups that are going to align to their selected item, get the frame of + // the selected item. + nsIFrame* GetSelectedItemForAlignment() const; + + // check if the popup will fit into the available space and resize it. This + // method handles only one axis at a time so is called twice, once for + // horizontal and once for vertical. All arguments are specified for this + // one axis. All coordinates are in app units relative to the screen. + // aScreenPoint - the point where the popup should appear + // aSize - the size of the popup + // aScreenBegin - the left or top edge of the screen + // aScreenEnd - the right or bottom edge of the screen + // aAnchorBegin - the left or top edge of the anchor rectangle + // aAnchorEnd - the right or bottom edge of the anchor rectangle + // aMarginBegin - the left or top margin of the popup + // aMarginEnd - the right or bottom margin of the popup + // aFlip - how to flip or resize the popup when there isn't space + // aFlipSide - pointer to where current flip mode is stored + nscoord FlipOrResize(nscoord& aScreenPoint, nscoord aSize, + nscoord aScreenBegin, nscoord aScreenEnd, + nscoord aAnchorBegin, nscoord aAnchorEnd, + nscoord aMarginBegin, nscoord aMarginEnd, + FlipStyle aFlip, bool aIsOnEnd, bool* aFlipSide) const; + + // check if the popup can fit into the available space by "sliding" (i.e., + // by having the anchor arrow slide along one axis and only resizing if that + // can't provide the requested size). Only one axis can be slid - the other + // axis is "flipped" as normal. This method can handle either axis, but is + // only called for the sliding axis. All coordinates are in app units + // relative to the screen. + // aScreenPoint - the point where the popup should appear + // aSize - the size of the popup + // aScreenBegin - the left or top edge of the screen + // aScreenEnd - the right or bottom edge of the screen + // aOffset - the amount by which the arrow must be slid such that it is + // still aligned with the anchor. + // Result is the new size of the popup, which will typically be the same + // as aSize, unless aSize is greater than the screen width/height. + nscoord SlideOrResize(nscoord& aScreenPoint, nscoord aSize, + nscoord aScreenBegin, nscoord aScreenEnd, + nscoord* aOffset) const; + + // Given an anchor frame, compute the anchor rectangle relative to the screen, + // using the popup frame's app units, and taking into account transforms. + nsRect ComputeAnchorRect(nsPresContext* aRootPresContext, + nsIFrame* aAnchorFrame) const; + + // Move the popup to the position specified in its |left| and |top| + // attributes. + void MoveToAttributePosition(); + + // Create a popup view for this frame. The view is added a child of the root + // view, and is initially hidden. + void CreatePopupView(); + + nsView* GetViewInternal() const override { return mView; } + void SetViewInternal(nsView* aView) override { mView = aView; } + + // Returns true if the popup should try to remain at the same relative + // location as the anchor while it is open. If the anchor becomes hidden + // either directly or indirectly because a parent popup or other element + // is no longer visible, or a parent deck page is changed, the popup hides + // as well. The second variation also sets the anchor rectangle, relative to + // the popup frame. + bool ShouldFollowAnchor() const; + + nsIFrame* GetAnchorFrame() const; + + public: + /** + * Return whether the popup direction should be RTL. + * If the popup has an anchor, its direction is the anchor direction. + * Otherwise, its the general direction of the UI. + * + * Return whether the popup direction should be RTL. + */ + bool IsDirectionRTL() const; + + bool ShouldFollowAnchor(nsRect& aRect); + + // Returns parent menu widget for submenus that are in the same + // frame hierarchy, it's needed for Linux/Wayland which demands + // strict popup windows hierarchy. + nsIWidget* GetParentMenuWidget(); + + // Returns the effective margin for this popup. This is the CSS margin plus + // the context-menu shift, if needed. + nsMargin GetMargin() const; + + // These are used by Wayland backend. + const nsRect& GetUntransformedAnchorRect() const { + return mUntransformedAnchorRect; + } + int GetPopupAlignment() const { return mPopupAlignment; } + int GetPopupAnchor() const { return mPopupAnchor; } + FlipType GetFlipType() const { return mFlip; } + + void WidgetPositionOrSizeDidChange(); + + protected: + nsString mIncrementalString; // for incremental typing navigation + + // the content that the popup is anchored to, if any, which may be in a + // different document than the popup. + nsCOMPtr<nsIContent> mAnchorContent; + + // the content that triggered the popup, typically the node where the mouse + // was clicked. It will be cleared when the popup is hidden. + nsCOMPtr<nsIContent> mTriggerContent; + + nsView* mView = nullptr; + + RefPtr<nsXULPopupShownEvent> mPopupShownDispatcher; + + // The popup's screen rectangle in app units. + nsRect mUsedScreenRect; + + // A popup's preferred size may be different than its actual size stored in + // mRect in the case where the popup was resized because it was too large + // for the screen. The preferred size mPrefSize holds the full size the popup + // would be before resizing. Computations are performed using this size. + nsSize mPrefSize{-1, -1}; + + // The position of the popup, in CSS pixels. + // The screen coordinates, if set to values other than -1, + // override mXPos and mYPos. + int32_t mXPos = 0; + int32_t mYPos = 0; + nsRect mScreenRect; + // Used for store rectangle which the popup is going to be anchored to, we + // need that for Wayland. It's important that this rect is unflipped, and + // without margins applied, as GTK is what takes care of determining how to + // flip etc. on Wayland. + nsRect mUntransformedAnchorRect; + + // If the panel prefers to "slide" rather than resize, then the arrow gets + // positioned at this offset (along either the x or y axis, depending on + // mPosition) + nscoord mAlignmentOffset = 0; + + // The value of the client offset of our widget the last time we positioned + // ourselves. We store this so that we can detect when it changes but the + // position of our widget didn't change. + mozilla::LayoutDeviceIntPoint mLastClientOffset; + + PopupType mPopupType = PopupType::Panel; // type of popup + nsPopupState mPopupState = ePopupClosed; // open state of the popup + + // popup alignment relative to the anchor node + int8_t mPopupAlignment = POPUPALIGNMENT_NONE; + int8_t mPopupAnchor = POPUPALIGNMENT_NONE; + int8_t mPosition = POPUPPOSITION_UNKNOWN; + + FlipType mFlip = FlipType_Default; // Whether to flip + + // Whether we were moved by the move-to-rect Wayland callback. In that case, + // we stop updating the anchor so that we can end up with a stable position. + bool mPositionedByMoveToRect = false; + // true if the open state changed since the last layout. + bool mIsOpenChanged = false; + // true for context menus and their submenus. + bool mIsContextMenu = false; + // true for the topmost context menu. + bool mIsTopLevelContextMenu = false; + // true if the popup is in a content shell. + bool mInContentShell = true; + + // The flip modes that were used when the popup was opened + bool mHFlip = false; + bool mVFlip = false; + // Whether layout has constrained this popup in some way. + bool mConstrainedByLayout = false; + + // Whether the most recent initialization of this menupopup happened via + // InitializePopupAsNativeContextMenu. + bool mIsNativeMenu = false; + + // Whether we have a pending `popuppositioned` event. + bool mPendingPositionedEvent = false; + + // Whether this popup is source of D&D operation. We can't close such + // popup on Wayland as it cancel whole D&D operation. + bool mIsDragSource = false; + + // When POPUPPOSITION_SELECTION is used, this indicates the vertical offset + // that the original selected item was. This needs to be used in case the + // popup gets changed so that we can keep the popup at the same vertical + // offset. + // TODO(emilio): try to make this not mutable. + mutable nscoord mPositionedOffset = 0; + + // How the popup is anchored. + MenuPopupAnchorType mAnchorType = MenuPopupAnchorType_Node; + + nsRect mOverrideConstraintRect; + + static int8_t sDefaultLevelIsTop; + + static mozilla::TimeStamp sLastKeyTime; + +}; // class nsMenuPopupFrame + +#endif |