Bug 1922333 - Land view transition plumbing for live capture behind a default-off pref. r=view-transitions-reviewers,boris

It is mostly working, but there are some tests that hit crashes and
asserts that we should sort out. For now, land it default-off.

This does implement other bits that are on by default tho, like creating
image frames for ::view-transition-new() pseudo-elements and so on. I
think that is fine (it's just that for now they are all transparent).

Differential Revision: https://phabricator.services.mozilla.com/D239382
This commit is contained in:
Emilio Cobos Álvarez
2025-03-05 11:18:18 +00:00
parent d58176b429
commit 0ff8015e82
18 changed files with 388 additions and 103 deletions

View File

@@ -5,11 +5,17 @@
#include "ViewTransition.h" #include "ViewTransition.h"
#include "mozilla/gfx/2D.h" #include "mozilla/gfx/2D.h"
#include "WindowRenderer.h"
#include "mozilla/layers/WebRenderLayerManager.h"
#include "mozilla/layers/RenderRootStateManager.h"
#include "mozilla/dom/BindContext.h" #include "mozilla/dom/BindContext.h"
#include "mozilla/layers/WebRenderBridgeChild.h"
#include "mozilla/gfx/DataSurfaceHelpers.h"
#include "mozilla/dom/DocumentInlines.h" #include "mozilla/dom/DocumentInlines.h"
#include "mozilla/dom/DocumentTimeline.h" #include "mozilla/dom/DocumentTimeline.h"
#include "mozilla/dom/Promise-inl.h" #include "mozilla/dom/Promise-inl.h"
#include "mozilla/dom/ViewTransitionBinding.h" #include "mozilla/dom/ViewTransitionBinding.h"
#include "mozilla/image/WebRenderImageProvider.h"
#include "mozilla/webrender/WebRenderAPI.h" #include "mozilla/webrender/WebRenderAPI.h"
#include "mozilla/AnimationEventDispatcher.h" #include "mozilla/AnimationEventDispatcher.h"
#include "mozilla/EffectSet.h" #include "mozilla/EffectSet.h"
@@ -18,9 +24,11 @@
#include "mozilla/SVGIntegrationUtils.h" #include "mozilla/SVGIntegrationUtils.h"
#include "mozilla/WritingModes.h" #include "mozilla/WritingModes.h"
#include "nsDisplayList.h" #include "nsDisplayList.h"
#include "nsFrameState.h"
#include "nsITimer.h" #include "nsITimer.h"
#include "nsLayoutUtils.h" #include "nsLayoutUtils.h"
#include "nsPresContext.h" #include "nsPresContext.h"
#include "nsString.h"
#include "Units.h" #include "Units.h"
namespace mozilla::dom { namespace mozilla::dom {
@@ -84,8 +92,78 @@ static RefPtr<gfx::DataSourceSurface> CaptureFallbackSnapshot(
return surf->GetDataSurface(); return surf->GetDataSurface();
} }
static layers::RenderRootStateManager* GetWRStateManagerFor(nsIFrame* aFrame) {
if ((true)) {
// TODO(emilio): Enable this code-path.
return nullptr;
}
nsIWidget* widget = aFrame->GetNearestWidget();
if (NS_WARN_IF(!widget)) {
return nullptr;
}
auto* renderer = widget->GetWindowRenderer();
if (NS_WARN_IF(!renderer)) {
return nullptr;
}
layers::WebRenderLayerManager* lm = renderer->AsWebRender();
if (NS_WARN_IF(!lm)) {
return nullptr;
}
return lm->GetRenderRootStateManager();
}
static constexpr wr::ImageKey kNoKey{{0}, 0};
struct OldSnapshotData {
wr::ImageKey mImageKey = kNoKey;
nsSize mSize;
RefPtr<gfx::DataSourceSurface> mFallback;
RefPtr<layers::RenderRootStateManager> mManager;
OldSnapshotData() = default;
explicit OldSnapshotData(nsIFrame* aFrame)
: mSize(aFrame->InkOverflowRectRelativeToSelf().Size()),
mManager(GetWRStateManagerFor(aFrame)) {
if (mManager) {
mImageKey = mManager->WrBridge()->GetNextImageKey();
} else {
mFallback = CaptureFallbackSnapshot(aFrame);
}
}
void EnsureKey(layers::RenderRootStateManager* aManager,
wr::IpcResourceUpdateQueue& aResources) {
if (mImageKey != kNoKey) {
MOZ_ASSERT(mManager == aManager, "Stale manager?");
return;
}
if (NS_WARN_IF(!mFallback)) {
return;
}
gfx::DataSourceSurface::ScopedMap map(mFallback,
gfx::DataSourceSurface::READ);
if (NS_WARN_IF(!map.IsMapped())) {
return;
}
mManager = aManager;
mImageKey = aManager->WrBridge()->GetNextImageKey();
auto size = mFallback->GetSize();
auto format = mFallback->GetFormat();
wr::ImageDescriptor desc(size, format);
Range<uint8_t> bytes(map.GetData(), map.GetStride() * size.height);
Unused << NS_WARN_IF(!aResources.AddImage(mImageKey, desc, bytes));
}
~OldSnapshotData() {
if (mManager) {
mManager->AddImageKeyForDiscard(mImageKey);
}
}
};
struct CapturedElementOldState { struct CapturedElementOldState {
RefPtr<gfx::DataSourceSurface> mImage; OldSnapshotData mSnapshot;
// Whether we tried to capture an image. Note we might fail to get a // Whether we tried to capture an image. Note we might fail to get a
// snapshot, so this might not be the same as !!mImage. // snapshot, so this might not be the same as !!mImage.
bool mTriedImage = false; bool mTriedImage = false;
@@ -101,7 +179,7 @@ struct CapturedElementOldState {
CapturedElementOldState(nsIFrame* aFrame, CapturedElementOldState(nsIFrame* aFrame,
const nsSize& aSnapshotContainingBlockSize) const nsSize& aSnapshotContainingBlockSize)
: mImage(CaptureFallbackSnapshot(aFrame)), : mSnapshot(aFrame),
mTriedImage(true), mTriedImage(true),
mSize(aFrame->Style()->IsRootElementStyle() mSize(aFrame->Style()->IsRootElementStyle()
? aSnapshotContainingBlockSize ? aSnapshotContainingBlockSize
@@ -119,6 +197,8 @@ struct CapturedElementOldState {
struct ViewTransition::CapturedElement { struct ViewTransition::CapturedElement {
CapturedElementOldState mOldState; CapturedElementOldState mOldState;
RefPtr<Element> mNewElement; RefPtr<Element> mNewElement;
wr::SnapshotImageKey mNewSnapshotKey{kNoKey};
nsSize mNewSnapshotSize;
CapturedElement() = default; CapturedElement() = default;
@@ -135,6 +215,14 @@ struct ViewTransition::CapturedElement {
RefPtr<StyleLockedDeclarationBlock> mOldRule; RefPtr<StyleLockedDeclarationBlock> mOldRule;
// The rules for ::view-transition-new(<name>). // The rules for ::view-transition-new(<name>).
RefPtr<StyleLockedDeclarationBlock> mNewRule; RefPtr<StyleLockedDeclarationBlock> mNewRule;
~CapturedElement() {
if (wr::AsImageKey(mNewSnapshotKey) != kNoKey) {
MOZ_ASSERT(mOldState.mSnapshot.mManager);
mOldState.mSnapshot.mManager->AddSnapshotImageKeyForDiscard(
mNewSnapshotKey);
}
}
}; };
static inline void ImplCycleCollectionTraverse( static inline void ImplCycleCollectionTraverse(
@@ -164,12 +252,75 @@ ViewTransition::ViewTransition(Document& aDoc,
ViewTransition::~ViewTransition() { ClearTimeoutTimer(); } ViewTransition::~ViewTransition() { ClearTimeoutTimer(); }
gfx::DataSourceSurface* ViewTransition::GetOldSurface(nsAtom* aName) const { Maybe<nsSize> ViewTransition::GetOldSize(nsAtom* aName) const {
auto* el = mNamedElements.Get(aName);
if (NS_WARN_IF(!el)) {
return {};
}
return Some(el->mOldState.mSnapshot.mSize);
}
Maybe<nsSize> ViewTransition::GetNewSize(nsAtom* aName) const {
auto* el = mNamedElements.Get(aName);
if (NS_WARN_IF(!el)) {
return {};
}
return Some(el->mNewSnapshotSize);
}
const wr::ImageKey* ViewTransition::GetOldImageKey(
nsAtom* aName, layers::RenderRootStateManager* aManager,
wr::IpcResourceUpdateQueue& aResources) const {
auto* el = mNamedElements.Get(aName); auto* el = mNamedElements.Get(aName);
if (NS_WARN_IF(!el)) { if (NS_WARN_IF(!el)) {
return nullptr; return nullptr;
} }
return el->mOldState.mImage; el->mOldState.mSnapshot.EnsureKey(aManager, aResources);
return &el->mOldState.mSnapshot.mImageKey;
}
const wr::ImageKey* ViewTransition::GetNewImageKey(nsAtom* aName) const {
auto* el = mNamedElements.Get(aName);
if (NS_WARN_IF(!el)) {
return nullptr;
}
return &el->mNewSnapshotKey._0;
}
const wr::ImageKey* ViewTransition::GetImageKeyForCapturedFrame(
nsIFrame* aFrame, layers::RenderRootStateManager* aManager,
wr::IpcResourceUpdateQueue& aResources) const {
MOZ_ASSERT(aFrame);
MOZ_ASSERT(aFrame->HasAnyStateBits(NS_FRAME_CAPTURED_IN_VIEW_TRANSITION));
if (!StaticPrefs::dom_viewTransitions_live_capture()) {
return nullptr;
}
nsAtom* name = aFrame->StyleUIReset()->mViewTransitionName._0.AsAtom();
if (NS_WARN_IF(name->IsEmpty())) {
return nullptr;
}
const bool isOld = mPhase < Phase::Animating;
if (isOld) {
return GetOldImageKey(name, aManager, aResources);
}
auto* el = mNamedElements.Get(name);
if (NS_WARN_IF(!el)) {
return nullptr;
}
if (NS_WARN_IF(el->mNewElement != aFrame->GetContent())) {
return nullptr;
}
if (wr::AsImageKey(el->mNewSnapshotKey) == kNoKey) {
MOZ_ASSERT(!el->mOldState.mSnapshot.mManager ||
el->mOldState.mSnapshot.mManager == aManager,
"Stale manager?");
el->mNewSnapshotKey = {aManager->WrBridge()->GetNextImageKey()};
el->mOldState.mSnapshot.mManager = aManager;
aResources.AddSnapshotImage(el->mNewSnapshotKey);
}
return &el->mNewSnapshotKey._0;
} }
nsIGlobalObject* ViewTransition::GetParentObject() const { nsIGlobalObject* ViewTransition::GetParentObject() const {
@@ -262,7 +413,7 @@ void ViewTransition::CallUpdateCallback(ErrorResult& aRv) {
// new state, so we need to flush frames. Do it here so that we deal // new state, so we need to flush frames. Do it here so that we deal
// with other potential script execution skipping the transition or // with other potential script execution skipping the transition or
// what not in a consistent way. // what not in a consistent way.
aVt->mDocument->FlushPendingNotifications(FlushType::Frames); aVt->mDocument->FlushPendingNotifications(FlushType::Layout);
if (aVt->mPhase == Phase::Done) { if (aVt->mPhase == Phase::Done) {
// "Skip a transition" step 8. We need to resolve "finished" after // "Skip a transition" step 8. We need to resolve "finished" after
// update-callback-done. // update-callback-done.
@@ -604,15 +755,15 @@ bool ViewTransition::UpdatePseudoElementStyles(bool aNeedsInvalidation) {
auto size = CSSPixel::FromAppUnits(newRect); auto size = CSSPixel::FromAppUnits(newRect);
// NOTE(emilio): Intentionally not short-circuiting. Int cast is needed to // NOTE(emilio): Intentionally not short-circuiting. Int cast is needed to
// silence warning. // silence warning.
bool changed = int(SetProp(rule, mDocument, eCSSProperty_width, size.width, bool groupStyleChanged = int(SetProp(rule, mDocument, eCSSProperty_width,
eCSSUnit_Pixel)) | size.width, eCSSUnit_Pixel)) |
SetProp(rule, mDocument, eCSSProperty_height, size.height, SetProp(rule, mDocument, eCSSProperty_height,
eCSSUnit_Pixel) | size.height, eCSSUnit_Pixel) |
SetProp(rule, mDocument, eCSSProperty_transform, SetProp(rule, mDocument, eCSSProperty_transform,
EffectiveTransform(frame)); EffectiveTransform(frame));
// TODO: writing-mode, direction, text-orientation, mix-blend-mode, // TODO: writing-mode, direction, text-orientation, mix-blend-mode,
// backdrop-filter, color-scheme. // backdrop-filter, color-scheme.
if (changed && aNeedsInvalidation) { if (groupStyleChanged && aNeedsInvalidation) {
auto* pseudo = FindPseudo(PseudoStyleRequest( auto* pseudo = FindPseudo(PseudoStyleRequest(
PseudoStyleType::viewTransitionGroup, transitionName)); PseudoStyleType::viewTransitionGroup, transitionName));
MOZ_ASSERT(pseudo); MOZ_ASSERT(pseudo);
@@ -621,7 +772,16 @@ bool ViewTransition::UpdatePseudoElementStyles(bool aNeedsInvalidation) {
nsLayoutUtils::PostRestyleEvent(pseudo, RestyleHint::RECASCADE_SELF, nsLayoutUtils::PostRestyleEvent(pseudo, RestyleHint::RECASCADE_SELF,
nsChangeHint(0)); nsChangeHint(0));
} }
// 5. TODO(emilio): Live capturing (probably nothing to do here)
// 5. Live capturing (nothing to do here regarding the capture itself, but
// if the size has changed, then we need to invalidate the new frame).
auto oldSize = capturedElement.mNewSnapshotSize;
capturedElement.mNewSnapshotSize =
frame->InkOverflowRectRelativeToSelf().Size();
if (oldSize != capturedElement.mNewSnapshotSize && aNeedsInvalidation) {
frame->PresShell()->FrameNeedsReflow(
frame, IntrinsicDirty::FrameAndAncestors, NS_FRAME_IS_DIRTY);
}
} }
return true; return true;
} }
@@ -931,6 +1091,8 @@ Maybe<SkipTransitionReason> ViewTransition::CaptureNewState() {
auto& capturedElement = mNamedElements.LookupOrInsertWith( auto& capturedElement = mNamedElements.LookupOrInsertWith(
name, [&] { return MakeUnique<CapturedElement>(); }); name, [&] { return MakeUnique<CapturedElement>(); });
capturedElement->mNewElement = aFrame->GetContent()->AsElement(); capturedElement->mNewElement = aFrame->GetContent()->AsElement();
capturedElement->mNewSnapshotSize =
aFrame->InkOverflowRectRelativeToSelf().Size();
aFrame->AddStateBits(NS_FRAME_CAPTURED_IN_VIEW_TRANSITION); aFrame->AddStateBits(NS_FRAME_CAPTURED_IN_VIEW_TRANSITION);
return true; return true;
}); });

View File

@@ -5,6 +5,7 @@
#ifndef mozilla_dom_ViewTransition_h #ifndef mozilla_dom_ViewTransition_h
#define mozilla_dom_ViewTransition_h #define mozilla_dom_ViewTransition_h
#include "mozilla/layers/IpcResourceUpdateQueue.h"
#include "nsRect.h" #include "nsRect.h"
#include "nsWrapperCache.h" #include "nsWrapperCache.h"
#include "nsAtomHashKeys.h" #include "nsAtomHashKeys.h"
@@ -25,6 +26,15 @@ namespace gfx {
class DataSourceSurface; class DataSourceSurface;
} }
namespace layers {
class RenderRootStateManager;
}
namespace wr {
struct ImageKey;
class IpcResourceUpdateQueue;
} // namespace wr
namespace dom { namespace dom {
class Document; class Document;
@@ -69,7 +79,15 @@ class ViewTransition final : public nsISupports, public nsWrapperCache {
void PerformPendingOperations(); void PerformPendingOperations();
Element* GetRoot() const { return mViewTransitionRoot; } Element* GetRoot() const { return mViewTransitionRoot; }
gfx::DataSourceSurface* GetOldSurface(nsAtom* aName) const; Maybe<nsSize> GetOldSize(nsAtom* aName) const;
Maybe<nsSize> GetNewSize(nsAtom* aName) const;
const wr::ImageKey* GetOldImageKey(nsAtom* aName,
layers::RenderRootStateManager*,
wr::IpcResourceUpdateQueue&) const;
const wr::ImageKey* GetNewImageKey(nsAtom* aName) const;
const wr::ImageKey* GetImageKeyForCapturedFrame(
nsIFrame* aFrame, layers::RenderRootStateManager*,
wr::IpcResourceUpdateQueue&) const;
Element* FindPseudo(const PseudoStyleRequest&) const; Element* FindPseudo(const PseudoStyleRequest&) const;

View File

@@ -25,6 +25,7 @@ using mozilla::wr::FontInstanceKey from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::FontKey from "mozilla/webrender/WebRenderTypes.h"; using mozilla::wr::FontKey from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::ImageKey from "mozilla/webrender/WebRenderTypes.h"; using mozilla::wr::ImageKey from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::BlobImageKey from "mozilla/webrender/WebRenderTypes.h"; using mozilla::wr::BlobImageKey from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::SnapshotImageKey from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::WrRotation from "mozilla/webrender/WebRenderTypes.h"; using mozilla::wr::WrRotation from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::PipelineId from "mozilla/webrender/WebRenderTypes.h"; using mozilla::wr::PipelineId from "mozilla/webrender/WebRenderTypes.h";
using mozilla::LayoutDeviceRect from "Units.h"; using mozilla::LayoutDeviceRect from "Units.h";
@@ -114,6 +115,10 @@ struct OpAddBlobImage {
BlobImageKey key; BlobImageKey key;
}; };
struct OpAddSnapshotImage {
SnapshotImageKey key;
};
struct OpUpdateImage { struct OpUpdateImage {
ImageDescriptor descriptor; ImageDescriptor descriptor;
OffsetRange bytes; OffsetRange bytes;
@@ -143,6 +148,10 @@ struct OpDeleteImage {
ImageKey key; ImageKey key;
}; };
struct OpDeleteSnapshotImage {
SnapshotImageKey key;
};
struct OpDeleteBlobImage { struct OpDeleteBlobImage {
BlobImageKey key; BlobImageKey key;
}; };
@@ -179,11 +188,13 @@ struct OpDeleteFontInstance {
union OpUpdateResource { union OpUpdateResource {
OpAddImage; OpAddImage;
OpAddBlobImage; OpAddBlobImage;
OpAddSnapshotImage;
OpUpdateImage; OpUpdateImage;
OpUpdateBlobImage; OpUpdateBlobImage;
OpSetBlobImageVisibleArea; OpSetBlobImageVisibleArea;
OpDeleteImage; OpDeleteImage;
OpDeleteBlobImage; OpDeleteBlobImage;
OpDeleteSnapshotImage;
OpAddRawFont; OpAddRawFont;
OpAddFontDescriptor; OpAddFontDescriptor;
OpDeleteFont; OpDeleteFont;

View File

@@ -322,6 +322,10 @@ bool IpcResourceUpdateQueue::AddImage(ImageKey key,
return true; return true;
} }
void IpcResourceUpdateQueue::AddSnapshotImage(SnapshotImageKey aKey) {
mUpdates.AppendElement(layers::OpAddSnapshotImage(aKey));
}
bool IpcResourceUpdateQueue::AddBlobImage(BlobImageKey key, bool IpcResourceUpdateQueue::AddBlobImage(BlobImageKey key,
const ImageDescriptor& aDescriptor, const ImageDescriptor& aDescriptor,
Range<uint8_t> aBytes, Range<uint8_t> aBytes,
@@ -393,6 +397,10 @@ void IpcResourceUpdateQueue::DeleteImage(ImageKey aKey) {
mUpdates.AppendElement(layers::OpDeleteImage(aKey)); mUpdates.AppendElement(layers::OpDeleteImage(aKey));
} }
void IpcResourceUpdateQueue::DeleteSnapshotImage(SnapshotImageKey aKey) {
mUpdates.AppendElement(layers::OpDeleteSnapshotImage(aKey));
}
void IpcResourceUpdateQueue::DeleteBlobImage(BlobImageKey aKey) { void IpcResourceUpdateQueue::DeleteBlobImage(BlobImageKey aKey) {
mUpdates.AppendElement(layers::OpDeleteBlobImage(aKey)); mUpdates.AppendElement(layers::OpDeleteBlobImage(aKey));
} }

View File

@@ -132,6 +132,8 @@ class IpcResourceUpdateQueue {
bool AddBlobImage(wr::BlobImageKey aKey, const ImageDescriptor& aDescriptor, bool AddBlobImage(wr::BlobImageKey aKey, const ImageDescriptor& aDescriptor,
Range<uint8_t> aBytes, ImageIntRect aVisibleRect); Range<uint8_t> aBytes, ImageIntRect aVisibleRect);
void AddSnapshotImage(wr::SnapshotImageKey aKey);
void AddSharedExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey); void AddSharedExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey);
void PushExternalImageForTexture(wr::ExternalImageId aExtId, void PushExternalImageForTexture(wr::ExternalImageId aExtId,
@@ -156,6 +158,8 @@ class IpcResourceUpdateQueue {
void DeleteBlobImage(wr::BlobImageKey aKey); void DeleteBlobImage(wr::BlobImageKey aKey);
void DeleteSnapshotImage(wr::SnapshotImageKey aKey);
bool AddRawFont(wr::FontKey aKey, Range<uint8_t> aBytes, uint32_t aIndex); bool AddRawFont(wr::FontKey aKey, Range<uint8_t> aBytes, uint32_t aIndex);
bool AddFontDescriptor(wr::FontKey aKey, Range<uint8_t> aBytes, bool AddFontDescriptor(wr::FontKey aKey, Range<uint8_t> aBytes,

View File

@@ -86,6 +86,11 @@ void RenderRootStateManager::AddBlobImageKeyForDiscard(wr::BlobImageKey key) {
mBlobImageKeysToDelete.AppendElement(key); mBlobImageKeysToDelete.AppendElement(key);
} }
void RenderRootStateManager::AddSnapshotImageKeyForDiscard(
wr::SnapshotImageKey key) {
mSnapshotImageKeysToDelete.AppendElement(key);
}
void RenderRootStateManager::DiscardImagesInTransaction( void RenderRootStateManager::DiscardImagesInTransaction(
wr::IpcResourceUpdateQueue& aResources) { wr::IpcResourceUpdateQueue& aResources) {
for (const auto& key : mImageKeysToDelete) { for (const auto& key : mImageKeysToDelete) {
@@ -94,8 +99,12 @@ void RenderRootStateManager::DiscardImagesInTransaction(
for (const auto& key : mBlobImageKeysToDelete) { for (const auto& key : mBlobImageKeysToDelete) {
aResources.DeleteBlobImage(key); aResources.DeleteBlobImage(key);
} }
for (const auto& key : mSnapshotImageKeysToDelete) {
aResources.DeleteSnapshotImage(key);
}
mImageKeysToDelete.Clear(); mImageKeysToDelete.Clear();
mBlobImageKeysToDelete.Clear(); mBlobImageKeysToDelete.Clear();
mSnapshotImageKeysToDelete.Clear();
} }
void RenderRootStateManager::DiscardLocalImages() { void RenderRootStateManager::DiscardLocalImages() {
@@ -104,6 +113,7 @@ void RenderRootStateManager::DiscardLocalImages() {
// image keys but didn't tell the parent about them yet. // image keys but didn't tell the parent about them yet.
mImageKeysToDelete.Clear(); mImageKeysToDelete.Clear();
mBlobImageKeysToDelete.Clear(); mBlobImageKeysToDelete.Clear();
mSnapshotImageKeysToDelete.Clear();
} }
void RenderRootStateManager::ClearCachedResources() { void RenderRootStateManager::ClearCachedResources() {

View File

@@ -35,8 +35,9 @@ class RenderRootStateManager {
WebRenderUserDataRefTable* GetWebRenderUserDataTable(); WebRenderUserDataRefTable* GetWebRenderUserDataTable();
WebRenderLayerManager* LayerManager() { return mLayerManager; } WebRenderLayerManager* LayerManager() { return mLayerManager; }
void AddImageKeyForDiscard(wr::ImageKey key); void AddImageKeyForDiscard(wr::ImageKey);
void AddBlobImageKeyForDiscard(wr::BlobImageKey key); void AddBlobImageKeyForDiscard(wr::BlobImageKey);
void AddSnapshotImageKeyForDiscard(wr::SnapshotImageKey);
void DiscardImagesInTransaction(wr::IpcResourceUpdateQueue& aResources); void DiscardImagesInTransaction(wr::IpcResourceUpdateQueue& aResources);
void DiscardLocalImages(); void DiscardLocalImages();
@@ -76,6 +77,7 @@ class RenderRootStateManager {
Maybe<wr::IpcResourceUpdateQueue> mAsyncResourceUpdates; Maybe<wr::IpcResourceUpdateQueue> mAsyncResourceUpdates;
nsTArray<wr::ImageKey> mImageKeysToDelete; nsTArray<wr::ImageKey> mImageKeysToDelete;
nsTArray<wr::BlobImageKey> mBlobImageKeysToDelete; nsTArray<wr::BlobImageKey> mBlobImageKeysToDelete;
nsTArray<wr::SnapshotImageKey> mSnapshotImageKeysToDelete;
std::unordered_map<uint64_t, RefPtr<SharedSurfacesAnimation>> std::unordered_map<uint64_t, RefPtr<SharedSurfacesAnimation>>
mAsyncAnimations; mAsyncAnimations;

View File

@@ -607,6 +607,24 @@ bool WebRenderBridgeParent::UpdateResources(
wr::ToDeviceIntRect(op.area())); wr::ToDeviceIntRect(op.area()));
break; break;
} }
case OpUpdateResource::TOpAddSnapshotImage: {
const auto& op = cmd.get_OpAddSnapshotImage();
if (!MatchesNamespace(wr::AsImageKey(op.key()))) {
MOZ_ASSERT_UNREACHABLE("Stale snapshot image key (add)!");
break;
}
aUpdates.AddSnapshotImage(op.key());
break;
}
case OpUpdateResource::TOpDeleteSnapshotImage: {
const auto& op = cmd.get_OpDeleteSnapshotImage();
if (!MatchesNamespace(wr::AsImageKey(op.key()))) {
MOZ_ASSERT_UNREACHABLE("Stale snapshot image key (remove)!");
break;
}
aUpdates.DeleteSnapshotImage(op.key());
break;
}
case OpUpdateResource::TOpAddSharedExternalImage: { case OpUpdateResource::TOpAddSharedExternalImage: {
const auto& op = cmd.get_OpAddSharedExternalImage(); const auto& op = cmd.get_OpAddSharedExternalImage();
// gfxCriticalNote is called on error // gfxCriticalNote is called on error

View File

@@ -236,6 +236,10 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent,
return MatchesNamespace(wr::AsImageKey(aBlobKey)); return MatchesNamespace(wr::AsImageKey(aBlobKey));
} }
bool MatchesNamespace(const wr::SnapshotImageKey& aSnapshotKey) const {
return MatchesNamespace(wr::AsImageKey(aSnapshotKey));
}
bool MatchesNamespace(const wr::FontKey& aFontKey) const { bool MatchesNamespace(const wr::FontKey& aFontKey) const {
return aFontKey.mNamespace == mIdNamespace; return aFontKey.mNamespace == mIdNamespace;
} }

View File

@@ -144,6 +144,12 @@ inline auto TiedFields<mozilla::wr::BlobImageKey>(
return std::tie(a._0); return std::tie(a._0);
} }
template <>
inline auto TiedFields<mozilla::wr::SnapshotImageKey>(
mozilla::wr::SnapshotImageKey& a) {
return std::tie(a._0);
}
template <> template <>
inline auto TiedFields<mozilla::wr::FontKey>(mozilla::wr::FontKey& a) { inline auto TiedFields<mozilla::wr::FontKey>(mozilla::wr::FontKey& a) {
return std::tie(a.mNamespace, a.mHandle); return std::tie(a.mNamespace, a.mHandle);
@@ -340,6 +346,10 @@ template <>
struct ParamTraits<mozilla::wr::BlobImageKey> struct ParamTraits<mozilla::wr::BlobImageKey>
: public ParamTraits_TiedFields<mozilla::wr::BlobImageKey> {}; : public ParamTraits_TiedFields<mozilla::wr::BlobImageKey> {};
template <>
struct ParamTraits<mozilla::wr::SnapshotImageKey>
: public ParamTraits_TiedFields<mozilla::wr::SnapshotImageKey> {};
template <> template <>
struct ParamTraits<mozilla::wr::FontKey> struct ParamTraits<mozilla::wr::FontKey>
: public ParamTraits_TiedFields<mozilla::wr::FontKey> {}; : public ParamTraits_TiedFields<mozilla::wr::FontKey> {};

View File

@@ -113,9 +113,10 @@ template struct mozilla::wr::Box2D<int, mozilla::wr::LayoutPixel>;
namespace mozilla { namespace mozilla {
namespace wr { namespace wr {
// Cast a blob image key into a regular image for use in // Cast a blob image key into a regular image for use in a display item.
// a display item.
inline ImageKey AsImageKey(BlobImageKey aKey) { return aKey._0; } inline ImageKey AsImageKey(BlobImageKey aKey) { return aKey._0; }
// Cast a snapshot image key into a regular image for use in a display item.
inline ImageKey AsImageKey(SnapshotImageKey aKey) { return aKey._0; }
} // namespace wr } // namespace wr
} // namespace mozilla } // namespace mozilla

View File

@@ -221,7 +221,7 @@ nsIFrame* NS_NewXULImageFrame(PresShell*, ComputedStyle*);
nsIFrame* NS_NewImageFrameForContentProperty(PresShell*, ComputedStyle*); nsIFrame* NS_NewImageFrameForContentProperty(PresShell*, ComputedStyle*);
nsIFrame* NS_NewImageFrameForGeneratedContentIndex(PresShell*, ComputedStyle*); nsIFrame* NS_NewImageFrameForGeneratedContentIndex(PresShell*, ComputedStyle*);
nsIFrame* NS_NewImageFrameForListStyleImage(PresShell*, ComputedStyle*); nsIFrame* NS_NewImageFrameForListStyleImage(PresShell*, ComputedStyle*);
nsIFrame* NS_NewImageFrameForViewTransitionOld(PresShell*, ComputedStyle*); nsIFrame* NS_NewImageFrameForViewTransition(PresShell*, ComputedStyle*);
// Returns true if aFrame is an anonymous flex/grid item. // Returns true if aFrame is an anonymous flex/grid item.
static inline bool IsAnonymousItem(const nsIFrame* aFrame) { static inline bool IsAnonymousItem(const nsIFrame* aFrame) {
@@ -3493,10 +3493,11 @@ nsCSSFrameConstructor::FindHTMLData(const Element& aElement,
return &sComboboxLabelData; return &sComboboxLabelData;
} }
} }
if (aElement.GetPseudoElementType() == PseudoStyleType::viewTransitionOld) { if (aStyle.GetPseudoType() == PseudoStyleType::viewTransitionOld ||
static constexpr FrameConstructionData sViewTransitionOldData( aStyle.GetPseudoType() == PseudoStyleType::viewTransitionNew) {
NS_NewImageFrameForViewTransitionOld); static constexpr FrameConstructionData sViewTransitionData(
return &sViewTransitionOldData; NS_NewImageFrameForViewTransition);
return &sViewTransitionData;
} }
} }

View File

@@ -20,6 +20,7 @@
#include "mozilla/DisplayPortUtils.h" #include "mozilla/DisplayPortUtils.h"
#include "mozilla/EventForwards.h" #include "mozilla/EventForwards.h"
#include "mozilla/FocusModel.h" #include "mozilla/FocusModel.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/dom/CSSAnimation.h" #include "mozilla/dom/CSSAnimation.h"
#include "mozilla/dom/CSSTransition.h" #include "mozilla/dom/CSSTransition.h"
#include "mozilla/dom/ContentVisibilityAutoStateChangeEvent.h" #include "mozilla/dom/ContentVisibilityAutoStateChangeEvent.h"
@@ -3366,16 +3367,11 @@ void nsIFrame::BuildDisplayListForStackingContext(
// outside to inside. // outside to inside.
enum class ContainerItemType : uint8_t { enum class ContainerItemType : uint8_t {
None = 0, None = 0,
OwnLayerIfNeeded,
BlendMode,
FixedPosition, FixedPosition,
OwnLayerForTransformWithRoundedClip, OwnLayerForTransformWithRoundedClip,
Perspective, Perspective,
Transform, Transform,
SeparatorTransforms,
Opacity,
Filter, Filter,
BlendContainer
}; };
nsDisplayListBuilder::AutoContainerASRTracker contASRTracker(aBuilder); nsDisplayListBuilder::AutoContainerASRTracker contASRTracker(aBuilder);
@@ -3579,6 +3575,18 @@ void nsIFrame::BuildDisplayListForStackingContext(
createdContainer = true; createdContainer = true;
} }
// FIXME: Ensure this is the right place to do this.
if (HasAnyStateBits(NS_FRAME_CAPTURED_IN_VIEW_TRANSITION) &&
StaticPrefs::dom_viewTransitions_live_capture()) {
resultList.AppendNewToTopWithIndex<nsDisplayOwnLayer>(
aBuilder, this,
/* aIndex = */ nsDisplayOwnLayer::OwnLayerForViewTransitionCapture,
&resultList, containerItemASR, nsDisplayOwnLayerFlags::None,
ScrollbarData{},
/* aForceActive = */ false, false);
createdContainer = true;
}
// If there are any SVG effects, wrap the list up in an SVG effects item // If there are any SVG effects, wrap the list up in an SVG effects item
// (which also handles CSS group opacity). Note that we create an SVG effects // (which also handles CSS group opacity). Note that we create an SVG effects
// item even if resultList is empty, since a filter can produce graphical // item even if resultList is empty, since a filter can produce graphical

View File

@@ -107,6 +107,8 @@ using namespace mozilla::layers;
using mozilla::layout::TextDrawTarget; using mozilla::layout::TextDrawTarget;
static constexpr wr::ImageKey kNoKey{{0}, 0};
class nsDisplayGradient final : public nsPaintedDisplayItem { class nsDisplayGradient final : public nsPaintedDisplayItem {
public: public:
nsDisplayGradient(nsDisplayListBuilder* aBuilder, nsImageFrame* aFrame) nsDisplayGradient(nsDisplayListBuilder* aBuilder, nsImageFrame* aFrame)
@@ -399,10 +401,10 @@ nsIFrame* NS_NewImageFrameForListStyleImage(PresShell* aPresShell,
nsImageFrame::Kind::ListStyleImage); nsImageFrame::Kind::ListStyleImage);
} }
nsIFrame* NS_NewImageFrameForViewTransitionOld(PresShell* aPresShell, nsIFrame* NS_NewImageFrameForViewTransition(PresShell* aPresShell,
ComputedStyle* aStyle) { ComputedStyle* aStyle) {
return new (aPresShell) nsImageFrame(aStyle, aPresShell->GetPresContext(), return new (aPresShell) nsImageFrame(aStyle, aPresShell->GetPresContext(),
nsImageFrame::Kind::ViewTransitionOld); nsImageFrame::Kind::ViewTransition);
} }
bool nsImageFrame::ShouldShowBrokenImageIcon() const { bool nsImageFrame::ShouldShowBrokenImageIcon() const {
@@ -471,7 +473,7 @@ a11y::AccType nsImageFrame::AccessibleType() {
return a11y::eNoType; return a11y::eNoType;
} }
if (mKind == Kind::ViewTransitionOld) { if (mKind == Kind::ViewTransition) {
// View transitions don't show up in the a11y tree. // View transitions don't show up in the a11y tree.
return a11y::eNoType; return a11y::eNoType;
} }
@@ -538,13 +540,6 @@ void nsImageFrame::Destroy(DestroyContext& aContext) {
BrokenImageIcon::RemoveObserver(this); BrokenImageIcon::RemoveObserver(this);
} }
if (mViewTransitionData.HasKey()) {
MOZ_ASSERT(mViewTransitionData.mManager);
mViewTransitionData.mManager->AddImageKeyForDiscard(
mViewTransitionData.mImageKey);
mViewTransitionData = {};
}
nsAtomicContainerFrame::Destroy(aContext); nsAtomicContainerFrame::Destroy(aContext);
} }
@@ -630,7 +625,7 @@ static bool SizeIsAvailable(imgIRequest* aRequest) {
const StyleImage* nsImageFrame::GetImageFromStyle() const { const StyleImage* nsImageFrame::GetImageFromStyle() const {
switch (mKind) { switch (mKind) {
case Kind::ViewTransitionOld: case Kind::ViewTransition:
break; break;
case Kind::ImageLoadingContent: case Kind::ImageLoadingContent:
break; break;
@@ -750,7 +745,7 @@ void nsImageFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
} }
} else if (mKind == Kind::XULImage) { } else if (mKind == Kind::XULImage) {
UpdateXULImage(); UpdateXULImage();
} else if (mKind == Kind::ViewTransitionOld) { } else if (mKind == Kind::ViewTransition) {
// View transitions have a surface directly. // View transitions have a surface directly.
} else { } else {
const StyleImage* image = GetImageFromStyle(); const StyleImage* image = GetImageFromStyle();
@@ -881,13 +876,10 @@ IntrinsicSize nsImageFrame::ComputeIntrinsicSize(
return FinishIntrinsicSize(containAxes, intrinsicSize); return FinishIntrinsicSize(containAxes, intrinsicSize);
} }
if (auto* surf = GetViewTransitionSurface()) { if (auto size = GetViewTransitionSnapshotSize()) {
IntrinsicSize intrinsicSize; IntrinsicSize intrinsicSize;
auto devPx = LayoutDeviceIntSize::FromUnknownSize(surf->GetSize()); intrinsicSize.width.emplace(size->width);
auto size = LayoutDeviceIntSize::ToAppUnits( intrinsicSize.height.emplace(size->height);
devPx, PresContext()->AppUnitsPerDevPixel());
intrinsicSize.width.emplace(size.width);
intrinsicSize.height.emplace(size.height);
return FinishIntrinsicSize(containAxes, intrinsicSize); return FinishIntrinsicSize(containAxes, intrinsicSize);
} }
@@ -950,18 +942,47 @@ bool nsImageFrame::UpdateIntrinsicSize() {
return mIntrinsicSize != oldIntrinsicSize; return mIntrinsicSize != oldIntrinsicSize;
} }
gfx::DataSourceSurface* nsImageFrame::GetViewTransitionSurface() const { nsAtom* nsImageFrame::GetViewTransitionName() const {
if (mKind != Kind::ViewTransitionOld) { if (mKind != Kind::ViewTransition) {
return nullptr;
}
auto* vt = PresContext()->Document()->GetActiveViewTransition();
if (NS_WARN_IF(!vt)) {
return nullptr; return nullptr;
} }
MOZ_ASSERT(GetContent()->AsElement()->HasName()); MOZ_ASSERT(GetContent()->AsElement()->HasName());
nsAtom* name = return GetContent()
GetContent()->AsElement()->GetParsedAttr(nsGkAtoms::name)->GetAtomValue(); ->AsElement()
return vt->GetOldSurface(name); ->GetParsedAttr(nsGkAtoms::name)
->GetAtomValue();
}
Maybe<nsSize> nsImageFrame::GetViewTransitionSnapshotSize() const {
auto* name = GetViewTransitionName();
if (!name) {
return {};
}
auto* vt = PresContext()->Document()->GetActiveViewTransition();
if (NS_WARN_IF(!vt)) {
return {};
}
return Style()->GetPseudoType() == PseudoStyleType::viewTransitionOld
? vt->GetOldSize(name)
: vt->GetNewSize(name);
}
wr::ImageKey nsImageFrame::GetViewTransitionImageKey(
layers::RenderRootStateManager* aManager,
wr::IpcResourceUpdateQueue& aResources) const {
auto* name = GetViewTransitionName();
if (!name) {
return kNoKey;
}
auto* vt = PresContext()->Document()->GetActiveViewTransition();
if (NS_WARN_IF(!vt)) {
return kNoKey;
}
const auto* key =
Style()->GetPseudoType() == PseudoStyleType::viewTransitionOld
? vt->GetOldImageKey(name, aManager, aResources)
: vt->GetNewImageKey(name);
return key ? *key : kNoKey;
} }
AspectRatio nsImageFrame::ComputeIntrinsicRatioForImage( AspectRatio nsImageFrame::ComputeIntrinsicRatioForImage(
@@ -976,8 +997,8 @@ AspectRatio nsImageFrame::ComputeIntrinsicRatioForImage(
} }
} }
if (auto* surf = GetViewTransitionSurface()) { if (auto size = GetViewTransitionSnapshotSize()) {
return AspectRatio::FromSize(surf->GetSize()); return AspectRatio::FromSize(*size);
} }
if (ShouldUseMappedAspectRatio()) { if (ShouldUseMappedAspectRatio()) {
@@ -2344,35 +2365,17 @@ void nsDisplayImage::MaybeCreateWebRenderCommandsForViewTransition(
nsDisplayListBuilder* aDisplayListBuilder) { nsDisplayListBuilder* aDisplayListBuilder) {
auto* frame = Frame(); auto* frame = Frame();
MOZ_ASSERT(!frame->mImage); MOZ_ASSERT(!frame->mImage);
auto* surf = frame->GetViewTransitionSurface(); auto key = frame->GetViewTransitionImageKey(aManager, aResources);
if (NS_WARN_IF(!surf)) { if (NS_WARN_IF(key == kNoKey)) {
return; return;
} }
if (!frame->mViewTransitionData.HasKey()) {
DataSourceSurface::ScopedMap map(surf, DataSourceSurface::READ);
if (NS_WARN_IF(!map.IsMapped())) {
return;
}
auto key = aManager->WrBridge()->GetNextImageKey();
auto size = surf->GetSize();
auto format = surf->GetFormat();
wr::ImageDescriptor desc(size, format);
Range<uint8_t> bytes(map.GetData(), map.GetStride() * size.height);
if (NS_WARN_IF(!aResources.AddImage(key, desc, bytes))) {
return;
}
// TODO: Discard this image
frame->mViewTransitionData.mImageKey = key;
frame->mViewTransitionData.mManager = aManager;
}
const nsRect destAppUnits = GetDestRect(); const nsRect destAppUnits = GetDestRect();
const int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel(); const int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel();
const auto destRect = const auto destRect =
wr::ToLayoutRect(LayoutDeviceRect::FromAppUnits(destAppUnits, factor)); wr::ToLayoutRect(LayoutDeviceRect::FromAppUnits(destAppUnits, factor));
auto rendering = wr::ToImageRendering(frame->UsedImageRendering()); auto rendering = wr::ToImageRendering(frame->UsedImageRendering());
aBuilder.PushImage(destRect, destRect, !BackfaceIsHidden(), aBuilder.PushImage(destRect, destRect, !BackfaceIsHidden(),
/* aForceAntiAliasing = */ false, rendering, /* aForceAntiAliasing = */ false, rendering, key);
frame->mViewTransitionData.mImageKey);
} }
bool nsDisplayImage::CreateWebRenderCommands( bool nsDisplayImage::CreateWebRenderCommands(
@@ -2576,7 +2579,7 @@ void nsImageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
aBuilder, this, clipFlags); aBuilder, this, clipFlags);
if (!mComputedSize.IsEmpty()) { if (!mComputedSize.IsEmpty()) {
const bool isViewTransition = mKind == Kind::ViewTransitionOld; const bool isViewTransition = mKind == Kind::ViewTransition;
const bool imageOK = mKind != Kind::ImageLoadingContent || const bool imageOK = mKind != Kind::ImageLoadingContent ||
ImageOk(mContent->AsElement()->State()); ImageOk(mContent->AsElement()->State());

View File

@@ -196,8 +196,9 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback {
ContentPropertyAtIndex, ContentPropertyAtIndex,
// For a list-style-image ::marker. // For a list-style-image ::marker.
ListStyleImage, ListStyleImage,
// For a ::view-transition-old pseudo-element // For a ::view-transition-old or ::view-transition-new pseudo-element.
ViewTransitionOld, // Which one of the two is determined by the PseudoStyleType applying to us.
ViewTransition,
}; };
// Creates a suitable continuing frame for this frame. // Creates a suitable continuing frame for this frame.
@@ -216,8 +217,8 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback {
ComputedStyle*); ComputedStyle*);
friend nsIFrame* NS_NewImageFrameForListStyleImage(mozilla::PresShell*, friend nsIFrame* NS_NewImageFrameForListStyleImage(mozilla::PresShell*,
ComputedStyle*); ComputedStyle*);
friend nsIFrame* NS_NewImageFrameForViewTransitionOld(mozilla::PresShell*, friend nsIFrame* NS_NewImageFrameForViewTransition(mozilla::PresShell*,
ComputedStyle*); ComputedStyle*);
nsImageFrame(ComputedStyle* aStyle, nsPresContext* aPresContext, Kind aKind) nsImageFrame(ComputedStyle* aStyle, nsPresContext* aPresContext, Kind aKind)
: nsImageFrame(aStyle, aPresContext, kClassID, aKind) {} : nsImageFrame(aStyle, aPresContext, kClassID, aKind) {}
@@ -306,7 +307,11 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback {
// and height="". // and height="".
bool ShouldUseMappedAspectRatio() const; bool ShouldUseMappedAspectRatio() const;
mozilla::gfx::DataSourceSurface* GetViewTransitionSurface() const; nsAtom* GetViewTransitionName() const;
Maybe<nsSize> GetViewTransitionSnapshotSize() const;
mozilla::wr::ImageKey GetViewTransitionImageKey(
mozilla::layers::RenderRootStateManager*,
mozilla::wr::IpcResourceUpdateQueue&) const;
/** /**
* Notification that aRequest will now be the current request. * Notification that aRequest will now be the current request.
@@ -398,15 +403,6 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback {
nsCOMPtr<imgIContainer> mImage; nsCOMPtr<imgIContainer> mImage;
nsCOMPtr<imgIContainer> mPrevImage; nsCOMPtr<imgIContainer> mPrevImage;
struct ViewTransitionData {
// The image key of our snapshot.
mozilla::wr::ImageKey mImageKey{{0}, 0};
// The owner of the key.
RefPtr<mozilla::layers::RenderRootStateManager> mManager;
bool HasKey() const { return mImageKey != mozilla::wr::ImageKey{{0}, 0}; }
} mViewTransitionData;
// The content-box size as if we are not fragmented, cached in the most recent // The content-box size as if we are not fragmented, cached in the most recent
// reflow. // reflow.
nsSize mComputedSize; nsSize mComputedSize;

View File

@@ -24,6 +24,7 @@
#include "mozilla/dom/HTMLCanvasElement.h" #include "mozilla/dom/HTMLCanvasElement.h"
#include "mozilla/dom/RemoteBrowser.h" #include "mozilla/dom/RemoteBrowser.h"
#include "mozilla/dom/Selection.h" #include "mozilla/dom/Selection.h"
#include "mozilla/dom/ViewTransition.h"
#include "mozilla/dom/ServiceWorkerRegistrar.h" #include "mozilla/dom/ServiceWorkerRegistrar.h"
#include "mozilla/dom/ServiceWorkerRegistration.h" #include "mozilla/dom/ServiceWorkerRegistration.h"
#include "mozilla/dom/SVGElement.h" #include "mozilla/dom/SVGElement.h"
@@ -5203,10 +5204,11 @@ bool nsDisplayOwnLayer::CreateWebRenderCommands(
const StackingContextHelper& aSc, RenderRootStateManager* aManager, const StackingContextHelper& aSc, RenderRootStateManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder) { nsDisplayListBuilder* aDisplayListBuilder) {
Maybe<wr::WrAnimationProperty> prop; Maybe<wr::WrAnimationProperty> prop;
bool needsProp = aManager->LayerManager()->AsyncPanZoomEnabled() && Maybe<wr::SnapshotInfo> snapshot;
(IsScrollThumbLayer() || IsZoomingLayer() || const bool needsProp = aManager->LayerManager()->AsyncPanZoomEnabled() &&
ShouldGetFixedAnimationId() || (IsScrollThumbLayer() || IsZoomingLayer() ||
(IsRootScrollbarContainer() && HasDynamicToolbar())); ShouldGetFixedAnimationId() ||
(IsRootScrollbarContainer() && HasDynamicToolbar()));
if (needsProp) { if (needsProp) {
// APZ is enabled and this is a scroll thumb or zooming layer, so we need // APZ is enabled and this is a scroll thumb or zooming layer, so we need
@@ -5228,12 +5230,33 @@ bool nsDisplayOwnLayer::CreateWebRenderCommands(
params.animation = prop.ptrOr(nullptr); params.animation = prop.ptrOr(nullptr);
params.clip = params.clip =
wr::WrStackingContextClip::ClipChain(aBuilder.CurrentClipChainId()); wr::WrStackingContextClip::ClipChain(aBuilder.CurrentClipChainId());
if (IsScrollbarContainer() && IsRootScrollbarContainer()) { const bool rootScrollbarContainer = IsRootScrollbarContainer();
if (rootScrollbarContainer) {
params.prim_flags |= wr::PrimitiveFlags::IS_SCROLLBAR_CONTAINER; params.prim_flags |= wr::PrimitiveFlags::IS_SCROLLBAR_CONTAINER;
} }
if (IsZoomingLayer() || if (mFrame->HasAnyStateBits(NS_FRAME_CAPTURED_IN_VIEW_TRANSITION)) {
(ShouldGetFixedAnimationId() || auto key = [&]() -> Maybe<wr::SnapshotImageKey> {
(IsRootScrollbarContainer() && HasDynamicToolbar()))) { auto* vt = mFrame->PresContext()->Document()->GetActiveViewTransition();
if (NS_WARN_IF(!vt)) {
return Nothing();
}
const auto* key =
vt->GetImageKeyForCapturedFrame(mFrame, aManager, aResources);
return key ? Some(wr::SnapshotImageKey{*key}) : Nothing();
}();
if (key) {
float auPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
snapshot.emplace(wr::SnapshotInfo{
.key = *key,
.area = wr::ToLayoutRect(LayoutDeviceRect::FromAppUnits(
mFrame->InkOverflowRectRelativeToSelf(), auPerDevPixel)),
.detached = true,
});
params.snapshot = snapshot.ptr();
}
}
if (IsZoomingLayer() || ShouldGetFixedAnimationId() ||
(rootScrollbarContainer && HasDynamicToolbar())) {
params.is_2d_scale_translation = true; params.is_2d_scale_translation = true;
params.should_snap = true; params.should_snap = true;
} }

View File

@@ -5380,7 +5380,7 @@ class nsDisplayOwnLayer : public nsDisplayWrapList {
public: public:
enum OwnLayerType { enum OwnLayerType {
OwnLayerForTransformWithRoundedClip, OwnLayerForTransformWithRoundedClip,
OwnLayerForStackingContext, OwnLayerForViewTransitionCapture,
OwnLayerForScrollbar, OwnLayerForScrollbar,
OwnLayerForScrollThumb, OwnLayerForScrollThumb,
OwnLayerForSubdoc, OwnLayerForSubdoc,

View File

@@ -4923,6 +4923,12 @@
value: false value: false
mirror: always mirror: always
# Whether view transitions use webrender for live-capture
- name: dom.viewTransitions.live-capture
type: bool
value: false
mirror: always
# Is support for WebVR APIs enabled? # Is support for WebVR APIs enabled?
# Disabled everywhere, but not removed. # Disabled everywhere, but not removed.
- name: dom.vr.enabled - name: dom.vr.enabled