Coverage Report

Created: 2018-09-25 14:53

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