Skip to content

Commit 93b4c09

Browse files
committed
Bug 1933181 - Stop using nsView for popups. r=layout-reviewers,tnikkel
Make the popup frame listener to the widget events itself, rather than via the view tree. This is a first step towards getting rid of views as a whole. This creates the (annoying, but temporary) subtlety of the view tree jumping across popups, so nsIFrame::GetNearestWidget and co need to become a bit careful and avoid doing that. Similarly a couple places relied on view visibility, which now need to check nsMenuPopupFrame::IsOpen() as well. Other than that this seems to just work. Differential Revision: https://phabricator.services.mozilla.com/D230106
1 parent 104e206 commit 93b4c09

24 files changed

+538
-626
lines changed

accessible/generic/LocalAccessible.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "mozilla/a11y/Platform.h"
1818
#include "mozilla/FocusModel.h"
1919
#include "nsAccUtils.h"
20+
#include "nsMenuPopupFrame.h"
2021
#include "nsAccessibilityService.h"
2122
#include "ApplicationAccessible.h"
2223
#include "nsGenericHTMLElement.h"
@@ -316,13 +317,14 @@ uint64_t LocalAccessible::VisibilityState() const {
316317
// scrolled out.
317318
nsIFrame* curFrame = frame;
318319
do {
319-
nsView* view = curFrame->GetView();
320-
if (view && view->GetVisibility() == ViewVisibility::Hide) {
321-
return states::INVISIBLE;
320+
if (nsView* view = curFrame->GetView()) {
321+
if (view->GetVisibility() == ViewVisibility::Hide) {
322+
return states::INVISIBLE;
323+
}
322324
}
323325

324-
if (nsLayoutUtils::IsPopup(curFrame)) {
325-
return 0;
326+
if (nsMenuPopupFrame* popup = do_QueryFrame(curFrame)) {
327+
return popup->IsOpen() ? 0 : states::INVISIBLE;
326328
}
327329

328330
if (curFrame->StyleUIReset()->mMozSubtreeHiddenOnlyVisually) {

dom/base/nsContentUtils.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@
117117
#include "mozilla/StaticPrefs_dom.h"
118118
#include "mozilla/extensions/WebExtensionPolicy.h"
119119
#include "nsIOService.h"
120+
#include "nsMenuPopupFrame.h"
120121
#include "nsObjectLoadingContent.h"
121122
#ifdef FUZZING
122123
# include "mozilla/StaticPrefs_fuzzing.h"

dom/base/nsDOMWindowUtils.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
#include "nsJSEnvironment.h"
6868
#include "nsJSUtils.h"
6969
#include "nsLayoutUtils.h"
70+
#include "nsMenuPopupFrame.h"
7071
#include "nsPresContext.h"
7172
#include "nsQueryContentEventResult.h"
7273
#include "nsQueryObject.h"

layout/base/PresShell.cpp

Lines changed: 63 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -4146,20 +4146,6 @@ void PresShell::SchedulePaint() {
41464146
}
41474147
}
41484148

4149-
void PresShell::DispatchSynthMouseOrPointerMove(
4150-
WidgetMouseEvent* aMouseOrPointerMoveEvent) {
4151-
AUTO_PROFILER_TRACING_MARKER_DOCSHELL("Paint",
4152-
"DispatchSynthMouseOrPointerMove",
4153-
GRAPHICS, mPresContext->GetDocShell());
4154-
nsEventStatus status = nsEventStatus_eIgnore;
4155-
nsView* targetView = nsView::GetViewFor(aMouseOrPointerMoveEvent->mWidget);
4156-
if (!targetView) {
4157-
return;
4158-
}
4159-
RefPtr<nsViewManager> viewManager = targetView->GetViewManager();
4160-
viewManager->DispatchEvent(aMouseOrPointerMoveEvent, targetView, &status);
4161-
}
4162-
41634149
void PresShell::ClearMouseCaptureOnView(nsView* aView) {
41644150
if (nsIContent* capturingContent = GetCapturingContent()) {
41654151
if (aView) {
@@ -5910,13 +5896,12 @@ void PresShell::SynthesizeMouseMove(bool aFromScroll) {
59105896
}
59115897
}
59125898

5913-
static nsView* FindFloatingViewContaining(nsPresContext* aRootPresContext,
5914-
nsIWidget* aRootWidget,
5915-
const LayoutDeviceIntPoint& aPt) {
5916-
nsIFrame* popupFrame = nsLayoutUtils::GetPopupFrameForPoint(
5899+
static nsMenuPopupFrame* FindPopupFrame(nsPresContext* aRootPresContext,
5900+
nsIWidget* aRootWidget,
5901+
const LayoutDeviceIntPoint& aPt) {
5902+
return nsLayoutUtils::GetPopupFrameForPoint(
59175903
aRootPresContext, aRootWidget, aPt,
59185904
nsLayoutUtils::GetPopupFrameForPointFlags::OnlyReturnFramesWithWidgets);
5919-
return popupFrame ? popupFrame->GetView() : nullptr;
59205905
}
59215906

59225907
/*
@@ -5925,8 +5910,7 @@ static nsView* FindFloatingViewContaining(nsPresContext* aRootPresContext,
59255910
* floating view. It assumes that only floating views extend outside the bounds
59265911
* of their parents.
59275912
*
5928-
* This methods should only be called if FindFloatingViewContaining returns
5929-
* null.
5913+
* This methods should only be called if FindPopupFrame returns null.
59305914
*
59315915
* aPt is relative aRelativeToView with the viewport type
59325916
* aRelativeToViewportType. aRelativeToView will always have a frame. If aView
@@ -6123,82 +6107,77 @@ void PresShell::ProcessSynthMouseOrPointerMoveEvent(
61236107

61246108
int32_t APD = mPresContext->AppUnitsPerDevPixel();
61256109

6126-
// We need a widget to put in the event we are going to dispatch so we look
6127-
// for a view that has a widget and the mouse location is over. We first look
6128-
// for floating views, if there isn't one we use the root view. |view| holds
6129-
// that view.
6130-
nsView* view = nullptr;
6131-
6132-
// The appunits per devpixel ratio of |view|.
6133-
int32_t viewAPD;
6134-
61356110
// mRefPoint will be mMouseLocation relative to the widget of |view|, the
6136-
// widget we will put in the event we dispatch, in viewAPD appunits
6111+
// widget we will put in the event we dispatch, in widgetAPD appunits
61376112
nsPoint refpoint(0, 0);
61386113

6139-
// We always dispatch the event to the pres shell that contains the view that
6140-
// the mouse is over. pointVM is the VM of that pres shell.
6141-
nsViewManager* pointVM = nullptr;
6142-
61436114
nsView* const rootView = mViewManager ? mViewManager->GetRootView() : nullptr;
61446115
if (!rootView || !rootView->HasWidget()) {
61456116
return;
61466117
}
6147-
#ifdef DEBUG
6148-
nsCOMPtr<nsIDragSession> dragSession =
6149-
nsContentUtils::GetDragSession(rootView->GetWidget());
6150-
MOZ_ASSERT(!dragSession);
6151-
#endif
6118+
MOZ_ASSERT(!nsCOMPtr{nsContentUtils::GetDragSession(rootView->GetWidget())});
61526119

6120+
// We need a widget to put in the event we are going to dispatch so we look
6121+
// for a view that has a widget and the mouse location is over. We first look
6122+
// for floating views, if there isn't one we use the root view. |view| holds
6123+
// that view.
6124+
nsCOMPtr<nsIWidget> widget;
6125+
// We always dispatch the event to the pres shell that contains the view that
6126+
// the mouse is over. pointShell is that.
6127+
RefPtr<PresShell> pointShell;
6128+
// The appunits per devpixel ratio of |widget|.
6129+
int32_t widgetAPD;
6130+
// If we're in a child process and the view points to an OOP iframe, this is
6131+
// its BrowserBridgeChild.
6132+
RefPtr<BrowserBridgeChild> bbc;
6133+
6134+
// We either dispatch the event to a popup, or a view.
6135+
nsMenuPopupFrame* popupFrame = nullptr;
61536136
if (rootView->GetFrame()) {
6154-
view =
6155-
FindFloatingViewContaining(mPresContext, rootView->GetWidget(),
6156-
LayoutDeviceIntPoint::FromAppUnitsToNearest(
6157-
aPointerInfo.mLastRefPointInRootDoc +
6158-
rootView->ViewToWidgetOffset(),
6159-
APD));
6160-
}
6161-
6162-
nsView* pointView = view;
6163-
if (!view) {
6164-
view = rootView;
6137+
popupFrame = FindPopupFrame(mPresContext, rootView->GetWidget(),
6138+
LayoutDeviceIntPoint::FromAppUnitsToNearest(
6139+
aPointerInfo.mLastRefPointInRootDoc +
6140+
rootView->ViewToWidgetOffset(),
6141+
APD));
6142+
if (popupFrame) {
6143+
pointShell = popupFrame->PresShell();
6144+
widget = popupFrame->GetWidget();
6145+
widgetAPD = popupFrame->PresContext()->AppUnitsPerDevPixel();
6146+
refpoint = aPointerInfo.mLastRefPointInRootDoc;
6147+
DebugOnly<nsLayoutUtils::TransformResult> result =
6148+
nsLayoutUtils::TransformPoint(
6149+
RelativeTo{rootView->GetFrame(), ViewportType::Visual},
6150+
RelativeTo{popupFrame, ViewportType::Layout}, refpoint);
6151+
MOZ_ASSERT(result == nsLayoutUtils::TRANSFORM_SUCCEEDED);
6152+
}
6153+
}
6154+
if (!widget) {
6155+
widget = rootView->GetWidget();
6156+
widgetAPD = APD;
6157+
nsView* pointView = rootView;
61656158
if (rootView->GetFrame()) {
61666159
pointView = FindViewContaining(rootView, ViewportType::Visual, rootView,
61676160
aPointerInfo.mLastRefPointInRootDoc);
6168-
} else {
6169-
pointView = rootView;
61706161
}
61716162
// pointView can be null in situations related to mouse capture
6172-
pointVM = (pointView ? pointView : view)->GetViewManager();
6163+
pointShell = (pointView ? pointView : rootView)->GetPresShell();
6164+
bbc = GetChildBrowser(pointView);
61736165
refpoint =
61746166
aPointerInfo.mLastRefPointInRootDoc + rootView->ViewToWidgetOffset();
6175-
viewAPD = APD;
6176-
} else {
6177-
pointVM = view->GetViewManager();
6178-
nsIFrame* frame = view->GetFrame();
6179-
NS_ASSERTION(frame, "floating views can't be anonymous");
6180-
viewAPD = frame->PresContext()->AppUnitsPerDevPixel();
6181-
refpoint = aPointerInfo.mLastRefPointInRootDoc;
6182-
DebugOnly<nsLayoutUtils::TransformResult> result =
6183-
nsLayoutUtils::TransformPoint(
6184-
RelativeTo{rootView->GetFrame(), ViewportType::Visual},
6185-
RelativeTo{frame, ViewportType::Layout}, refpoint);
6186-
MOZ_ASSERT(result == nsLayoutUtils::TRANSFORM_SUCCEEDED);
6187-
refpoint += view->ViewToWidgetOffset();
6188-
}
6189-
NS_ASSERTION(view->GetWidget(), "view should have a widget here");
6167+
}
6168+
NS_ASSERTION(widget, "view should have a widget here");
61906169
Maybe<WidgetMouseEvent> mouseMoveEvent;
61916170
Maybe<WidgetPointerEvent> pointerMoveEvent;
61926171
if (aMoveMessage == eMouseMove) {
6193-
mouseMoveEvent.emplace(true, eMouseMove, view->GetWidget(),
6172+
mouseMoveEvent.emplace(true, eMouseMove, widget,
61946173
WidgetMouseEvent::eSynthesized);
61956174
mouseMoveEvent->mButton = MouseButton::ePrimary;
61966175
// We don't want to dispatch preceding pointer event since the caller
61976176
// should've already been dispatched it. However, if the target is an OOP
61986177
// iframe, we'll set this to true again below.
61996178
mouseMoveEvent->convertToPointer = false;
62006179
} else {
6201-
pointerMoveEvent.emplace(true, ePointerMove, view->GetWidget());
6180+
pointerMoveEvent.emplace(true, ePointerMove, widget);
62026181
pointerMoveEvent->mButton = MouseButton::eNotPressed;
62036182
pointerMoveEvent->mReason = WidgetMouseEvent::eSynthesized;
62046183
}
@@ -6214,13 +6193,13 @@ void PresShell::ProcessSynthMouseOrPointerMoveEvent(
62146193
event.mFlags.mIsSynthesizedForTests = aPointerInfo.mIsSynthesizedForTests;
62156194

62166195
event.mRefPoint =
6217-
LayoutDeviceIntPoint::FromAppUnitsToNearest(refpoint, viewAPD);
6196+
LayoutDeviceIntPoint::FromAppUnitsToNearest(refpoint, widgetAPD);
62186197
event.mButtons = aPointerInfo.mLastButtons;
62196198
event.mInputSource = aPointerInfo.mInputSource;
62206199
event.pointerId = aPointerId;
62216200
event.mModifiers = PresShell::GetCurrentModifiers();
62226201

6223-
if (BrowserBridgeChild* bbc = GetChildBrowser(pointView)) {
6202+
if (bbc) {
62246203
// If we have a BrowserBridgeChild, we're going to be dispatching this
62256204
// mouse event into an OOP iframe of the current document if and only if
62266205
// we're synthesizing a mouse move.
@@ -6237,7 +6216,7 @@ void PresShell::ProcessSynthMouseOrPointerMoveEvent(
62376216
return;
62386217
}
62396218

6240-
if (RefPtr<PresShell> presShell = pointVM->GetPresShell()) {
6219+
if (pointShell) {
62416220
// Since this gets run in a refresh tick there isn't an InputAPZContext on
62426221
// the stack from the nsBaseWidget. We need to simulate one with at least
62436222
// the correct target guid, so that the correct callback transform gets
@@ -6246,7 +6225,16 @@ void PresShell::ProcessSynthMouseOrPointerMoveEvent(
62466225
// input block. Same for the APZ response field.
62476226
InputAPZContext apzContext(aPointerInfo.mLastTargetGuid, 0,
62486227
nsEventStatus_eIgnore);
6249-
presShell->DispatchSynthMouseOrPointerMove(&event);
6228+
AUTO_PROFILER_TRACING_MARKER_DOCSHELL(
6229+
"Paint", "DispatchSynthMouseOrPointerMove", GRAPHICS,
6230+
pointShell->GetPresContext()->GetDocShell());
6231+
nsEventStatus status = nsEventStatus_eIgnore;
6232+
if (popupFrame) {
6233+
pointShell->HandleEvent(popupFrame, &event, false, &status);
6234+
} else {
6235+
RefPtr<nsViewManager> viewManager = rootView->GetViewManager();
6236+
viewManager->DispatchEvent(&event, rootView, &status);
6237+
}
62506238
}
62516239
}
62526240

layout/base/PresShell.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,9 +1091,6 @@ class PresShell final : public nsStubDocumentObserver,
10911091
mUnderHiddenEmbedderElement = aUnderHiddenEmbedderElement;
10921092
}
10931093

1094-
MOZ_CAN_RUN_SCRIPT void DispatchSynthMouseOrPointerMove(
1095-
WidgetMouseEvent* aMouseOrPointerMoveEvent);
1096-
10971094
/* Temporarily ignore the Displayport for better paint performance. We
10981095
* trigger a repaint once suppression is disabled. Without that
10991096
* the displayport may get left at the suppressed size for an extended

layout/base/nsDocumentViewer.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3245,6 +3245,8 @@ bool nsDocumentViewer::ShouldAttachToTopLevel() {
32453245
nsIWidgetListener* parentListener = mParentWidget->GetWidgetListener();
32463246
MOZ_ASSERT(!parentListener || !parentListener->GetView(),
32473247
"Expect a top level widget");
3248+
MOZ_ASSERT(!parentListener || !parentListener->GetAsMenuPopupFrame(),
3249+
"Expect a top level widget");
32483250
#endif
32493251
return true;
32503252
}

layout/base/nsLayoutUtils.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1582,7 +1582,7 @@ nsIFrame* nsLayoutUtils::GetPopupFrameForEventCoordinates(
15821582
guiEvent->mRefPoint);
15831583
}
15841584

1585-
nsIFrame* nsLayoutUtils::GetPopupFrameForPoint(
1585+
nsMenuPopupFrame* nsLayoutUtils::GetPopupFrameForPoint(
15861586
nsPresContext* aRootPresContext, nsIWidget* aWidget,
15871587
const mozilla::LayoutDeviceIntPoint& aPoint,
15881588
GetPopupFrameForPointFlags aFlags /* = GetPopupFrameForPointFlags(0) */) {

layout/base/nsLayoutUtils.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,7 @@ class nsLayoutUtils {
719719
enum class GetPopupFrameForPointFlags : uint8_t {
720720
OnlyReturnFramesWithWidgets = 0x1,
721721
};
722-
static nsIFrame* GetPopupFrameForPoint(
722+
static nsMenuPopupFrame* GetPopupFrameForPoint(
723723
nsPresContext* aRootPresContext, nsIWidget* aWidget,
724724
const mozilla::LayoutDeviceIntPoint& aPoint,
725725
GetPopupFrameForPointFlags aFlags = GetPopupFrameForPointFlags(0));

layout/base/nsRefreshDriver.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2638,6 +2638,10 @@ bool nsRefreshDriver::PaintIfNeeded() {
26382638
{
26392639
PaintTelemetry::AutoRecordPaint record;
26402640
vm->ProcessPendingUpdates();
2641+
// Paint our popups.
2642+
if (nsXULPopupManager* pm = nsXULPopupManager::GetInstance()) {
2643+
pm->PaintPopups(this);
2644+
}
26412645
}
26422646
return true;
26432647
}

layout/generic/FrameClasses.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@
9595
Frame("nsMathMLmtrFrame", "TableRow", TABLE_PART | MATHML),
9696
Frame("nsMathMLmunderoverFrame", "None", MATHML_CONTAINER),
9797
Frame("nsMathMLTokenFrame", "None", MATHML_CONTAINER),
98-
Frame("nsMenuPopupFrame", "MenuPopup", BLOCK | MAY_HAVE_VIEW),
98+
Frame("nsMenuPopupFrame", "MenuPopup", BLOCK),
9999
Frame("nsNumberControlFrame", "TextInput", REPLACED | LEAF),
100100
Frame("nsPageBreakFrame", "PageBreak", COMMON | LEAF),
101101
Frame("nsPageContentFrame", "PageContent", BLOCK),

0 commit comments

Comments
 (0)