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 : // nsMenuPopupFrame
8 : //
9 :
10 : #ifndef nsMenuPopupFrame_h__
11 : #define nsMenuPopupFrame_h__
12 :
13 : #include "mozilla/Attributes.h"
14 : #include "mozilla/gfx/Types.h"
15 : #include "nsIAtom.h"
16 : #include "nsGkAtoms.h"
17 : #include "nsCOMPtr.h"
18 : #include "nsMenuFrame.h"
19 :
20 : #include "nsBoxFrame.h"
21 : #include "nsMenuParent.h"
22 :
23 : #include "nsITimer.h"
24 :
25 : #include "Units.h"
26 :
27 : class nsIWidget;
28 :
29 : // XUL popups can be in several different states. When opening a popup, the
30 : // state changes as follows:
31 : // ePopupClosed - initial state
32 : // ePopupShowing - during the period when the popupshowing event fires
33 : // ePopupOpening - between the popupshowing event and being visible. Creation
34 : // of the child frames, layout and reflow occurs in this
35 : // state. The popup is stored in the popup manager's list of
36 : // open popups during this state.
37 : // ePopupVisible - layout is done and the popup's view and widget are made
38 : // visible. The popup is visible on screen but may be
39 : // transitioning. The popupshown event has not yet fired.
40 : // ePopupShown - the popup has been shown and is fully ready. This state is
41 : // assigned just before the popupshown event fires.
42 : // When closing a popup:
43 : // ePopupHidden - during the period when the popuphiding event fires and
44 : // the popup is removed.
45 : // ePopupClosed - the popup's widget is made invisible.
46 : enum nsPopupState {
47 : // state when a popup is not open
48 : ePopupClosed,
49 : // state from when a popup is requested to be shown to after the
50 : // popupshowing event has been fired.
51 : ePopupShowing,
52 : // state while a popup is waiting to be laid out and positioned
53 : ePopupPositioning,
54 : // state while a popup is open but the widget is not yet visible
55 : ePopupOpening,
56 : // state while a popup is visible and waiting for the popupshown event
57 : ePopupVisible,
58 : // state while a popup is open and visible on screen
59 : ePopupShown,
60 : // state from when a popup is requested to be hidden to when it is closed.
61 : ePopupHiding,
62 : // state which indicates that the popup was hidden without firing the
63 : // popuphiding or popuphidden events. It is used when executing a menu
64 : // command because the menu needs to be hidden before the command event
65 : // fires, yet the popuphiding and popuphidden events are fired after. This
66 : // state can also occur when the popup is removed because the document is
67 : // unloaded.
68 : ePopupInvisible
69 : };
70 :
71 : enum ConsumeOutsideClicksResult {
72 : ConsumeOutsideClicks_ParentOnly = 0, // Only consume clicks on the parent anchor
73 : ConsumeOutsideClicks_True = 1, // Always consume clicks
74 : ConsumeOutsideClicks_Never = 2 // Never consume clicks
75 : };
76 :
77 : // How a popup may be flipped. Flipping to the outside edge is like how
78 : // a submenu would work. The entire popup is flipped to the opposite side
79 : // of the anchor.
80 : enum FlipStyle {
81 : FlipStyle_None = 0,
82 : FlipStyle_Outside = 1,
83 : FlipStyle_Inside = 2
84 : };
85 :
86 : // Values for the flip attribute
87 : enum FlipType {
88 : FlipType_Default = 0,
89 : FlipType_None = 1, // don't try to flip or translate to stay onscreen
90 : FlipType_Both = 2, // flip in both directions
91 : FlipType_Slide = 3 // allow the arrow to "slide" instead of resizing
92 : };
93 :
94 : enum MenuPopupAnchorType {
95 : MenuPopupAnchorType_Node = 0, // anchored to a node
96 : MenuPopupAnchorType_Point = 1, // unanchored and positioned at a screen point
97 : MenuPopupAnchorType_Rect = 2, // anchored at a screen rectangle
98 : };
99 :
100 : // values are selected so that the direction can be flipped just by
101 : // changing the sign
102 : #define POPUPALIGNMENT_NONE 0
103 : #define POPUPALIGNMENT_TOPLEFT 1
104 : #define POPUPALIGNMENT_TOPRIGHT -1
105 : #define POPUPALIGNMENT_BOTTOMLEFT 2
106 : #define POPUPALIGNMENT_BOTTOMRIGHT -2
107 :
108 : #define POPUPALIGNMENT_LEFTCENTER 16
109 : #define POPUPALIGNMENT_RIGHTCENTER -16
110 : #define POPUPALIGNMENT_TOPCENTER 17
111 : #define POPUPALIGNMENT_BOTTOMCENTER 18
112 :
113 : // The constants here are selected so that horizontally and vertically flipping
114 : // can be easily handled using the two flip macros below.
115 : #define POPUPPOSITION_UNKNOWN -1
116 : #define POPUPPOSITION_BEFORESTART 0
117 : #define POPUPPOSITION_BEFOREEND 1
118 : #define POPUPPOSITION_AFTERSTART 2
119 : #define POPUPPOSITION_AFTEREND 3
120 : #define POPUPPOSITION_STARTBEFORE 4
121 : #define POPUPPOSITION_ENDBEFORE 5
122 : #define POPUPPOSITION_STARTAFTER 6
123 : #define POPUPPOSITION_ENDAFTER 7
124 : #define POPUPPOSITION_OVERLAP 8
125 : #define POPUPPOSITION_AFTERPOINTER 9
126 : #define POPUPPOSITION_SELECTION 10
127 :
128 : #define POPUPPOSITION_HFLIP(v) (v ^ 1)
129 : #define POPUPPOSITION_VFLIP(v) (v ^ 2)
130 :
131 : nsIFrame* NS_NewMenuPopupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
132 :
133 : class nsView;
134 : class nsMenuPopupFrame;
135 :
136 : // this class is used for dispatching popupshown events asynchronously.
137 : class nsXULPopupShownEvent : public mozilla::Runnable,
138 : public nsIDOMEventListener
139 : {
140 : public:
141 0 : nsXULPopupShownEvent(nsIContent* aPopup, nsPresContext* aPresContext)
142 0 : : mozilla::Runnable("nsXULPopupShownEvent")
143 : , mPopup(aPopup)
144 0 : , mPresContext(aPresContext)
145 : {
146 0 : }
147 :
148 : NS_DECL_ISUPPORTS_INHERITED
149 : NS_DECL_NSIRUNNABLE
150 : NS_DECL_NSIDOMEVENTLISTENER
151 :
152 : void CancelListener();
153 :
154 : protected:
155 0 : virtual ~nsXULPopupShownEvent() { }
156 :
157 : private:
158 : nsCOMPtr<nsIContent> mPopup;
159 : RefPtr<nsPresContext> mPresContext;
160 : };
161 :
162 7 : class nsMenuPopupFrame final : public nsBoxFrame, public nsMenuParent,
163 : public nsIReflowCallback
164 : {
165 : public:
166 : NS_DECL_QUERYFRAME
167 154 : NS_DECL_FRAMEARENA_HELPERS(nsMenuPopupFrame)
168 :
169 : explicit nsMenuPopupFrame(nsStyleContext* aContext);
170 :
171 : // nsMenuParent interface
172 : virtual nsMenuFrame* GetCurrentMenuItem() override;
173 : NS_IMETHOD SetCurrentMenuItem(nsMenuFrame* aMenuItem) override;
174 : virtual void CurrentMenuIsBeingDestroyed() override;
175 : NS_IMETHOD ChangeMenuItem(nsMenuFrame* aMenuItem,
176 : bool aSelectFirstItem,
177 : bool aFromKey) override;
178 :
179 : // as popups are opened asynchronously, the popup pending state is used to
180 : // prevent multiple requests from attempting to open the same popup twice
181 3 : nsPopupState PopupState() { return mPopupState; }
182 0 : void SetPopupState(nsPopupState aPopupState) { mPopupState = aPopupState; }
183 :
184 0 : NS_IMETHOD SetActive(bool aActiveFlag) override { return NS_OK; } // We don't care.
185 0 : virtual bool IsActive() override { return false; }
186 0 : virtual bool IsMenuBar() override { return false; }
187 :
188 : /*
189 : * When this popup is open, should clicks outside of it be consumed?
190 : * Return true if the popup should rollup on an outside click,
191 : * but consume that click so it can't be used for anything else.
192 : * Return false to allow clicks outside the popup to activate content
193 : * even when the popup is open.
194 : * ---------------------------------------------------------------------
195 : *
196 : * Should clicks outside of a popup be eaten?
197 : *
198 : * Menus Autocomplete Comboboxes
199 : * Mac Eat No Eat
200 : * Win No No Eat
201 : * Unix Eat No Eat
202 : *
203 : */
204 : ConsumeOutsideClicksResult ConsumeOutsideClicks();
205 :
206 0 : virtual bool IsContextMenu() override { return mIsContextMenu; }
207 :
208 0 : virtual bool MenuClosed() override { return true; }
209 :
210 : virtual void LockMenuUntilClosed(bool aLock) override;
211 0 : virtual bool IsMenuLocked() override { return mIsMenuLocked; }
212 :
213 : nsIWidget* GetWidget();
214 :
215 : // The dismissal listener gets created and attached to the window.
216 : void AttachedDismissalListener();
217 :
218 : // Overridden methods
219 : virtual void Init(nsIContent* aContent,
220 : nsContainerFrame* aParent,
221 : nsIFrame* aPrevInFlow) override;
222 :
223 : virtual nsresult AttributeChanged(int32_t aNameSpaceID,
224 : nsIAtom* aAttribute,
225 : int32_t aModType) override;
226 :
227 : virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
228 :
229 : bool HasRemoteContent() const;
230 :
231 : // returns true if the popup is a panel with the noautohide attribute set to
232 : // true. These panels do not roll up automatically.
233 : bool IsNoAutoHide() const;
234 :
235 0 : nsPopupLevel PopupLevel() const
236 : {
237 0 : return PopupLevel(IsNoAutoHide());
238 : }
239 :
240 : // Ensure that a widget has already been created for this view, and create
241 : // one if it hasn't. If aRecreate is true, destroys any existing widget and
242 : // creates a new one, regardless of whether one has already been created.
243 : void EnsureWidget(bool aRecreate = false);
244 :
245 : nsresult CreateWidgetForView(nsView* aView);
246 : uint8_t GetShadowStyle();
247 :
248 : virtual void SetInitialChildList(ChildListID aListID,
249 : nsFrameList& aChildList) override;
250 :
251 : virtual bool IsLeafDynamic() const override;
252 :
253 : virtual void UpdateWidgetProperties() override;
254 :
255 : // layout, position and display the popup as needed
256 : void LayoutPopup(nsBoxLayoutState& aState, nsIFrame* aParentMenu,
257 : nsIFrame* aAnchor, bool aSizedToPopup);
258 :
259 : nsView* GetRootViewForPopup(nsIFrame* aStartFrame);
260 :
261 : // Set the position of the popup either relative to the anchor aAnchorFrame
262 : // (or the frame for mAnchorContent if aAnchorFrame is null), anchored at a
263 : // rectangle, or at a specific point if a screen position is set. The popup
264 : // will be adjusted so that it is on screen. If aIsMove is true, then the
265 : // popup is being moved, and should not be flipped. If aNotify is true, then
266 : // a popuppositioned event is sent.
267 : nsresult SetPopupPosition(nsIFrame* aAnchorFrame, bool aIsMove,
268 : bool aSizedToPopup, bool aNotify);
269 :
270 0 : bool HasGeneratedChildren() { return mGeneratedChildren; }
271 0 : void SetGeneratedChildren() { mGeneratedChildren = true; }
272 :
273 : // called when the Enter key is pressed while the popup is open. This will
274 : // just pass the call down to the current menu, if any. If a current menu
275 : // should be opened as a result, this method should return the frame for
276 : // that menu, or null if no menu should be opened. Also, calling Enter will
277 : // reset the current incremental search string, calculated in
278 : // FindMenuWithShortcut.
279 : nsMenuFrame* Enter(mozilla::WidgetGUIEvent* aEvent);
280 :
281 0 : nsPopupType PopupType() const { return mPopupType; }
282 0 : bool IsMenu() override { return mPopupType == ePopupTypeMenu; }
283 0 : bool IsOpen() override { return mPopupState == ePopupOpening ||
284 0 : mPopupState == ePopupVisible ||
285 0 : mPopupState == ePopupShown; }
286 0 : bool IsVisible() { return mPopupState == ePopupVisible ||
287 0 : mPopupState == ePopupShown; }
288 :
289 : // Return true if the popup is for a menulist.
290 : bool IsMenuList();
291 :
292 0 : bool IsMouseTransparent() { return mMouseTransparent; }
293 :
294 : static nsIContent* GetTriggerContent(nsMenuPopupFrame* aMenuPopupFrame);
295 0 : void ClearTriggerContent() { mTriggerContent = nullptr; }
296 :
297 : // returns true if the popup is in a content shell, or false for a popup in
298 : // a chrome shell
299 0 : bool IsInContentShell() { return mInContentShell; }
300 :
301 : // the Initialize methods are used to set the anchor position for
302 : // each way of opening a popup.
303 : void InitializePopup(nsIContent* aAnchorContent,
304 : nsIContent* aTriggerContent,
305 : const nsAString& aPosition,
306 : int32_t aXPos, int32_t aYPos,
307 : MenuPopupAnchorType aAnchorType,
308 : bool aAttributesOverride);
309 :
310 : void InitializePopupAtRect(nsIContent* aTriggerContent,
311 : const nsAString& aPosition,
312 : const nsIntRect& aRect,
313 : bool aAttributesOverride);
314 :
315 : /**
316 : * @param aIsContextMenu if true, then the popup is
317 : * positioned at a slight offset from aXPos/aYPos to ensure the
318 : * (presumed) mouse position is not over the menu.
319 : */
320 : void InitializePopupAtScreen(nsIContent* aTriggerContent,
321 : int32_t aXPos, int32_t aYPos,
322 : bool aIsContextMenu);
323 :
324 : void InitializePopupWithAnchorAlign(nsIContent* aAnchorContent,
325 : nsAString& aAnchor,
326 : nsAString& aAlign,
327 : int32_t aXPos, int32_t aYPos);
328 :
329 : // indicate that the popup should be opened
330 : void ShowPopup(bool aIsContextMenu);
331 : // indicate that the popup should be hidden. The new state should either be
332 : // ePopupClosed or ePopupInvisible.
333 : void HidePopup(bool aDeselectMenu, nsPopupState aNewState);
334 :
335 : // locate and return the menu frame that should be activated for the
336 : // supplied key event. If doAction is set to true by this method,
337 : // then the menu's action should be carried out, as if the user had pressed
338 : // the Enter key. If doAction is false, the menu should just be highlighted.
339 : // This method also handles incremental searching in menus so the user can
340 : // type the first few letters of an item/s name to select it.
341 : nsMenuFrame* FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent, bool& doAction);
342 :
343 0 : void ClearIncrementalString() { mIncrementalString.Truncate(); }
344 0 : static bool IsWithinIncrementalTime(DOMTimeStamp time) {
345 0 : return !sTimeoutOfIncrementalSearch || time - sLastKeyTime <= sTimeoutOfIncrementalSearch;
346 : }
347 :
348 : #ifdef DEBUG_FRAME_DUMP
349 0 : virtual nsresult GetFrameName(nsAString& aResult) const override
350 : {
351 0 : return MakeFrameName(NS_LITERAL_STRING("MenuPopup"), aResult);
352 : }
353 : #endif
354 :
355 : void EnsureMenuItemIsVisible(nsMenuFrame* aMenuFrame);
356 :
357 : void ChangeByPage(bool aIsUp);
358 :
359 : // Move the popup to the screen coordinate |aPos| in CSS pixels.
360 : // If aUpdateAttrs is true, and the popup already has left or top attributes,
361 : // then those attributes are updated to the new location.
362 : // The frame may be destroyed by this method.
363 : void MoveTo(const mozilla::CSSIntPoint& aPos, bool aUpdateAttrs);
364 :
365 : void MoveToAnchor(nsIContent* aAnchorContent,
366 : const nsAString& aPosition,
367 : int32_t aXPos, int32_t aYPos,
368 : bool aAttributesOverride);
369 :
370 : bool GetAutoPosition();
371 : void SetAutoPosition(bool aShouldAutoPosition);
372 : void SetConsumeRollupEvent(uint32_t aConsumeMode);
373 :
374 : nsIScrollableFrame* GetScrollFrame(nsIFrame* aStart);
375 :
376 0 : void SetOverrideConstraintRect(mozilla::LayoutDeviceIntRect aRect) {
377 0 : mOverrideConstraintRect = ToAppUnits(aRect, PresContext()->AppUnitsPerCSSPixel());
378 0 : }
379 :
380 : // For a popup that should appear anchored at the given rect, determine
381 : // the screen area that it is constrained by. This will be the available
382 : // area of the screen the popup should be displayed on. Content popups,
383 : // however, will also be constrained by the content area, given by
384 : // aRootScreenRect. All coordinates are in app units.
385 : // For non-toplevel popups (which will always be panels), we will also
386 : // constrain them to the available screen rect, ie they will not fall
387 : // underneath the taskbar, dock or other fixed OS elements.
388 : // This operates in device pixels.
389 : mozilla::LayoutDeviceIntRect
390 : GetConstraintRect(const mozilla::LayoutDeviceIntRect& aAnchorRect,
391 : const mozilla::LayoutDeviceIntRect& aRootScreenRect,
392 : nsPopupLevel aPopupLevel);
393 :
394 : // Determines whether the given edges of the popup may be moved, where
395 : // aHorizontalSide and aVerticalSide are one of the enum Side constants.
396 : // aChange is the distance to move on those sides. If will be reset to 0
397 : // if the side cannot be adjusted at all in that direction. For example, a
398 : // popup cannot be moved if it is anchored on a particular side.
399 : //
400 : // Later, when bug 357725 is implemented, we can make this adjust aChange by
401 : // the amount that the side can be resized, so that minimums and maximums
402 : // can be taken into account.
403 : void CanAdjustEdges(mozilla::Side aHorizontalSide,
404 : mozilla::Side aVerticalSide,
405 : mozilla::LayoutDeviceIntPoint& aChange);
406 :
407 : // Return true if the popup is positioned relative to an anchor.
408 0 : bool IsAnchored() const { return mAnchorType != MenuPopupAnchorType_Point; }
409 :
410 : // Return the anchor if there is one.
411 0 : nsIContent* GetAnchor() const { return mAnchorContent; }
412 :
413 : // Return the screen coordinates in CSS pixels of the popup,
414 : // or (-1, -1, 0, 0) if anchored.
415 0 : nsIntRect GetScreenAnchorRect() const { return mScreenRect; }
416 :
417 0 : mozilla::LayoutDeviceIntPoint GetLastClientOffset() const
418 : {
419 0 : return mLastClientOffset;
420 : }
421 :
422 : // Return the alignment of the popup
423 : int8_t GetAlignmentPosition() const;
424 :
425 : // Return the offset applied to the alignment of the popup
426 0 : nscoord GetAlignmentOffset() const { return mAlignmentOffset; }
427 :
428 : // Clear the mPopupShownDispatcher, remove the listener and return true if
429 : // mPopupShownDispatcher was non-null.
430 7 : bool ClearPopupShownDispatcher()
431 : {
432 7 : if (mPopupShownDispatcher) {
433 0 : mPopupShownDispatcher->CancelListener();
434 0 : mPopupShownDispatcher = nullptr;
435 0 : return true;
436 : }
437 :
438 7 : return false;
439 : }
440 :
441 0 : void ShowWithPositionedEvent() {
442 0 : mPopupState = ePopupPositioning;
443 0 : mShouldAutoPosition = true;
444 0 : }
445 :
446 : // Checks for the anchor to change and either moves or hides the popup
447 : // accordingly. The original position of the anchor should be supplied as
448 : // the argument. If the popup needs to be hidden, HidePopup will be called by
449 : // CheckForAnchorChange. If the popup needs to be moved, aRect will be updated
450 : // with the new rectangle.
451 : void CheckForAnchorChange(nsRect& aRect);
452 :
453 : // nsIReflowCallback
454 : virtual bool ReflowFinished() override;
455 : virtual void ReflowCallbackCanceled() override;
456 :
457 : protected:
458 :
459 : // returns the popup's level.
460 : nsPopupLevel PopupLevel(bool aIsNoAutoHide) const;
461 :
462 : // redefine to tell the box system not to move the views.
463 : virtual uint32_t GetXULLayoutFlags() override;
464 :
465 : void InitPositionFromAnchorAlign(const nsAString& aAnchor,
466 : const nsAString& aAlign);
467 :
468 : // return the position where the popup should be, when it should be
469 : // anchored at anchorRect. aHFlip and aVFlip will be set if the popup may be
470 : // flipped in that direction if there is not enough space available.
471 : nsPoint AdjustPositionForAnchorAlign(nsRect& anchorRect,
472 : FlipStyle& aHFlip, FlipStyle& aVFlip);
473 :
474 : // For popups that are going to align to their selected item, get the frame of
475 : // the selected item.
476 : nsIFrame* GetSelectedItemForAlignment();
477 :
478 : // check if the popup will fit into the available space and resize it. This
479 : // method handles only one axis at a time so is called twice, once for
480 : // horizontal and once for vertical. All arguments are specified for this
481 : // one axis. All coordinates are in app units relative to the screen.
482 : // aScreenPoint - the point where the popup should appear
483 : // aSize - the size of the popup
484 : // aScreenBegin - the left or top edge of the screen
485 : // aScreenEnd - the right or bottom edge of the screen
486 : // aAnchorBegin - the left or top edge of the anchor rectangle
487 : // aAnchorEnd - the right or bottom edge of the anchor rectangle
488 : // aMarginBegin - the left or top margin of the popup
489 : // aMarginEnd - the right or bottom margin of the popup
490 : // aOffsetForContextMenu - the additional offset to add for context menus
491 : // aFlip - how to flip or resize the popup when there isn't space
492 : // aFlipSide - pointer to where current flip mode is stored
493 : nscoord FlipOrResize(nscoord& aScreenPoint, nscoord aSize,
494 : nscoord aScreenBegin, nscoord aScreenEnd,
495 : nscoord aAnchorBegin, nscoord aAnchorEnd,
496 : nscoord aMarginBegin, nscoord aMarginEnd,
497 : nscoord aOffsetForContextMenu, FlipStyle aFlip,
498 : bool aIsOnEnd, bool* aFlipSide);
499 :
500 : // check if the popup can fit into the available space by "sliding" (i.e.,
501 : // by having the anchor arrow slide along one axis and only resizing if that
502 : // can't provide the requested size). Only one axis can be slid - the other
503 : // axis is "flipped" as normal. This method can handle either axis, but is
504 : // only called for the sliding axis. All coordinates are in app units
505 : // relative to the screen.
506 : // aScreenPoint - the point where the popup should appear
507 : // aSize - the size of the popup
508 : // aScreenBegin - the left or top edge of the screen
509 : // aScreenEnd - the right or bottom edge of the screen
510 : // aOffset - the amount by which the arrow must be slid such that it is
511 : // still aligned with the anchor.
512 : // Result is the new size of the popup, which will typically be the same
513 : // as aSize, unless aSize is greater than the screen width/height.
514 : nscoord SlideOrResize(nscoord& aScreenPoint, nscoord aSize,
515 : nscoord aScreenBegin, nscoord aScreenEnd,
516 : nscoord *aOffset);
517 :
518 : // Given an anchor frame, compute the anchor rectangle relative to the screen,
519 : // using the popup frame's app units, and taking into account transforms.
520 : nsRect ComputeAnchorRect(nsPresContext* aRootPresContext, nsIFrame* aAnchorFrame);
521 :
522 : // Move the popup to the position specified in its |left| and |top| attributes.
523 : void MoveToAttributePosition();
524 :
525 : /**
526 : * Return whether the popup direction should be RTL.
527 : * If the popup has an anchor, its direction is the anchor direction.
528 : * Otherwise, its the general direction of the UI.
529 : *
530 : * Return whether the popup direction should be RTL.
531 : */
532 0 : bool IsDirectionRTL() const {
533 0 : return mAnchorContent && mAnchorContent->GetPrimaryFrame()
534 0 : ? mAnchorContent->GetPrimaryFrame()->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL
535 0 : : StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
536 : }
537 :
538 : // Create a popup view for this frame. The view is added a child of the root
539 : // view, and is initially hidden.
540 : void CreatePopupView();
541 :
542 64 : nsView* GetViewInternal() const override { return mView; }
543 44 : void SetViewInternal(nsView* aView) override { mView = aView; }
544 :
545 : // Returns true if the popup should try to remain at the same relative
546 : // location as the anchor while it is open. If the anchor becomes hidden
547 : // either directly or indirectly because a parent popup or other element
548 : // is no longer visible, or a parent deck page is changed, the popup hides
549 : // as well. The second variation also sets the anchor rectangle, relative to
550 : // the popup frame.
551 : bool ShouldFollowAnchor();
552 : public:
553 : bool ShouldFollowAnchor(nsRect& aRect);
554 :
555 : protected:
556 : nsString mIncrementalString; // for incremental typing navigation
557 :
558 : // the content that the popup is anchored to, if any, which may be in a
559 : // different document than the popup.
560 : nsCOMPtr<nsIContent> mAnchorContent;
561 :
562 : // the content that triggered the popup, typically the node where the mouse
563 : // was clicked. It will be cleared when the popup is hidden.
564 : nsCOMPtr<nsIContent> mTriggerContent;
565 :
566 : nsMenuFrame* mCurrentMenu; // The current menu that is active.
567 : nsView* mView;
568 :
569 : RefPtr<nsXULPopupShownEvent> mPopupShownDispatcher;
570 :
571 : // The popup's screen rectangle in app units.
572 : nsIntRect mUsedScreenRect;
573 :
574 : // A popup's preferred size may be different than its actual size stored in
575 : // mRect in the case where the popup was resized because it was too large
576 : // for the screen. The preferred size mPrefSize holds the full size the popup
577 : // would be before resizing. Computations are performed using this size.
578 : nsSize mPrefSize;
579 :
580 : // The position of the popup, in CSS pixels.
581 : // The screen coordinates, if set to values other than -1,
582 : // override mXPos and mYPos.
583 : int32_t mXPos;
584 : int32_t mYPos;
585 : nsIntRect mScreenRect;
586 :
587 : // If the panel prefers to "slide" rather than resize, then the arrow gets
588 : // positioned at this offset (along either the x or y axis, depending on
589 : // mPosition)
590 : nscoord mAlignmentOffset;
591 :
592 : // The value of the client offset of our widget the last time we positioned
593 : // ourselves. We store this so that we can detect when it changes but the
594 : // position of our widget didn't change.
595 : mozilla::LayoutDeviceIntPoint mLastClientOffset;
596 :
597 : nsPopupType mPopupType; // type of popup
598 : nsPopupState mPopupState; // open state of the popup
599 :
600 : // popup alignment relative to the anchor node
601 : int8_t mPopupAlignment;
602 : int8_t mPopupAnchor;
603 : int8_t mPosition;
604 :
605 : // One of PopupBoxObject::ROLLUP_DEFAULT/ROLLUP_CONSUME/ROLLUP_NO_CONSUME
606 : uint8_t mConsumeRollupEvent;
607 : FlipType mFlip; // Whether to flip
608 :
609 : struct ReflowCallbackData {
610 44 : ReflowCallbackData() :
611 : mPosted(false),
612 : mAnchor(nullptr),
613 44 : mSizedToPopup(false)
614 44 : {}
615 0 : void MarkPosted(nsIFrame* aAnchor, bool aSizedToPopup) {
616 0 : mPosted = true;
617 0 : mAnchor = aAnchor;
618 0 : mSizedToPopup = aSizedToPopup;
619 0 : }
620 0 : void Clear() {
621 0 : mPosted = false;
622 0 : mAnchor = nullptr;
623 0 : mSizedToPopup = false;
624 0 : }
625 : bool mPosted;
626 : nsIFrame* mAnchor;
627 : bool mSizedToPopup;
628 : };
629 : ReflowCallbackData mReflowCallbackData;
630 :
631 : bool mIsOpenChanged; // true if the open state changed since the last layout
632 : bool mIsContextMenu; // true for context menus
633 : // true if we need to offset the popup to ensure it's not under the mouse
634 : bool mAdjustOffsetForContextMenu;
635 : bool mGeneratedChildren; // true if the contents have been created
636 :
637 : bool mMenuCanOverlapOSBar; // can we appear over the taskbar/menubar?
638 : bool mShouldAutoPosition; // Should SetPopupPosition be allowed to auto position popup?
639 : bool mInContentShell; // True if the popup is in a content shell
640 : bool mIsMenuLocked; // Should events inside this menu be ignored?
641 : bool mMouseTransparent; // True if this is a popup is transparent to mouse events
642 :
643 : // True if this popup has been offset due to moving off / near the edge of the screen.
644 : // (This is useful for ensuring that a move, which can't offset the popup, doesn't undo
645 : // a previously set offset.)
646 : bool mIsOffset;
647 :
648 : // the flip modes that were used when the popup was opened
649 : bool mHFlip;
650 : bool mVFlip;
651 :
652 : // How the popup is anchored.
653 : MenuPopupAnchorType mAnchorType;
654 :
655 : nsRect mOverrideConstraintRect;
656 :
657 : static int8_t sDefaultLevelIsTop;
658 :
659 : static DOMTimeStamp sLastKeyTime;
660 :
661 : // If 0, never timed out. Otherwise, the value is in milliseconds.
662 : static uint32_t sTimeoutOfIncrementalSearch;
663 : }; // class nsMenuPopupFrame
664 :
665 : #endif
|