tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 4e8d566344b931bac7de8e949d321a8365593a60
parent 5a626c97e748a6b56fbdc4473c316f3ca9a71a9a
Author: Cosmin Sabou <csabou@mozilla.com>
Date:   Thu, 27 Nov 2025 03:50:31 +0200

Revert "Bug 2002232 - Clean up top level widget painting. r=jwatt" for causing failures on browser_startup.js

This reverts commit 0c8a58a9fe08770a67028525a3e1f2eca98de93c.

Diffstat:
Mlayout/base/PresShell.cpp | 27+++++++++++++++------------
Mlayout/base/PresShell.h | 8++++++--
Mlayout/xul/nsMenuPopupFrame.cpp | 3++-
Mlayout/xul/nsMenuPopupFrame.h | 2+-
Mview/nsView.cpp | 29++++++++++++++---------------
Mview/nsView.h | 6+++++-
Mview/nsViewManager.cpp | 31+++++++++++++++++++++++++++++++
Mview/nsViewManager.h | 4++++
Mwidget/PuppetWidget.cpp | 9++++++++-
Mwidget/cocoa/nsCocoaWindow.h | 5+++--
Mwidget/cocoa/nsCocoaWindow.mm | 30++++++++++++++++++++++++------
Mwidget/gtk/nsWindow.cpp | 52+++++++++++++++++++++++++++++++++++++++++-----------
Mwidget/nsIWidgetListener.h | 28++++++++++++++++++++++++++--
Mwidget/uikit/nsWindow.h | 3++-
Mwidget/uikit/nsWindow.mm | 27+++++++++++++++++++++++----
Mwidget/windows/nsWindowGfx.cpp | 93++++++++++++++++++++++++++++++++++++++++++-------------------------------------
16 files changed, 254 insertions(+), 103 deletions(-)

diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp @@ -10137,21 +10137,24 @@ void PresShell::WillPaint() { } void PresShell::DidPaintWindow() { - if (mHasReceivedPaintMessage) { + nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext(); + if (rootPresContext != mPresContext) { + // This could be a popup's presshell. No point in notifying XPConnect + // about compositing of popups. return; } - mHasReceivedPaintMessage = true; - nsPIDOMWindowOuter* win = mDocument->GetWindow(); - if (!win || !nsGlobalWindowOuter::Cast(win)->IsChromeWindow()) { - return; + + if (!mHasReceivedPaintMessage) { + mHasReceivedPaintMessage = true; + + nsCOMPtr<nsIObserverService> obsvc = services::GetObserverService(); + if (obsvc && mDocument) { + nsPIDOMWindowOuter* window = mDocument->GetWindow(); + if (window && nsGlobalWindowOuter::Cast(window)->IsChromeWindow()) { + obsvc->NotifyObservers(window, "widget-first-paint", nullptr); + } + } } - NS_DispatchToMainThread( - NS_NewRunnableFunction("NotifyWidgetFirstPaint", [win = RefPtr{win}] { - if (nsCOMPtr<nsIObserverService> obsvc = - services::GetObserverService()) { - obsvc->NotifyObservers(win, "widget-first-paint", nullptr); - } - })); } nsSubDocumentFrame* PresShell::GetInProcessEmbedderFrame() const { diff --git a/layout/base/PresShell.h b/layout/base/PresShell.h @@ -1086,8 +1086,12 @@ class PresShell final : public nsStubDocumentObserver, nsresult HandleEvent(nsIFrame* aFrame, WidgetGUIEvent* aEvent, bool aDontRetargetEvents, nsEventStatus* aEventStatus); bool ShouldIgnoreInvalidation(); - // Notify that we called PaintWindow() from widget. - void DidPaintWindow(); + /** + * Notify that we called Paint with PaintFlags::PaintComposite. + * Fires on the presshell for the painted widget. + * This is issued at a time when it's safe to modify widget geometry. + */ + MOZ_CAN_RUN_SCRIPT void DidPaintWindow(); bool IsVisible() const; bool IsUnderHiddenEmbedderElement() const { diff --git a/layout/xul/nsMenuPopupFrame.cpp b/layout/xul/nsMenuPopupFrame.cpp @@ -2593,7 +2593,7 @@ nsEventStatus nsMenuPopupFrame::HandleEvent(mozilla::WidgetGUIEvent* aEvent) { return status; } -void nsMenuPopupFrame::PaintWindow(nsIWidget* aWidget) { +bool nsMenuPopupFrame::PaintWindow(nsIWidget* aWidget, LayoutDeviceIntRegion) { MOZ_ASSERT(aWidget == mWidget); nsAutoScriptBlocker scriptBlocker; RefPtr ps = PresShell(); @@ -2603,6 +2603,7 @@ void nsMenuPopupFrame::PaintWindow(nsIWidget* aWidget) { } else { ps->SyncPaintFallback(this, renderer); } + return true; } void nsMenuPopupFrame::DidCompositeWindow( diff --git a/layout/xul/nsMenuPopupFrame.h b/layout/xul/nsMenuPopupFrame.h @@ -206,7 +206,7 @@ class nsMenuPopupFrame final : public nsBlockFrame, public nsIWidgetListener { MOZ_CAN_RUN_SCRIPT_BOUNDARY nsEventStatus HandleEvent(mozilla::WidgetGUIEvent* aEvent) override; MOZ_CAN_RUN_SCRIPT_BOUNDARY - void PaintWindow(nsIWidget* aWidget) override; + bool PaintWindow(nsIWidget* aWidget, mozilla::LayoutDeviceIntRegion) override; void DidCompositeWindow(mozilla::layers::TransactionId aTransactionId, const mozilla::TimeStamp& aCompositeStart, const mozilla::TimeStamp& aCompositeEnd) override; diff --git a/view/nsView.cpp b/view/nsView.cpp @@ -22,7 +22,6 @@ #include "nsContentUtils.h" // for nsAutoScriptBlocker #include "nsDocShell.h" #include "nsLayoutUtils.h" -#include "WindowRenderer.h" #include "mozilla/StartupTimeline.h" using namespace mozilla; @@ -229,20 +228,20 @@ void nsView::AndroidPipModeChanged(bool aPipMode) { } #endif -void nsView::PaintWindow(nsIWidget* aWidget) { - RefPtr ps = GetPresShell(); - if (!ps) { - return; - } - RefPtr renderer = aWidget->GetWindowRenderer(); - if (!renderer->NeedsWidgetInvalidation()) { - ps->PaintSynchronously(); - renderer->FlushRendering(wr::RenderReasons::WIDGET); - } else { - ps->SyncPaintFallback(ps->GetRootFrame(), renderer); - } - mozilla::StartupTimeline::RecordOnce(mozilla::StartupTimeline::FIRST_PAINT); - ps->DidPaintWindow(); +void nsView::WillPaintWindow(nsIWidget* aWidget) { + RefPtr<nsViewManager> vm = mViewManager; + vm->WillPaintWindow(aWidget); +} + +bool nsView::PaintWindow(nsIWidget* aWidget, LayoutDeviceIntRegion) { + RefPtr<nsViewManager> vm = mViewManager; + vm->PaintWindow(aWidget); + return true; +} + +void nsView::DidPaintWindow() { + RefPtr<nsViewManager> vm = mViewManager; + vm->DidPaintWindow(); } void nsView::DidCompositeWindow(mozilla::layers::TransactionId aTransactionId, diff --git a/view/nsView.h b/view/nsView.h @@ -199,7 +199,11 @@ class nsView final : public nsIWidgetListener { void AndroidPipModeChanged(bool) override; #endif MOZ_CAN_RUN_SCRIPT_BOUNDARY - void PaintWindow(nsIWidget* aWidget) override; + void WillPaintWindow(nsIWidget* aWidget) override; + MOZ_CAN_RUN_SCRIPT_BOUNDARY + bool PaintWindow(nsIWidget* aWidget, LayoutDeviceIntRegion aRegion) override; + MOZ_CAN_RUN_SCRIPT_BOUNDARY + void DidPaintWindow() override; void DidCompositeWindow(mozilla::layers::TransactionId aTransactionId, const mozilla::TimeStamp& aCompositeStart, const mozilla::TimeStamp& aCompositeEnd) override; diff --git a/view/nsViewManager.cpp b/view/nsViewManager.cpp @@ -150,6 +150,37 @@ void nsViewManager::FlushDelayedResize() { } } +void nsViewManager::PaintWindow(nsIWidget* aWidget) { + RefPtr ps = mPresShell; + if (!ps) { + return; + } + RefPtr renderer = aWidget->GetWindowRenderer(); + if (!renderer->NeedsWidgetInvalidation()) { + renderer->FlushRendering(wr::RenderReasons::WIDGET); + } else { + ps->SyncPaintFallback(ps->GetRootFrame(), renderer); + } + mozilla::StartupTimeline::RecordOnce(mozilla::StartupTimeline::FIRST_PAINT); +} + +void nsViewManager::WillPaintWindow(nsIWidget* aWidget) { + WindowRenderer* renderer = aWidget->GetWindowRenderer(); + if (renderer->NeedsWidgetInvalidation()) { + return; + } + if (RefPtr ps = mPresShell) { + // FIXME(bug 2002232): Why is this needed? + ps->PaintSynchronously(); + } +} + +void nsViewManager::DidPaintWindow() { + if (RefPtr<PresShell> presShell = mPresShell) { + presShell->DidPaintWindow(); + } +} + void nsViewManager::MaybeUpdateLastUserEventTime(WidgetGUIEvent* aEvent) { WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); if ((mouseEvent && diff --git a/view/nsViewManager.h b/view/nsViewManager.h @@ -106,6 +106,10 @@ class nsViewManager final { MOZ_CAN_RUN_SCRIPT_BOUNDARY void DoSetWindowDimensions(const nsSize&); bool ShouldDelayResize() const; + MOZ_CAN_RUN_SCRIPT void WillPaintWindow(nsIWidget* aWidget); + MOZ_CAN_RUN_SCRIPT void PaintWindow(nsIWidget* aWidget); + MOZ_CAN_RUN_SCRIPT void DidPaintWindow(); + mozilla::PresShell* mPresShell; // The size for a resize that we delayed until the root view becomes diff --git a/widget/PuppetWidget.cpp b/widget/PuppetWidget.cpp @@ -896,11 +896,18 @@ PuppetWidget::WidgetPaintTask::Run() { } void PuppetWidget::Paint() { + if (!GetPaintListener()) { + return; + } + mWidgetPaintTask.Revoke(); RefPtr<PuppetWidget> strongThis(this); + + GetPaintListener()->WillPaintWindow(this); + if (auto* listener = GetPaintListener()) { - listener->PaintWindow(this); + listener->DidPaintWindow(); } } diff --git a/widget/cocoa/nsCocoaWindow.h b/widget/cocoa/nsCocoaWindow.h @@ -375,8 +375,9 @@ class nsCocoaWindow final : public nsIWidget { int32_t RoundsWidgetCoordinatesTo() override; // Mac specific methods - void PaintWindow(); - void PaintWindowInDrawTarget(mozilla::gfx::DrawTarget* aDT, + void WillPaintWindow(); + bool PaintWindow(LayoutDeviceIntRegion aRegion); + bool PaintWindowInDrawTarget(mozilla::gfx::DrawTarget* aDT, const LayoutDeviceIntRegion& aRegion, const mozilla::gfx::IntSize& aSurfaceSize); diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm @@ -753,17 +753,33 @@ void nsCocoaWindow::Invalidate(const LayoutDeviceIntRect& aRect) { #pragma mark - -void nsCocoaWindow::PaintWindow() { +void nsCocoaWindow::WillPaintWindow() { if (nsIWidgetListener* listener = GetPaintListener()) { - listener->PaintWindow(this); + listener->WillPaintWindow(this); } } -void nsCocoaWindow::PaintWindowInDrawTarget( +bool nsCocoaWindow::PaintWindow(LayoutDeviceIntRegion aRegion) { + nsIWidgetListener* listener = GetPaintListener(); + if (!listener) { + return false; + } + + bool returnValue = listener->PaintWindow(this, aRegion); + + listener = GetPaintListener(); + if (listener) { + listener->DidPaintWindow(); + } + + return returnValue; +} + +bool nsCocoaWindow::PaintWindowInDrawTarget( gfx::DrawTarget* aDT, const LayoutDeviceIntRegion& aRegion, const gfx::IntSize& aSurfaceSize) { if (!aDT || !aDT->IsValid()) { - return; + return false; } gfxContext targetContext(aDT); @@ -779,8 +795,9 @@ void nsCocoaWindow::PaintWindowInDrawTarget( nsAutoRetainCocoaObject kungFuDeathGrip(mChildView); if (GetWindowRenderer()->GetBackendType() == LayersBackend::LAYERS_NONE) { nsIWidget::AutoLayerManagerSetup setupLayerManager(this, &targetContext); - PaintWindow(); + return PaintWindow(aRegion); } + return false; } void nsCocoaWindow::EnsureContentLayerForMainThreadPainting() { @@ -826,6 +843,7 @@ void nsCocoaWindow::PaintWindowInContentLayer() { void nsCocoaWindow::HandleMainThreadCATransaction() { AUTO_PROFILER_MARKER("HandleMainThreadCATransaction", GRAPHICS); + WillPaintWindow(); if (GetWindowRenderer()->GetBackendType() == LayersBackend::LAYERS_NONE) { // We're in BasicLayers mode, i.e. main thread software compositing. @@ -836,7 +854,7 @@ void nsCocoaWindow::HandleMainThreadCATransaction() { // NotifySurfaceReady on the compositor thread to update mNativeLayerRoot's // contents, and the main thread (this thread) will wait inside PaintWindow // during that time. - PaintWindow(); + PaintWindow(LayoutDeviceIntRegion(GetClientBounds())); } { diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp @@ -4107,6 +4107,11 @@ gboolean nsWindow::OnExposeEvent(cairo_t* cr) { RefPtr<nsWindow> strongThis(this); + // Dispatch WillPaintWindow notification to allow scripts etc. to run + // before we paint. It also spins event loop which may show/hide the window + // so we may have new renderer etc. + GetPaintListener()->WillPaintWindow(this); + // If the window has been destroyed during the will paint notification, // there is nothing left to do. if (mIsDestroyed) { @@ -4132,6 +4137,9 @@ gboolean nsWindow::OnExposeEvent(cairo_t* cr) { layerManager->SetNeedsComposite(false); } + // Our bounds may have changed after calling WillPaintWindow. Clip + // to the new bounds here. The region is relative to this + // window. region.AndWith(LayoutDeviceIntRect(LayoutDeviceIntPoint(), GetClientSize())); if (region.IsEmpty()) { LOG("quit, region.IsEmpty()"); @@ -4141,7 +4149,16 @@ gboolean nsWindow::OnExposeEvent(cairo_t* cr) { // If this widget uses OMTC... if (renderer->GetBackendType() == LayersBackend::LAYERS_WR) { LOG("redirect painting to OMTC rendering..."); - listener->PaintWindow(this); + listener->PaintWindow(this, region); + + // Re-get the listener since the will paint notification might have + // killed it. + listener = GetPaintListener(); + if (!listener) { + return TRUE; + } + + listener->DidPaintWindow(); return TRUE; } @@ -4174,16 +4191,25 @@ gboolean nsWindow::OnExposeEvent(cairo_t* cr) { #endif // MOZ_X11 - if (renderer->GetBackendType() == LayersBackend::LAYERS_NONE) { - if (GetTransparencyMode() == TransparencyMode::Transparent && - mHasAlphaVisual) { - // If our draw target is unbuffered and we use an alpha channel, - // clear the image beforehand to ensure we don't get artifacts from a - // reused SHM image. See bug 1258086. - dt->ClearRect(Rect(boundsRect)); + { + if (renderer->GetBackendType() == LayersBackend::LAYERS_NONE) { + if (GetTransparencyMode() == TransparencyMode::Transparent && + mHasAlphaVisual) { + // If our draw target is unbuffered and we use an alpha channel, + // clear the image beforehand to ensure we don't get artifacts from a + // reused SHM image. See bug 1258086. + dt->ClearRect(Rect(boundsRect)); + } + AutoLayerManagerSetup setupLayerManager(this, ctx.ptrOr(nullptr)); + listener->PaintWindow(this, region); + + // Re-get the listener since the will paint notification might have + // killed it. + listener = GetPaintListener(); + if (!listener) { + return TRUE; + } } - AutoLayerManagerSetup setupLayerManager(this, ctx.ptrOr(nullptr)); - listener->PaintWindow(this); } #ifdef MOZ_X11 @@ -4193,8 +4219,12 @@ gboolean nsWindow::OnExposeEvent(cairo_t* cr) { EndRemoteDrawingInRegion(dt, region); + listener->DidPaintWindow(); + // Synchronously flush any new dirty areas - if (cairo_region_t* dirtyArea = gdk_window_get_update_area(mGdkWindow)) { + cairo_region_t* dirtyArea = gdk_window_get_update_area(mGdkWindow); + + if (dirtyArea) { gdk_window_invalidate_region(mGdkWindow, dirtyArea, false); cairo_region_destroy(dirtyArea); gdk_window_process_updates(mGdkWindow, false); diff --git a/widget/nsIWidgetListener.h b/widget/nsIWidgetListener.h @@ -110,9 +110,33 @@ class nsIWidgetListener { */ virtual bool RequestWindowClose(nsIWidget* aWidget) { return false; } - /** Paint the window if needed. */ + /* + * Indicate that a paint is about to occur on this window. This is called + * at a time when it's OK to change the geometry of this widget or of + * other widgets. Must be called before every call to PaintWindow. + */ + MOZ_CAN_RUN_SCRIPT_BOUNDARY + virtual void WillPaintWindow(nsIWidget* aWidget) {} + + /** + * Paint the specified region of the window. Returns true if the + * notification was handled. + * This is called at a time when it is not OK to change the geometry of + * this widget or of other widgets. + */ + MOZ_CAN_RUN_SCRIPT_BOUNDARY + virtual bool PaintWindow(nsIWidget* aWidget, + mozilla::LayoutDeviceIntRegion aRegion) { + return false; + } + /** + * Indicates that a paint occurred. + * This is called at a time when it is OK to change the geometry of + * this widget or of other widgets. + * Must be called after every call to PaintWindow. + */ MOZ_CAN_RUN_SCRIPT_BOUNDARY - virtual void PaintWindow(nsIWidget* aWidget) {} + virtual void DidPaintWindow() {} virtual void DidCompositeWindow(mozilla::layers::TransactionId aTransactionId, const mozilla::TimeStamp& aCompositeStart, diff --git a/widget/uikit/nsWindow.h b/widget/uikit/nsWindow.h @@ -85,7 +85,8 @@ class nsWindow final : public nsIWidget { void Invalidate(const LayoutDeviceIntRect& aRect) override; - void PaintWindow(); + void WillPaintWindow(); + bool PaintWindow(LayoutDeviceIntRegion aRegion); bool HasModalDescendents() { return false; } diff --git a/widget/uikit/nsWindow.mm b/widget/uikit/nsWindow.mm @@ -412,7 +412,11 @@ class nsAutoRetainUIKitObject { if (!mGeckoChild->IsVisible()) return; mWaitingForPaint = NO; - mGeckoChild->PaintWindow(); + + LayoutDeviceIntRect geckoBounds = mGeckoChild->GetBounds(); + LayoutDeviceIntRegion region(geckoBounds); + + mGeckoChild->PaintWindow(region); } // Called asynchronously after setNeedsDisplay in order to avoid entering the @@ -954,12 +958,25 @@ void nsWindow::SetFocus(Raise, mozilla::dom::CallerType) { [mNativeView becomeFirstResponder]; } -void nsWindow::PaintWindow() { +void nsWindow::WillPaintWindow() { if (mWidgetListener) { - mWidgetListener->PaintWindow(this); + mWidgetListener->WillPaintWindow(this); } } +bool nsWindow::PaintWindow(LayoutDeviceIntRegion aRegion) { + if (!mWidgetListener) return false; + + bool returnValue = false; + returnValue = mWidgetListener->PaintWindow(this, aRegion); + + if (mWidgetListener) { + mWidgetListener->DidPaintWindow(); + } + + return returnValue; +} + void nsWindow::ReportMoveEvent() { NotifyWindowMoved(mBounds.x, mBounds.y); } void nsWindow::ReportSizeModeEvent(nsSizeMode aMode) { @@ -1124,11 +1141,13 @@ layers::NativeLayerRoot* nsWindow::GetNativeLayerRoot() { } void nsWindow::HandleMainThreadCATransaction() { + WillPaintWindow(); + // Trigger a synchronous OMTC composite. This will call NextSurface and // NotifySurfaceReady on the compositor thread to update mNativeLayerRoot's // contents, and the main thread (this thread) will wait inside PaintWindow // during that time. - PaintWindow(); + PaintWindow(LayoutDeviceIntRegion(GetBounds())); { // Apply the changes inside mNativeLayerRoot to the underlying CALayers. Now diff --git a/widget/windows/nsWindowGfx.cpp b/widget/windows/nsWindowGfx.cpp @@ -179,6 +179,13 @@ bool nsWindow::OnPaint() { mLastPaintBounds = mBounds; RefPtr<nsWindow> strongThis(this); + if (nsIWidgetListener* listener = GetPaintListener()) { + // WillPaintWindow will update our transparent area if needed, which we use + // below. Note that this might kill the listener. + listener->WillPaintWindow(this); + } + + bool didPaint = false; // BeginPaint/EndPaint must be called to make Windows think that invalid // area is painted. Otherwise it will continue sending the same message // endlessly. Note that we need to call it after WillPaintWindow, which @@ -189,9 +196,39 @@ bool nsWindow::OnPaint() { HDC hDC = ::BeginPaint(mWnd, &ps); auto endPaint = MakeScopeExit([&] { ::EndPaint(mWnd, &ps); - mLastPaintEndTime = TimeStamp::Now(); + if (didPaint) { + mLastPaintEndTime = TimeStamp::Now(); + if (nsIWidgetListener* listener = GetPaintListener()) { + listener->DidPaintWindow(); + } + } }); + LayoutDeviceIntRegion region = GetRegionToPaint(ps, hDC); + LayoutDeviceIntRegion regionToClear; + // Clear the translucent region if needed. + if (isTransparent) { + auto translucentRegion = GetTranslucentRegion(); + // Clear the parts of the translucent region that aren't clear already or + // that Windows has told us to repaint. + // NOTE(emilio): Ordering of region ops is a bit subtle to avoid + // unnecessary copies, but we want to end up with: + // regionToClear = translucentRegion - (mClearedRegion - region) + // mClearedRegion = translucentRegion; + // And add translucentRegion to region afterwards. + regionToClear = translucentRegion; + if (!mClearedRegion.IsEmpty()) { + mClearedRegion.SubOut(region); + regionToClear.SubOut(mClearedRegion); + } + region.OrWith(translucentRegion); + mClearedRegion = std::move(translucentRegion); + } + + if (region.IsEmpty() || !GetPaintListener()) { + return false; + } + Maybe<FallbackPaintContext> fallback; if (isFallback) { uint32_t flags = isTransparent ? gfxWindowsSurface::FLAG_IS_TRANSPARENT : 0; @@ -209,23 +246,12 @@ bool nsWindow::OnPaint() { fallback.emplace(this, std::move(targetSurface), std::move(dt)); } - LayoutDeviceIntRegion region = GetRegionToPaint(ps, hDC); - if (!mClearedRegion.IsEmpty()) { - // Don't consider regions that Windows has told us to repaint as clear, even - // if we've cleared them before. - mClearedRegion.SubOut(region); + if (knowsCompositor && layerManager) { + layerManager->SendInvalidRegion(region.ToUnknownRegion()); + layerManager->ScheduleComposite(wr::RenderReasons::WIDGET); } - auto ComputeAndClearTranslucentRegion = [&]() { - if (!isTransparent) { - return; - } - const LayoutDeviceIntRegion translucentRegion = GetTranslucentRegion(); - auto regionToClear = translucentRegion; - if (!mClearedRegion.IsEmpty()) { - regionToClear.SubOut(mClearedRegion); - } - mClearedRegion = std::move(translucentRegion); + if (!regionToClear.IsEmpty()) { auto black = reinterpret_cast<HBRUSH>(::GetStockObject(BLACK_BRUSH)); // We could use RegionToHRGN, but at least for simple regions (and // possibly for complex ones too?) FillRect is faster; see bug 1946365 @@ -242,33 +268,6 @@ bool nsWindow::OnPaint() { ::FillRect(hDC, &rect, black); } } - region.OrWith(regionToClear); - }; - - // This is a bit subtle: For fallback windows, we paint directly into the DC, - // so we need to clear it before PaintWindow(). - // - // For composited windows, we first need to paint (so that we know the - // translucent area, which is computed from the display list), then we clear - // it. - // - // We don't track the transparent region for popups (meaning we always rely on - // the whole client area being cleared) so this works out. - if (fallback) { - ComputeAndClearTranslucentRegion(); - } - - if (auto* listener = GetPaintListener()) { - listener->PaintWindow(this); - } - - if (!fallback) { - ComputeAndClearTranslucentRegion(); - } - - if (knowsCompositor && layerManager && !region.IsEmpty()) { - layerManager->SendInvalidRegion(region.ToUnknownRegion()); - layerManager->ScheduleComposite(wr::RenderReasons::WIDGET); } #ifdef WIDGET_DEBUG_OUTPUT @@ -276,12 +275,18 @@ bool nsWindow::OnPaint() { (int32_t)mWnd); #endif // WIDGET_DEBUG_OUTPUT + bool result = true; + if (nsIWidgetListener* listener = GetPaintListener()) { + result = listener->PaintWindow(this, region); + } + if (!isFallback && !gfxEnv::MOZ_DISABLE_FORCE_PRESENT()) { NS_DispatchToMainThread(NewRunnableMethod("nsWindow::ForcePresent", this, &nsWindow::ForcePresent)); } - return true; + didPaint = true; + return result; } bool nsWindow::NeedsToTrackWindowOcclusionState() {