diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index d2f7a240fdef..a5ca578a8a96 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -360,7 +360,8 @@ nsDOMWindowUtils::UpdateLayerTree() { RefPtr vm = presShell->GetViewManager(); if (nsView* view = vm->GetRootView()) { nsAutoScriptBlocker scriptBlocker; - presShell->Paint(view, PaintFlags::PaintSyncDecodeImages); + presShell->PaintAndRequestComposite(view, + PaintFlags::PaintSyncDecodeImages); presShell->GetWindowRenderer()->WaitOnTransactionProcessed(); } } diff --git a/dom/ipc/BrowserChild.cpp b/dom/ipc/BrowserChild.cpp index 8324202b61bf..4bf2e01d8494 100644 --- a/dom/ipc/BrowserChild.cpp +++ b/dom/ipc/BrowserChild.cpp @@ -2734,7 +2734,7 @@ mozilla::ipc::IPCResult BrowserChild::RecvRenderLayers( } else { RefPtr vm = presShell->GetViewManager(); if (nsView* view = vm->GetRootView()) { - presShell->Paint(view, PaintFlags::None); + presShell->PaintAndRequestComposite(view, PaintFlags::None); } } presShell->SuppressDisplayport(false); diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp index eec1313e834b..a7dc2d6b42e8 100644 --- a/layout/base/PresShell.cpp +++ b/layout/base/PresShell.cpp @@ -6195,22 +6195,47 @@ void PresShell::RemoveFrameFromApproximatelyVisibleList(nsIFrame* aFrame) { } } -class nsAutoNotifyDidPaint { - public: - nsAutoNotifyDidPaint(PresShell* aShell, PaintFlags aFlags) - : mShell(aShell), mFlags(aFlags) {} - ~nsAutoNotifyDidPaint() { - if (!!(mFlags & PaintFlags::PaintComposite)) { - mShell->GetPresContext()->NotifyDidPaintForSubtree(); - } +void PresShell::PaintAndRequestComposite(nsView* aView, PaintFlags aFlags) { + if (!mIsActive) { + return; } - private: - PresShell* mShell; - PaintFlags mFlags; -}; + 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); + return; + } -void PresShell::Paint(nsView* aViewToPaint, PaintFlags aFlags) { + // Otherwise we're a retained WebRenderLayerManager, so we want to call + // Paint to update with any changes and push those to WR. + PaintInternalFlags flags = PaintInternalFlags::None; + if (aFlags & PaintFlags::PaintSyncDecodeImages) { + flags |= PaintInternalFlags::PaintSyncDecodeImages; + } + PaintInternal(aView, flags); +} + +void PresShell::SyncPaintFallback(nsView* aView) { + if (!mIsActive) { + return; + } + + WindowRenderer* renderer = aView->GetWidget()->GetWindowRenderer(); + NS_ASSERTION(renderer->AsFallback(), + "Can't do Sync paint for remote renderers"); + if (!renderer->AsFallback()) { + return; + } + + PaintInternal(aView, PaintInternalFlags::PaintComposite); + GetPresContext()->NotifyDidPaintForSubtree(); +} + +void PresShell::PaintInternal(nsView* aViewToPaint, PaintInternalFlags aFlags) { nsCString url; nsIURI* uri = mDocument->GetDocumentURI(); Document* contentRoot = GetPrimaryContentDocument(); @@ -6226,7 +6251,7 @@ void PresShell::Paint(nsView* aViewToPaint, PaintFlags aFlags) { // assert there. However, we don't rely on this assertion on Android because // we don't paint while JS is running. #if !defined(MOZ_WIDGET_ANDROID) - if (!(aFlags & PaintFlags::PaintComposite)) { + if (!(aFlags & PaintInternalFlags::PaintComposite)) { // We need to allow content JS when the flag is set since we may trigger // MozAfterPaint events in content in those cases. nojs.emplace(dom::danger::GetJSContext()); @@ -6258,9 +6283,6 @@ void PresShell::Paint(nsView* aViewToPaint, PaintFlags aFlags) { WindowRenderer* renderer = aViewToPaint->GetWidget()->GetWindowRenderer(); NS_ASSERTION(renderer, "Must be in paint event"); WebRenderLayerManager* layerManager = renderer->AsWebRender(); - bool shouldInvalidate = renderer->NeedsWidgetInvalidation(); - - nsAutoNotifyDidPaint notifyDidPaint(this, aFlags); // 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 @@ -6277,13 +6299,6 @@ void PresShell::Paint(nsView* aViewToPaint, PaintFlags aFlags) { } if (!renderer->BeginTransaction(url)) { - if (renderer->AsFallback() && !(aFlags & PaintFlags::PaintComposite)) { - // The fallback renderer doesn't do any retaining, and so always - // fails when called without PaintComposite (from the refresh driver). - // We just need to notify the view and widget that we're invalid, and - // we'll do a paint+composite from the PaintWindow callback. - aViewToPaint->GetViewManager()->InvalidateView(aViewToPaint); - } return; } @@ -6294,19 +6309,16 @@ void PresShell::Paint(nsView* aViewToPaint, PaintFlags aFlags) { } if (frame) { - if (!(aFlags & PaintFlags::PaintSyncDecodeImages) && + if (!(aFlags & PaintInternalFlags::PaintSyncDecodeImages) && !frame->HasAnyStateBits(NS_FRAME_UPDATE_LAYER_TREE)) { if (layerManager) { layerManager->SetTransactionIdAllocator(presContext->RefreshDriver()); } - if (renderer->EndEmptyTransaction((aFlags & PaintFlags::PaintComposite) - ? LayerManager::END_DEFAULT - : LayerManager::END_NO_COMPOSITE)) { - if (shouldInvalidate) { - aViewToPaint->GetViewManager()->InvalidateView(aViewToPaint); - } - + if (renderer->EndEmptyTransaction( + (aFlags & PaintInternalFlags::PaintComposite) + ? LayerManager::END_DEFAULT + : LayerManager::END_NO_COMPOSITE)) { frame->UpdatePaintCountForPaintedPresShells(); return; } @@ -6323,7 +6335,7 @@ void PresShell::Paint(nsView* aViewToPaint, PaintFlags aFlags) { // We force sync-decode for printing / print-preview (printing already does // this from nsPageSequenceFrame::PrintNextSheet). - if (aFlags & PaintFlags::PaintSyncDecodeImages || + if (aFlags & PaintInternalFlags::PaintSyncDecodeImages || mDocument->IsStaticDocument()) { flags |= PaintFrameFlags::SyncDecodeImages; } @@ -6356,7 +6368,7 @@ void PresShell::Paint(nsView* aViewToPaint, PaintFlags aFlags) { FallbackRenderer* fallback = renderer->AsFallback(); MOZ_ASSERT(fallback); - if (aFlags & PaintFlags::PaintComposite) { + if (aFlags & PaintInternalFlags::PaintComposite) { nsIntRect bounds = presContext->GetVisibleArea().ToOutsidePixels( presContext->AppUnitsPerDevPixel()); fallback->EndTransactionWithColor(bounds, ToDeviceColor(bgcolor)); diff --git a/layout/base/PresShell.h b/layout/base/PresShell.h index 23b43c1b99ac..1b893cb2fbe7 100644 --- a/layout/base/PresShell.h +++ b/layout/base/PresShell.h @@ -90,6 +90,7 @@ struct nsCallbackEventRequest; namespace mozilla { class nsDisplayList; class nsDisplayListBuilder; +class FallbackRenderer; class AccessibleCaretEventHub; class EventStates; @@ -1265,8 +1266,21 @@ class PresShell final : public nsStubDocumentObserver, void BackingScaleFactorChanged() { mPresContext->UIResolutionChangedSync(); } + /** + * Does any painting work required to update retained paint state, and pushes + * it the compositor (if any). Requests a composite, either by scheduling a + * remote composite, or invalidating the widget so that we get a call to + * SyncPaintFallback from the widget paint event. + */ MOZ_CAN_RUN_SCRIPT - void Paint(nsView* aViewToPaint, PaintFlags aFlags); + void PaintAndRequestComposite(nsView* aView, 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); /** * Notify that we're going to call Paint with PaintFlags::PaintLayers @@ -1699,6 +1713,9 @@ class PresShell final : public nsStubDocumentObserver, void SetIsActive(bool aIsActive); bool ShouldBeActive() const; + MOZ_CAN_RUN_SCRIPT + void PaintInternal(nsView* aViewToPaint, PaintInternalFlags aFlags); + /** * Refresh observer management. */ diff --git a/layout/base/PresShellForwards.h b/layout/base/PresShellForwards.h index fa0c635771a6..4cdfc60c434b 100644 --- a/layout/base/PresShellForwards.h +++ b/layout/base/PresShellForwards.h @@ -188,14 +188,22 @@ MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(AddCanvasBackgroundColorFlags) enum class PaintFlags { None = 0, - /* Composite layers to the window. */ - PaintComposite = 1 << 1, /* Sync-decode images. */ - PaintSyncDecodeImages = 1 << 2, + PaintSyncDecodeImages = 1 << 1, }; MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(PaintFlags) +enum class PaintInternalFlags { + None = 0, + /* Sync-decode images. */ + PaintSyncDecodeImages = 1 << 1, + /* Composite layers to the window. */ + PaintComposite = 1 << 2, +}; + +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(PaintInternalFlags) + // This is a private enum class of PresShell, but currently, // MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS isn't available in class definition. // Therefore, we need to put this here. diff --git a/view/nsViewManager.cpp b/view/nsViewManager.cpp index e41f482ad201..927cedd86cf7 100644 --- a/view/nsViewManager.cpp +++ b/view/nsViewManager.cpp @@ -318,7 +318,7 @@ void nsViewManager::Refresh(nsView* aView, if (!renderer->NeedsWidgetInvalidation()) { renderer->FlushRendering(); } else { - presShell->Paint(aView, PaintFlags::PaintComposite); + presShell->SyncPaintFallback(aView); } #ifdef MOZ_DUMP_PAINTING if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) { @@ -441,7 +441,7 @@ void nsViewManager::ProcessPendingUpdatesPaint(nsIWidget* aWidget) { } #endif - presShell->Paint(view, PaintFlags::None); + presShell->PaintAndRequestComposite(view, PaintFlags::None); view->SetForcedRepaint(false); #ifdef MOZ_DUMP_PAINTING