commit a7b3b2903c2b6fb87d0869ef12851c39adca480e
parent 98b063a0ef2c14f20a4cd184afd82fdbc59b43d6
Author: Emilio Cobos Álvarez <emilio@crisal.io>
Date: Fri, 10 Oct 2025 09:36:05 +0000
Bug 1993570 - Make painting code not use views directly. r=layout-reviewers,dshin
The idea is that by passing (frame, renderer) we'll accommodate popups
not having views (and eventually kill views directly).
Differential Revision: https://phabricator.services.mozilla.com/D268208
Diffstat:
8 files changed, 66 insertions(+), 61 deletions(-)
diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp
@@ -426,8 +426,9 @@ nsDOMWindowUtils::UpdateLayerTree() {
RefPtr<nsViewManager> vm = presShell->GetViewManager();
if (nsView* view = vm->GetRootView()) {
nsAutoScriptBlocker scriptBlocker;
- presShell->PaintAndRequestComposite(view,
- PaintFlags::PaintSyncDecodeImages);
+ presShell->PaintAndRequestComposite(
+ view->GetFrame(), view->GetWidget()->GetWindowRenderer(),
+ PaintFlags::PaintSyncDecodeImages);
presShell->GetWindowRenderer()->WaitOnTransactionProcessed();
}
}
diff --git a/dom/ipc/BrowserChild.cpp b/dom/ipc/BrowserChild.cpp
@@ -3070,7 +3070,9 @@ mozilla::ipc::IPCResult BrowserChild::RecvRenderLayers(const bool& aEnabled) {
} else {
RefPtr<nsViewManager> vm = presShell->GetViewManager();
if (nsView* view = vm->GetRootView()) {
- presShell->PaintAndRequestComposite(view, PaintFlags::None);
+ presShell->PaintAndRequestComposite(
+ view->GetFrame(), view->GetWidget()->GetWindowRenderer(),
+ PaintFlags::None);
}
}
presShell->SuppressDisplayport(false);
diff --git a/dom/view-transitions/ViewTransition.cpp b/dom/view-transitions/ViewTransition.cpp
@@ -1352,13 +1352,16 @@ Maybe<SkipTransitionReason> ViewTransition::CaptureOldState() {
if (RefPtr<PresShell> ps =
nsContentUtils::GetInProcessSubtreeRootDocument(mDocument)
->GetPresShell()) {
- VT_LOG("ViewTransitions::CaptureOldState(), requesting composite");
// Build a display list and send it to WR in order to perform the
// capturing of old content.
RefPtr<nsViewManager> vm = ps->GetViewManager();
- ps->PaintAndRequestComposite(vm->GetRootView(),
- PaintFlags::PaintCompositeOffscreen);
- VT_LOG("ViewTransitions::CaptureOldState(), requesting composite end");
+ if (RefPtr widget = vm->GetRootWidget()) {
+ VT_LOG("ViewTransitions::CaptureOldState(), requesting composite");
+ ps->PaintAndRequestComposite(ps->GetRootFrame(),
+ widget->GetWindowRenderer(),
+ PaintFlags::PaintCompositeOffscreen);
+ VT_LOG("ViewTransitions::CaptureOldState(), requesting composite end");
+ }
}
}
diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp
@@ -5763,8 +5763,8 @@ PresShell::CanvasBackground PresShell::ComputeCanvasBackground() const {
return {viewportBg, pageBg};
}
-nscolor PresShell::ComputeBackstopColor(nsView* aDisplayRoot) {
- nsIWidget* widget = aDisplayRoot->GetWidget();
+nscolor PresShell::ComputeBackstopColor(nsIFrame* aDisplayRoot) {
+ nsIWidget* widget = aDisplayRoot ? aDisplayRoot->GetNearestWidget() : nullptr;
if (widget &&
(widget->GetTransparencyMode() != widget::TransparencyMode::Opaque ||
widget->WidgetPaintsBackground())) {
@@ -6703,18 +6703,21 @@ void PresShell::RemoveFrameFromApproximatelyVisibleList(nsIFrame* aFrame) {
}
}
-void PresShell::PaintAndRequestComposite(nsView* aView, PaintFlags aFlags) {
+void PresShell::PaintAndRequestComposite(nsIFrame* aFrame,
+ WindowRenderer* aRenderer,
+ PaintFlags aFlags) {
if (!mIsActive) {
return;
}
- WindowRenderer* renderer = aView->GetWidget()->GetWindowRenderer();
- NS_ASSERTION(renderer, "Must be in paint event");
- if (renderer->AsFallback()) {
- // The fallback renderer doesn't do any retaining, so we
- // just need to notify the view and widget that we're invalid, and
- // we'll do a paint+composite from the PaintWindow callback.
- GetViewManager()->InvalidateView(aView);
+ NS_ASSERTION(aRenderer, "Must be in paint event");
+ if (aRenderer->AsFallback()) {
+ // The fallback renderer doesn't do any retaining, so we just need to
+ // notify the view and widget that we're invalid, and we'll do a
+ // paint+composite from the PaintWindow callback.
+ if (auto* view = aFrame ? aFrame->GetView() : nullptr) {
+ GetViewManager()->InvalidateView(view);
+ }
return;
}
@@ -6727,26 +6730,28 @@ void PresShell::PaintAndRequestComposite(nsView* aView, PaintFlags aFlags) {
if (aFlags & PaintFlags::PaintCompositeOffscreen) {
flags |= PaintInternalFlags::PaintCompositeOffscreen;
}
- PaintInternal(aView, flags);
+ PaintInternal(aFrame, aRenderer, flags);
}
-void PresShell::SyncPaintFallback(nsView* aView) {
+void PresShell::SyncPaintFallback(nsIFrame* aFrame, WindowRenderer* aRenderer) {
if (!mIsActive) {
return;
}
- WindowRenderer* renderer = aView->GetWidget()->GetWindowRenderer();
- NS_ASSERTION(renderer->AsFallback(),
+ NS_ASSERTION(aRenderer->AsFallback(),
"Can't do Sync paint for remote renderers");
- if (!renderer->AsFallback()) {
+ if (!aRenderer->AsFallback()) {
return;
}
- PaintInternal(aView, PaintInternalFlags::PaintComposite);
+ PaintInternal(aFrame, aRenderer, PaintInternalFlags::PaintComposite);
GetPresContext()->NotifyDidPaintForSubtree();
}
-void PresShell::PaintInternal(nsView* aViewToPaint, PaintInternalFlags aFlags) {
+void PresShell::PaintInternal(nsIFrame* aFrame, WindowRenderer* aRenderer,
+ PaintInternalFlags aFlags) {
+ MOZ_ASSERT_IF(aFrame,
+ aFrame->IsViewportFrame() || aFrame->IsMenuPopupFrame());
nsCString url;
nsIURI* uri = mDocument->GetDocumentURI();
Document* contentRoot = GetPrimaryContentDocument();
@@ -6771,7 +6776,7 @@ void PresShell::PaintInternal(nsView* aViewToPaint, PaintInternalFlags aFlags) {
#endif
NS_ASSERTION(!mIsDestroying, "painting a destroyed PresShell");
- NS_ASSERTION(aViewToPaint, "null view");
+ NS_ASSERTION(aRenderer, "null renderer");
MOZ_ASSERT(!mApproximateFrameVisibilityVisited, "Should have been cleared");
@@ -6779,19 +6784,15 @@ void PresShell::PaintInternal(nsView* aViewToPaint, PaintInternalFlags aFlags) {
return;
}
- nsIFrame* frame = aViewToPaint->GetFrame();
-
FocusTarget focusTarget;
if (StaticPrefs::apz_keyboard_enabled_AtStartup()) {
// Update the focus target for async keyboard scrolling. This will be
// forwarded to APZ by nsDisplayList::PaintRoot. We need to to do this
// before we enter the paint phase because dispatching eVoid events can
// cause layout to happen.
- uint64_t focusSequenceNumber;
- if (nsMenuPopupFrame* popup = do_QueryFrame(frame)) {
+ uint64_t focusSequenceNumber = mAPZFocusSequenceNumber;
+ if (nsMenuPopupFrame* popup = do_QueryFrame(aFrame)) {
focusSequenceNumber = popup->GetAPZFocusSequenceNumber();
- } else {
- focusSequenceNumber = mAPZFocusSequenceNumber;
}
focusTarget = FocusTarget(this, focusSequenceNumber);
}
@@ -6799,9 +6800,7 @@ void PresShell::PaintInternal(nsView* aViewToPaint, PaintInternalFlags aFlags) {
nsPresContext* presContext = GetPresContext();
AUTO_LAYOUT_PHASE_ENTRY_POINT(presContext, Paint);
- WindowRenderer* renderer = aViewToPaint->GetWidget()->GetWindowRenderer();
- NS_ASSERTION(renderer, "Must be in paint event");
- WebRenderLayerManager* layerManager = renderer->AsWebRender();
+ WebRenderLayerManager* layerManager = aRenderer->AsWebRender();
// Whether or not we should set first paint when painting is suppressed
// is debatable. For now we'll do it because B2G relied on first paint
@@ -6820,7 +6819,7 @@ void PresShell::PaintInternal(nsView* aViewToPaint, PaintInternalFlags aFlags) {
const bool offscreen =
bool(aFlags & PaintInternalFlags::PaintCompositeOffscreen);
- if (!renderer->BeginTransaction(url)) {
+ if (!aRenderer->BeginTransaction(url)) {
return;
}
@@ -6830,24 +6829,24 @@ void PresShell::PaintInternal(nsView* aViewToPaint, PaintInternalFlags aFlags) {
layerManager->SetFocusTarget(focusTarget);
}
- if (frame) {
+ if (aFrame) {
if (!(aFlags & PaintInternalFlags::PaintSyncDecodeImages) &&
- !frame->HasAnyStateBits(NS_FRAME_UPDATE_LAYER_TREE)) {
+ !aFrame->HasAnyStateBits(NS_FRAME_UPDATE_LAYER_TREE)) {
if (layerManager) {
layerManager->SetTransactionIdAllocator(presContext->RefreshDriver());
}
- if (renderer->EndEmptyTransaction(
+ if (aRenderer->EndEmptyTransaction(
(aFlags & PaintInternalFlags::PaintComposite)
? WindowRenderer::END_DEFAULT
: WindowRenderer::END_NO_COMPOSITE)) {
return;
}
}
- frame->RemoveStateBits(NS_FRAME_UPDATE_LAYER_TREE);
+ aFrame->RemoveStateBits(NS_FRAME_UPDATE_LAYER_TREE);
}
- nscolor bgcolor = ComputeBackstopColor(aViewToPaint);
+ nscolor bgcolor = ComputeBackstopColor(aFrame);
PaintFrameFlags flags =
PaintFrameFlags::WidgetLayers | PaintFrameFlags::ExistingTransaction;
@@ -6862,21 +6861,21 @@ void PresShell::PaintInternal(nsView* aViewToPaint, PaintInternalFlags aFlags) {
if (aFlags & PaintInternalFlags::PaintCompositeOffscreen) {
flags |= PaintFrameFlags::CompositeOffscreen;
}
- if (renderer->GetBackendType() == layers::LayersBackend::LAYERS_WR) {
+ if (aRenderer->GetBackendType() == layers::LayersBackend::LAYERS_WR) {
flags |= PaintFrameFlags::ForWebRender;
}
- if (frame) {
+ if (aFrame) {
// We can paint directly into the widget using its layer manager.
SelectionNodeCache cache(*this);
- nsLayoutUtils::PaintFrame(nullptr, frame, nsRegion(), bgcolor,
+ nsLayoutUtils::PaintFrame(nullptr, aFrame, nsRegion(), bgcolor,
nsDisplayListBuilderMode::Painting, flags);
return;
}
bgcolor = NS_ComposeColors(bgcolor, mCanvasBackground.mViewport.mColor);
- if (renderer->GetBackendType() == layers::LayersBackend::LAYERS_WR) {
+ if (aRenderer->GetBackendType() == layers::LayersBackend::LAYERS_WR) {
LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(
presContext->GetVisibleArea(), presContext->AppUnitsPerDevPixel());
WebRenderBackgroundData data(wr::ToLayoutRect(bounds),
@@ -6889,7 +6888,7 @@ void PresShell::PaintInternal(nsView* aViewToPaint, PaintInternalFlags aFlags) {
return;
}
- FallbackRenderer* fallback = renderer->AsFallback();
+ FallbackRenderer* fallback = aRenderer->AsFallback();
MOZ_ASSERT(fallback);
if (aFlags & PaintInternalFlags::PaintComposite) {
diff --git a/layout/base/PresShell.h b/layout/base/PresShell.h
@@ -965,7 +965,7 @@ class PresShell final : public nsStubDocumentObserver,
* widget, otherwise the PresContext default background color. This color is
* only visible if the contents of the view as a whole are translucent.
*/
- nscolor ComputeBackstopColor(nsView* aDisplayRoot);
+ nscolor ComputeBackstopColor(nsIFrame* aDisplayRoot);
void ObserveNativeAnonMutationsForPrint(bool aObserve) {
mObservesMutationsForPrint = aObserve;
@@ -1367,14 +1367,15 @@ class PresShell final : public nsStubDocumentObserver,
* SyncPaintFallback from the widget paint event.
*/
MOZ_CAN_RUN_SCRIPT
- void PaintAndRequestComposite(nsView* aView, PaintFlags aFlags);
+ void PaintAndRequestComposite(nsIFrame* aFrame, WindowRenderer* aRenderer,
+ PaintFlags aFlags);
/**
* Does an immediate paint+composite using the FallbackRenderer (which must
* be the current WindowRenderer for the root frame's widget).
*/
MOZ_CAN_RUN_SCRIPT
- void SyncPaintFallback(nsView* aView);
+ void SyncPaintFallback(nsIFrame* aFrame, WindowRenderer* aRenderer);
/**
* Notify that we're going to call Paint with PaintFlags::PaintLayers
@@ -1868,7 +1869,8 @@ class PresShell final : public nsStubDocumentObserver,
bool ComputeActiveness() const;
MOZ_CAN_RUN_SCRIPT
- void PaintInternal(nsView* aViewToPaint, PaintInternalFlags aFlags);
+ void PaintInternal(nsIFrame* aFrame, WindowRenderer* aRenderer,
+ PaintInternalFlags aFlags);
// Refresh observer management.
void ScheduleFlush();
diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp
@@ -2860,12 +2860,9 @@ void nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame,
nsIFrame* displayRoot = GetDisplayRootFrame(aFrame);
- if (aFlags & PaintFrameFlags::WidgetLayers) {
- nsView* view = aFrame->GetView();
- if (!(view && view->GetWidget() && displayRoot == aFrame)) {
- aFlags &= ~PaintFrameFlags::WidgetLayers;
- NS_ASSERTION(aRenderingContext, "need a rendering context");
- }
+ if ((aFlags & PaintFrameFlags::WidgetLayers) && displayRoot != aFrame) {
+ aFlags &= ~PaintFrameFlags::WidgetLayers;
+ NS_ASSERTION(aRenderingContext, "need a rendering context");
}
nsPresContext* presContext = aFrame->PresContext();
@@ -6690,7 +6687,7 @@ bool nsLayoutUtils::HasNonZeroCornerOnSide(const BorderRadius& aCorners,
/* static */
widget::TransparencyMode nsLayoutUtils::GetFrameTransparency(
- nsIFrame* aBackgroundFrame, nsIFrame* aCSSRootFrame) {
+ const nsIFrame* aBackgroundFrame, const nsIFrame* aCSSRootFrame) {
if (!aCSSRootFrame->StyleEffects()->IsOpaque()) {
return TransparencyMode::Transparent;
}
diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h
@@ -2166,8 +2166,8 @@ class nsLayoutUtils {
* @return a value suitable for passing to SetWindowTranslucency.
*/
using TransparencyMode = mozilla::widget::TransparencyMode;
- static TransparencyMode GetFrameTransparency(nsIFrame* aBackgroundFrame,
- nsIFrame* aCSSRootFrame);
+ static TransparencyMode GetFrameTransparency(const nsIFrame* aBackgroundFrame,
+ const nsIFrame* aCSSRootFrame);
/**
* A frame is a popup if it has its own floating window. Menus, panels
diff --git a/view/nsViewManager.cpp b/view/nsViewManager.cpp
@@ -269,11 +269,11 @@ void nsViewManager::Refresh(nsView* aView,
printf_stderr("--COMPOSITE-- %p\n", presShell.get());
}
#endif
- WindowRenderer* renderer = widget->GetWindowRenderer();
+ RefPtr<WindowRenderer> renderer = widget->GetWindowRenderer();
if (!renderer->NeedsWidgetInvalidation()) {
renderer->FlushRendering(wr::RenderReasons::WIDGET);
} else {
- presShell->SyncPaintFallback(aView);
+ presShell->SyncPaintFallback(aView->GetFrame(), renderer);
}
#ifdef MOZ_DUMP_PAINTING
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
@@ -396,7 +396,8 @@ void nsViewManager::ProcessPendingUpdatesPaint(nsIWidget* aWidget) {
}
#endif
- presShell->PaintAndRequestComposite(view, PaintFlags::None);
+ presShell->PaintAndRequestComposite(
+ view->GetFrame(), aWidget->GetWindowRenderer(), PaintFlags::None);
view->SetForcedRepaint(false);
#ifdef MOZ_DUMP_PAINTING