commit 476c551dc522acb523a09d2764bffb62098b96ed
parent 0620775c83fdc4a357330c0f7f63b47b940e35a9
Author: Emilio Cobos Álvarez <emilio@crisal.io>
Date: Fri, 17 Oct 2025 06:33:35 +0000
Bug 1994893 - Clean up widget / view / nsDocumentViewer initialization. r=tnikkel,layout-reviewers
We always attach to the top-level widget / never create child popups.
On child processes this is already asserted via nsIWidget::CreateChild,
and on the parent nowadays our behavior would be nonsensical (we'd
create a separate nsCocoaWindow etc).
Differential Revision: https://phabricator.services.mozilla.com/D268976
Diffstat:
9 files changed, 51 insertions(+), 182 deletions(-)
diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp
@@ -11473,12 +11473,9 @@ bool PresShell::VerifyIncrementalReflow() {
// Get our scrolling preference
nsView* rootView = mViewManager->GetRootView();
NS_ENSURE_TRUE(rootView->HasWidget(), false);
- nsIWidget* parentWidget = rootView->GetWidget();
// Create a new view manager.
- auto vm = MakeRefPtr<nsViewManager>();
- rv = vm->Init(dc);
- NS_ENSURE_SUCCESS(rv, false);
+ auto vm = MakeRefPtr<nsViewManager>(dc);
// Create a child window of the parent that is our "root view/window"
// Create a view
@@ -11486,10 +11483,6 @@ bool PresShell::VerifyIncrementalReflow() {
nsView* view = vm->CreateView(tbounds, nullptr);
NS_ENSURE_TRUE(view, false);
- // now create the widget for the view
- rv = view->CreateWidget(parentWidget, true);
- NS_ENSURE_SUCCESS(rv, false);
-
// Setup hierarchical relationship in view manager
vm->SetRootView(view);
diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp
@@ -342,7 +342,7 @@ class nsDocumentViewer final : public nsIDocumentViewer,
* @param aContainerView the container view to hook our root view up
* to as a child, or null if this will be the root view manager
*/
- nsresult MakeWindow(const nsSize& aSize, nsView* aContainerView);
+ void MakeWindow(const nsSize& aSize, nsView* aContainerView);
/**
* Create our device context
@@ -386,11 +386,6 @@ class nsDocumentViewer final : public nsIDocumentViewer,
void InvalidatePotentialSubDocDisplayItem();
- // Whether we should attach to the top level widget. This is true if we
- // are sharing/recycling a single base widget and not creating multiple
- // child widgets.
- bool ShouldAttachToTopLevel();
-
std::tuple<const nsIFrame*, int32_t> GetCurrentSheetFrameAndNumber() const;
protected:
@@ -796,6 +791,7 @@ nsresult nsDocumentViewer::InitInternal(
nsAutoScriptBlocker blockScripts;
mParentWidget = aParentWidget; // not ref counted
+
mBounds = aBounds;
nsresult rv = NS_OK;
@@ -849,10 +845,9 @@ nsresult nsDocumentViewer::InitInternal(
// into nsSubDocumentFrame code through reflows caused by
// FlushPendingNotifications() calls down the road...
- rv = MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(aBounds.width),
- mPresContext->DevPixelsToAppUnits(aBounds.height)),
- containerView);
- NS_ENSURE_SUCCESS(rv, rv);
+ MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(aBounds.width),
+ mPresContext->DevPixelsToAppUnits(aBounds.height)),
+ containerView);
Hide();
#ifdef NS_PRINT_PREVIEW
@@ -1466,8 +1461,7 @@ nsDocumentViewer::Open(nsISupports* aState, nsISHEntry* aSHEntry) {
// page B, we detach. So page A's view has no widget. If we then go
// back to it, and it is in the bfcache, we will use that view, which
// doesn't have a widget. The attach call here will properly attach us.
- if (nsIWidget::UsePuppetWidgets() && mPresContext &&
- ShouldAttachToTopLevel()) {
+ if (mParentWidget && mPresContext) {
// If the old view is already attached to our parent, detach
DetachFromTopLevelWidget();
@@ -2097,12 +2091,9 @@ nsDocumentViewer::Show() {
return rv;
}
- rv = MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(mBounds.width),
- mPresContext->DevPixelsToAppUnits(mBounds.height)),
- containerView);
- if (NS_FAILED(rv)) {
- return rv;
- }
+ MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(mBounds.width),
+ mPresContext->DevPixelsToAppUnits(mBounds.height)),
+ containerView);
if (mPresContext) {
Hide();
@@ -2217,51 +2208,29 @@ nsDocumentViewer::ClearHistoryEntry() {
//-------------------------------------------------------
-nsresult nsDocumentViewer::MakeWindow(const nsSize& aSize,
- nsView* aContainerView) {
+void nsDocumentViewer::MakeWindow(const nsSize& aSize, nsView* aContainerView) {
if (GetIsPrintPreview()) {
- return NS_OK;
- }
-
- const bool shouldAttach = ShouldAttachToTopLevel();
- if (shouldAttach) {
- // If the old view is already attached to our parent, detach
- DetachFromTopLevelWidget();
+ return;
}
- mViewManager = new nsViewManager();
-
- nsDeviceContext* dx = mPresContext->DeviceContext();
-
- nsresult rv = mViewManager->Init(dx);
- if (NS_FAILED(rv)) {
- return rv;
- }
+ mViewManager = new nsViewManager(mPresContext->DeviceContext());
// The root view is always at 0,0.
nsRect tbounds(nsPoint(0, 0), aSize);
// Create a view
nsView* view = mViewManager->CreateView(tbounds, aContainerView);
- if (!view) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
+ MOZ_ASSERT(view);
// Create a widget if we were given a parent widget or don't have a
// container view that we can hook up to without a widget.
// Don't create widgets for ResourceDocs (external resources & svg images),
// because when they're displayed, they're painted into *another* document's
// widget.
- if (!mDocument->IsResourceDoc() && (mParentWidget || !aContainerView)) {
- if (shouldAttach) {
- // Reuse the top level parent widget.
- rv = view->AttachToTopLevelWidget(mParentWidget);
- mAttachedToParent = true;
- } else {
- rv = view->CreateWidget(mParentWidget, true, false);
- }
- if (NS_FAILED(rv)) {
- return rv;
- }
+ MOZ_ASSERT_IF(!aContainerView, mParentWidget);
+ if (!mDocument->IsResourceDoc() && mParentWidget) {
+ // Reuse the top level parent widget.
+ view->AttachToTopLevelWidget(mParentWidget);
+ mAttachedToParent = true;
}
// Setup hierarchical relationship in view manager
@@ -2273,8 +2242,6 @@ nsresult nsDocumentViewer::MakeWindow(const nsSize& aSize,
// go to the scrolled view as soon as the Window is created instead of going
// to the browser window (this enables keyboard scrolling of the document)
// mWindow->SetFocus();
-
- return rv;
}
void nsDocumentViewer::DetachFromTopLevelWidget() {
@@ -3232,25 +3199,6 @@ nsDocumentViewer::GetPrintPreviewNumPages(int32_t* aPrintPreviewNumPages) {
// happening
#endif // NS_PRINTING
-bool nsDocumentViewer::ShouldAttachToTopLevel() {
- if (!mParentWidget) {
- return false;
- }
-
- // We always attach when using puppet widgets
- if (nsIWidget::UsePuppetWidgets() || mParentWidget->IsPuppetWidget()) {
- return true;
- }
-#ifdef DEBUG
- nsIWidgetListener* parentListener = mParentWidget->GetWidgetListener();
- MOZ_ASSERT(!parentListener || !parentListener->GetView(),
- "Expect a top level widget");
- MOZ_ASSERT(!parentListener || !parentListener->GetAsMenuPopupFrame(),
- "Expect a top level widget");
-#endif
- return true;
-}
-
//------------------------------------------------------------
// XXX this always returns false for subdocuments
bool nsDocumentViewer::GetIsPrinting() const {
@@ -3400,10 +3348,9 @@ NS_IMETHODIMP nsDocumentViewer::SetPrintSettingsForSubdocument(
rv = mPresContext->Init(mDeviceContext);
NS_ENSURE_SUCCESS(rv, rv);
- rv = MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(mBounds.width),
- mPresContext->DevPixelsToAppUnits(mBounds.height)),
- FindContainerView());
- NS_ENSURE_SUCCESS(rv, rv);
+ MakeWindow(nsSize(mPresContext->DevPixelsToAppUnits(mBounds.width),
+ mPresContext->DevPixelsToAppUnits(mBounds.height)),
+ FindContainerView());
MOZ_TRY(InitPresentationStuff(true));
}
@@ -3535,7 +3482,7 @@ void nsDocumentViewer::SetPrintPreviewPresentation(nsViewManager* aViewManager,
mPresContext = aPresContext;
mPresShell = aPresShell;
- if (ShouldAttachToTopLevel()) {
+ if (mParentWidget) {
DetachFromTopLevelWidget();
nsView* rootView = mViewManager->GetRootView();
rootView->AttachToTopLevelWidget(mParentWidget);
diff --git a/layout/printing/nsPrintJob.cpp b/layout/printing/nsPrintJob.cpp
@@ -1286,9 +1286,7 @@ nsresult nsPrintJob::ReflowPrintObject(const UniquePtr<nsPrintObject>& aPO) {
// init it with the DC
MOZ_TRY(aPO->mPresContext->Init(printData->mPrintDC));
- aPO->mViewManager = new nsViewManager();
-
- MOZ_TRY(aPO->mViewManager->Init(printData->mPrintDC));
+ aPO->mViewManager = new nsViewManager(printData->mPrintDC);
bool doReturn = false;
bool documentIsTopLevel = false;
diff --git a/view/nsView.cpp b/view/nsView.cpp
@@ -382,55 +382,6 @@ void nsView::RemoveChild(nsView* child) {
}
}
-struct DefaultWidgetInitData : public widget::InitData {
- DefaultWidgetInitData() : widget::InitData() {
- mClipChildren = true;
- mClipSiblings = true;
- }
-};
-
-nsresult nsView::CreateWidget(nsIWidget* aParent, bool aEnableDragDrop,
- bool aResetVisibility) {
- AssertNoWindow();
-
- DefaultWidgetInitData initData;
- LayoutDeviceIntRect trect =
- CalcWidgetBounds(initData.mWindowType, initData.mTransparencyMode);
-
- if (!aParent && GetParent()) {
- aParent = GetParent()->GetNearestWidget(nullptr);
- }
- if (!aParent) {
- NS_ERROR("nsView::CreateWidget without suitable parent widget??");
- return NS_ERROR_FAILURE;
- }
-
- mWindow = aParent->CreateChild(trect, initData);
- if (!mWindow) {
- return NS_ERROR_FAILURE;
- }
-
- InitializeWindow(aEnableDragDrop, aResetVisibility);
-
- return NS_OK;
-}
-
-void nsView::InitializeWindow(bool aEnableDragDrop, bool aResetVisibility) {
- MOZ_ASSERT(mWindow, "Must have a window to initialize");
-
- mWindow->SetWidgetListener(this);
-
- if (aEnableDragDrop) {
- mWindow->EnableDragDrop(true);
- }
-
- // make sure visibility state is accurate
-
- if (aResetVisibility) {
- SetVisibility(GetVisibility());
- }
-}
-
void nsView::SetNeedsWindowPropertiesSync() {
mNeedsWindowPropertiesSync = true;
if (mViewManager) {
@@ -439,8 +390,15 @@ void nsView::SetNeedsWindowPropertiesSync() {
}
// Attach to a top level widget and start receiving mirrored events.
-nsresult nsView::AttachToTopLevelWidget(nsIWidget* aWidget) {
+void nsView::AttachToTopLevelWidget(nsIWidget* aWidget) {
MOZ_ASSERT(aWidget, "null widget ptr");
+#ifdef DEBUG
+ nsIWidgetListener* parentListener = aWidget->GetWidgetListener();
+ MOZ_ASSERT(!parentListener || !parentListener->GetView(),
+ "Expect a top level widget");
+ MOZ_ASSERT(!parentListener || !parentListener->GetAsMenuPopupFrame(),
+ "Expect a top level widget");
+#endif
/// XXXjimm This is a temporary workaround to an issue w/document
// viewer (bug 513162).
@@ -458,18 +416,16 @@ nsresult nsView::AttachToTopLevelWidget(nsIWidget* aWidget) {
mWindow->SetAttachedWidgetListener(this);
if (mWindow->GetWindowType() != WindowType::Invisible) {
- nsresult rv = mWindow->AsyncEnableDragDrop(true);
- NS_ENSURE_SUCCESS(rv, rv);
+ mWindow->AsyncEnableDragDrop(true);
}
mWidgetIsTopLevel = true;
// Refresh the view bounds
RecalcWidgetBounds();
- return NS_OK;
}
// Detach this view from an attached widget.
-nsresult nsView::DetachFromTopLevelWidget() {
+void nsView::DetachFromTopLevelWidget() {
MOZ_ASSERT(mWidgetIsTopLevel, "Not attached currently!");
MOZ_ASSERT(mWindow, "null mWindow for DetachFromTopLevelWidget!");
@@ -490,8 +446,6 @@ nsresult nsView::DetachFromTopLevelWidget() {
mWindow = nullptr;
mWidgetIsTopLevel = false;
-
- return NS_OK;
}
void nsView::AssertNoWindow() {
diff --git a/view/nsView.h b/view/nsView.h
@@ -261,16 +261,6 @@ class nsView final : public nsIWidgetListener {
nsIWidget* GetNearestWidget(nsPoint* aOffset) const;
/**
- * Create a widget to associate with this view. This variant of
- * CreateWidget*() will look around in the view hierarchy for an
- * appropriate parent widget for the view.
- *
- * @return error status
- */
- nsresult CreateWidget(nsIWidget* aParent, bool aEnableDragDrop = true,
- bool aResetVisibility = true);
-
- /**
* Destroys the associated widget for this view. If this method is
* not called explicitly, the widget when be destroyed when its
* view gets destroyed.
@@ -288,8 +278,8 @@ class nsView final : public nsIWidgetListener {
*
* @param aWidget The widget to attach to / detach from.
*/
- nsresult AttachToTopLevelWidget(nsIWidget* aWidget);
- nsresult DetachFromTopLevelWidget();
+ void AttachToTopLevelWidget(nsIWidget* aWidget);
+ void DetachFromTopLevelWidget();
/**
* Returns a flag indicating whether the view owns it's widget
diff --git a/view/nsViewManager.cpp b/view/nsViewManager.cpp
@@ -51,14 +51,17 @@ using namespace mozilla::layers;
uint32_t nsViewManager::gLastUserEventTime = 0;
-nsViewManager::nsViewManager()
- : mPresShell(nullptr),
+nsViewManager::nsViewManager(nsDeviceContext* aContext)
+ : mContext(aContext),
+ mPresShell(nullptr),
mDelayedResize(NSCOORD_NONE, NSCOORD_NONE),
mRootView(nullptr),
mRefreshDisableCount(0),
mPainting(false),
mRecursiveRefreshPending(false),
- mHasPendingWidgetGeometryChanges(false) {}
+ mHasPendingWidgetGeometryChanges(false) {
+ MOZ_ASSERT(aContext);
+}
nsViewManager::~nsViewManager() {
if (mRootView) {
@@ -74,22 +77,6 @@ nsViewManager::~nsViewManager() {
"the PresShell!");
}
-// We don't hold a reference to the presentation context because it
-// holds a reference to us.
-nsresult nsViewManager::Init(nsDeviceContext* aContext) {
- MOZ_ASSERT(nullptr != aContext, "null ptr");
-
- if (nullptr == aContext) {
- return NS_ERROR_NULL_POINTER;
- }
- if (nullptr != mContext) {
- return NS_ERROR_ALREADY_INITIALIZED;
- }
- mContext = aContext;
-
- return NS_OK;
-}
-
nsView* nsViewManager::CreateView(const nsRect& aBounds, nsView* aParent,
ViewVisibility aVisibilityFlag) {
auto* v = new nsView(this, aVisibilityFlag);
@@ -540,7 +527,9 @@ void nsViewManager::WillPaintWindow(nsIWidget* aWidget) {
bool nsViewManager::PaintWindow(nsIWidget* aWidget,
const LayoutDeviceIntRegion& aRegion) {
- if (!aWidget || !mContext) return false;
+ if (!aWidget) {
+ return false;
+ }
NS_ASSERTION(
IsPaintingAllowed(),
diff --git a/view/nsViewManager.h b/view/nsViewManager.h
@@ -36,7 +36,7 @@ class nsViewManager final {
NS_INLINE_DECL_REFCOUNTING(nsViewManager)
- nsViewManager();
+ explicit nsViewManager(nsDeviceContext* aContext);
/**
* Initialize the ViewManager
diff --git a/widget/nsIWidget.cpp b/widget/nsIWidget.cpp
@@ -2292,12 +2292,10 @@ void nsIWidget::NotifyLiveResizeStopped() {
}
}
-nsresult nsIWidget::AsyncEnableDragDrop(bool aEnable) {
- RefPtr<nsIWidget> kungFuDeathGrip = this;
- return NS_DispatchToCurrentThreadQueue(
- NS_NewRunnableFunction(
- "AsyncEnableDragDropFn",
- [this, aEnable, kungFuDeathGrip]() { EnableDragDrop(aEnable); }),
+void nsIWidget::AsyncEnableDragDrop(bool aEnable) {
+ NS_DispatchToCurrentThreadQueue(
+ NewRunnableMethod<bool>("AsyncEnableDragDrop", this,
+ &nsIWidget::EnableDragDrop, aEnable),
kAsyncDragDropTimeout, EventQueuePriority::Idle);
}
diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h
@@ -1566,7 +1566,7 @@ class nsIWidget : public nsSupportsWeakReference {
* Enables the dropping of files to a widget.
*/
virtual void EnableDragDrop(bool aEnable) {}
- nsresult AsyncEnableDragDrop(bool aEnable);
+ void AsyncEnableDragDrop(bool aEnable);
/**
* Classify the window for the window manager. Mostly for X11.