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:
@@ -5,11 +5,17 @@
|
||||
#include "ViewTransition.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/layers/WebRenderBridgeChild.h"
|
||||
#include "mozilla/gfx/DataSurfaceHelpers.h"
|
||||
#include "mozilla/dom/DocumentInlines.h"
|
||||
#include "mozilla/dom/DocumentTimeline.h"
|
||||
#include "mozilla/dom/Promise-inl.h"
|
||||
#include "mozilla/dom/ViewTransitionBinding.h"
|
||||
#include "mozilla/image/WebRenderImageProvider.h"
|
||||
#include "mozilla/webrender/WebRenderAPI.h"
|
||||
#include "mozilla/AnimationEventDispatcher.h"
|
||||
#include "mozilla/EffectSet.h"
|
||||
@@ -18,9 +24,11 @@
|
||||
#include "mozilla/SVGIntegrationUtils.h"
|
||||
#include "mozilla/WritingModes.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "nsFrameState.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsString.h"
|
||||
#include "Units.h"
|
||||
|
||||
namespace mozilla::dom {
|
||||
@@ -84,8 +92,78 @@ static RefPtr<gfx::DataSourceSurface> CaptureFallbackSnapshot(
|
||||
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 {
|
||||
RefPtr<gfx::DataSourceSurface> mImage;
|
||||
OldSnapshotData mSnapshot;
|
||||
// Whether we tried to capture an image. Note we might fail to get a
|
||||
// snapshot, so this might not be the same as !!mImage.
|
||||
bool mTriedImage = false;
|
||||
@@ -101,7 +179,7 @@ struct CapturedElementOldState {
|
||||
|
||||
CapturedElementOldState(nsIFrame* aFrame,
|
||||
const nsSize& aSnapshotContainingBlockSize)
|
||||
: mImage(CaptureFallbackSnapshot(aFrame)),
|
||||
: mSnapshot(aFrame),
|
||||
mTriedImage(true),
|
||||
mSize(aFrame->Style()->IsRootElementStyle()
|
||||
? aSnapshotContainingBlockSize
|
||||
@@ -119,6 +197,8 @@ struct CapturedElementOldState {
|
||||
struct ViewTransition::CapturedElement {
|
||||
CapturedElementOldState mOldState;
|
||||
RefPtr<Element> mNewElement;
|
||||
wr::SnapshotImageKey mNewSnapshotKey{kNoKey};
|
||||
nsSize mNewSnapshotSize;
|
||||
|
||||
CapturedElement() = default;
|
||||
|
||||
@@ -135,6 +215,14 @@ struct ViewTransition::CapturedElement {
|
||||
RefPtr<StyleLockedDeclarationBlock> mOldRule;
|
||||
// The rules for ::view-transition-new(<name>).
|
||||
RefPtr<StyleLockedDeclarationBlock> mNewRule;
|
||||
|
||||
~CapturedElement() {
|
||||
if (wr::AsImageKey(mNewSnapshotKey) != kNoKey) {
|
||||
MOZ_ASSERT(mOldState.mSnapshot.mManager);
|
||||
mOldState.mSnapshot.mManager->AddSnapshotImageKeyForDiscard(
|
||||
mNewSnapshotKey);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static inline void ImplCycleCollectionTraverse(
|
||||
@@ -164,12 +252,75 @@ ViewTransition::ViewTransition(Document& aDoc,
|
||||
|
||||
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);
|
||||
if (NS_WARN_IF(!el)) {
|
||||
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 {
|
||||
@@ -262,7 +413,7 @@ void ViewTransition::CallUpdateCallback(ErrorResult& aRv) {
|
||||
// new state, so we need to flush frames. Do it here so that we deal
|
||||
// with other potential script execution skipping the transition or
|
||||
// what not in a consistent way.
|
||||
aVt->mDocument->FlushPendingNotifications(FlushType::Frames);
|
||||
aVt->mDocument->FlushPendingNotifications(FlushType::Layout);
|
||||
if (aVt->mPhase == Phase::Done) {
|
||||
// "Skip a transition" step 8. We need to resolve "finished" after
|
||||
// update-callback-done.
|
||||
@@ -604,15 +755,15 @@ bool ViewTransition::UpdatePseudoElementStyles(bool aNeedsInvalidation) {
|
||||
auto size = CSSPixel::FromAppUnits(newRect);
|
||||
// NOTE(emilio): Intentionally not short-circuiting. Int cast is needed to
|
||||
// silence warning.
|
||||
bool changed = int(SetProp(rule, mDocument, eCSSProperty_width, size.width,
|
||||
eCSSUnit_Pixel)) |
|
||||
SetProp(rule, mDocument, eCSSProperty_height, size.height,
|
||||
eCSSUnit_Pixel) |
|
||||
bool groupStyleChanged = int(SetProp(rule, mDocument, eCSSProperty_width,
|
||||
size.width, eCSSUnit_Pixel)) |
|
||||
SetProp(rule, mDocument, eCSSProperty_height,
|
||||
size.height, eCSSUnit_Pixel) |
|
||||
SetProp(rule, mDocument, eCSSProperty_transform,
|
||||
EffectiveTransform(frame));
|
||||
// TODO: writing-mode, direction, text-orientation, mix-blend-mode,
|
||||
// backdrop-filter, color-scheme.
|
||||
if (changed && aNeedsInvalidation) {
|
||||
if (groupStyleChanged && aNeedsInvalidation) {
|
||||
auto* pseudo = FindPseudo(PseudoStyleRequest(
|
||||
PseudoStyleType::viewTransitionGroup, transitionName));
|
||||
MOZ_ASSERT(pseudo);
|
||||
@@ -621,7 +772,16 @@ bool ViewTransition::UpdatePseudoElementStyles(bool aNeedsInvalidation) {
|
||||
nsLayoutUtils::PostRestyleEvent(pseudo, RestyleHint::RECASCADE_SELF,
|
||||
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;
|
||||
}
|
||||
@@ -931,6 +1091,8 @@ Maybe<SkipTransitionReason> ViewTransition::CaptureNewState() {
|
||||
auto& capturedElement = mNamedElements.LookupOrInsertWith(
|
||||
name, [&] { return MakeUnique<CapturedElement>(); });
|
||||
capturedElement->mNewElement = aFrame->GetContent()->AsElement();
|
||||
capturedElement->mNewSnapshotSize =
|
||||
aFrame->InkOverflowRectRelativeToSelf().Size();
|
||||
aFrame->AddStateBits(NS_FRAME_CAPTURED_IN_VIEW_TRANSITION);
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#ifndef mozilla_dom_ViewTransition_h
|
||||
#define mozilla_dom_ViewTransition_h
|
||||
|
||||
#include "mozilla/layers/IpcResourceUpdateQueue.h"
|
||||
#include "nsRect.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsAtomHashKeys.h"
|
||||
@@ -25,6 +26,15 @@ namespace gfx {
|
||||
class DataSourceSurface;
|
||||
}
|
||||
|
||||
namespace layers {
|
||||
class RenderRootStateManager;
|
||||
}
|
||||
|
||||
namespace wr {
|
||||
struct ImageKey;
|
||||
class IpcResourceUpdateQueue;
|
||||
} // namespace wr
|
||||
|
||||
namespace dom {
|
||||
|
||||
class Document;
|
||||
@@ -69,7 +79,15 @@ class ViewTransition final : public nsISupports, public nsWrapperCache {
|
||||
void PerformPendingOperations();
|
||||
|
||||
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;
|
||||
|
||||
|
||||
@@ -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::ImageKey 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::PipelineId from "mozilla/webrender/WebRenderTypes.h";
|
||||
using mozilla::LayoutDeviceRect from "Units.h";
|
||||
@@ -114,6 +115,10 @@ struct OpAddBlobImage {
|
||||
BlobImageKey key;
|
||||
};
|
||||
|
||||
struct OpAddSnapshotImage {
|
||||
SnapshotImageKey key;
|
||||
};
|
||||
|
||||
struct OpUpdateImage {
|
||||
ImageDescriptor descriptor;
|
||||
OffsetRange bytes;
|
||||
@@ -143,6 +148,10 @@ struct OpDeleteImage {
|
||||
ImageKey key;
|
||||
};
|
||||
|
||||
struct OpDeleteSnapshotImage {
|
||||
SnapshotImageKey key;
|
||||
};
|
||||
|
||||
struct OpDeleteBlobImage {
|
||||
BlobImageKey key;
|
||||
};
|
||||
@@ -179,11 +188,13 @@ struct OpDeleteFontInstance {
|
||||
union OpUpdateResource {
|
||||
OpAddImage;
|
||||
OpAddBlobImage;
|
||||
OpAddSnapshotImage;
|
||||
OpUpdateImage;
|
||||
OpUpdateBlobImage;
|
||||
OpSetBlobImageVisibleArea;
|
||||
OpDeleteImage;
|
||||
OpDeleteBlobImage;
|
||||
OpDeleteSnapshotImage;
|
||||
OpAddRawFont;
|
||||
OpAddFontDescriptor;
|
||||
OpDeleteFont;
|
||||
|
||||
@@ -322,6 +322,10 @@ bool IpcResourceUpdateQueue::AddImage(ImageKey key,
|
||||
return true;
|
||||
}
|
||||
|
||||
void IpcResourceUpdateQueue::AddSnapshotImage(SnapshotImageKey aKey) {
|
||||
mUpdates.AppendElement(layers::OpAddSnapshotImage(aKey));
|
||||
}
|
||||
|
||||
bool IpcResourceUpdateQueue::AddBlobImage(BlobImageKey key,
|
||||
const ImageDescriptor& aDescriptor,
|
||||
Range<uint8_t> aBytes,
|
||||
@@ -393,6 +397,10 @@ void IpcResourceUpdateQueue::DeleteImage(ImageKey aKey) {
|
||||
mUpdates.AppendElement(layers::OpDeleteImage(aKey));
|
||||
}
|
||||
|
||||
void IpcResourceUpdateQueue::DeleteSnapshotImage(SnapshotImageKey aKey) {
|
||||
mUpdates.AppendElement(layers::OpDeleteSnapshotImage(aKey));
|
||||
}
|
||||
|
||||
void IpcResourceUpdateQueue::DeleteBlobImage(BlobImageKey aKey) {
|
||||
mUpdates.AppendElement(layers::OpDeleteBlobImage(aKey));
|
||||
}
|
||||
|
||||
@@ -132,6 +132,8 @@ class IpcResourceUpdateQueue {
|
||||
bool AddBlobImage(wr::BlobImageKey aKey, const ImageDescriptor& aDescriptor,
|
||||
Range<uint8_t> aBytes, ImageIntRect aVisibleRect);
|
||||
|
||||
void AddSnapshotImage(wr::SnapshotImageKey aKey);
|
||||
|
||||
void AddSharedExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey);
|
||||
|
||||
void PushExternalImageForTexture(wr::ExternalImageId aExtId,
|
||||
@@ -156,6 +158,8 @@ class IpcResourceUpdateQueue {
|
||||
|
||||
void DeleteBlobImage(wr::BlobImageKey aKey);
|
||||
|
||||
void DeleteSnapshotImage(wr::SnapshotImageKey aKey);
|
||||
|
||||
bool AddRawFont(wr::FontKey aKey, Range<uint8_t> aBytes, uint32_t aIndex);
|
||||
|
||||
bool AddFontDescriptor(wr::FontKey aKey, Range<uint8_t> aBytes,
|
||||
|
||||
@@ -86,6 +86,11 @@ void RenderRootStateManager::AddBlobImageKeyForDiscard(wr::BlobImageKey key) {
|
||||
mBlobImageKeysToDelete.AppendElement(key);
|
||||
}
|
||||
|
||||
void RenderRootStateManager::AddSnapshotImageKeyForDiscard(
|
||||
wr::SnapshotImageKey key) {
|
||||
mSnapshotImageKeysToDelete.AppendElement(key);
|
||||
}
|
||||
|
||||
void RenderRootStateManager::DiscardImagesInTransaction(
|
||||
wr::IpcResourceUpdateQueue& aResources) {
|
||||
for (const auto& key : mImageKeysToDelete) {
|
||||
@@ -94,8 +99,12 @@ void RenderRootStateManager::DiscardImagesInTransaction(
|
||||
for (const auto& key : mBlobImageKeysToDelete) {
|
||||
aResources.DeleteBlobImage(key);
|
||||
}
|
||||
for (const auto& key : mSnapshotImageKeysToDelete) {
|
||||
aResources.DeleteSnapshotImage(key);
|
||||
}
|
||||
mImageKeysToDelete.Clear();
|
||||
mBlobImageKeysToDelete.Clear();
|
||||
mSnapshotImageKeysToDelete.Clear();
|
||||
}
|
||||
|
||||
void RenderRootStateManager::DiscardLocalImages() {
|
||||
@@ -104,6 +113,7 @@ void RenderRootStateManager::DiscardLocalImages() {
|
||||
// image keys but didn't tell the parent about them yet.
|
||||
mImageKeysToDelete.Clear();
|
||||
mBlobImageKeysToDelete.Clear();
|
||||
mSnapshotImageKeysToDelete.Clear();
|
||||
}
|
||||
|
||||
void RenderRootStateManager::ClearCachedResources() {
|
||||
|
||||
@@ -35,8 +35,9 @@ class RenderRootStateManager {
|
||||
WebRenderUserDataRefTable* GetWebRenderUserDataTable();
|
||||
WebRenderLayerManager* LayerManager() { return mLayerManager; }
|
||||
|
||||
void AddImageKeyForDiscard(wr::ImageKey key);
|
||||
void AddBlobImageKeyForDiscard(wr::BlobImageKey key);
|
||||
void AddImageKeyForDiscard(wr::ImageKey);
|
||||
void AddBlobImageKeyForDiscard(wr::BlobImageKey);
|
||||
void AddSnapshotImageKeyForDiscard(wr::SnapshotImageKey);
|
||||
void DiscardImagesInTransaction(wr::IpcResourceUpdateQueue& aResources);
|
||||
void DiscardLocalImages();
|
||||
|
||||
@@ -76,6 +77,7 @@ class RenderRootStateManager {
|
||||
Maybe<wr::IpcResourceUpdateQueue> mAsyncResourceUpdates;
|
||||
nsTArray<wr::ImageKey> mImageKeysToDelete;
|
||||
nsTArray<wr::BlobImageKey> mBlobImageKeysToDelete;
|
||||
nsTArray<wr::SnapshotImageKey> mSnapshotImageKeysToDelete;
|
||||
std::unordered_map<uint64_t, RefPtr<SharedSurfacesAnimation>>
|
||||
mAsyncAnimations;
|
||||
|
||||
|
||||
@@ -607,6 +607,24 @@ bool WebRenderBridgeParent::UpdateResources(
|
||||
wr::ToDeviceIntRect(op.area()));
|
||||
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: {
|
||||
const auto& op = cmd.get_OpAddSharedExternalImage();
|
||||
// gfxCriticalNote is called on error
|
||||
|
||||
@@ -236,6 +236,10 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent,
|
||||
return MatchesNamespace(wr::AsImageKey(aBlobKey));
|
||||
}
|
||||
|
||||
bool MatchesNamespace(const wr::SnapshotImageKey& aSnapshotKey) const {
|
||||
return MatchesNamespace(wr::AsImageKey(aSnapshotKey));
|
||||
}
|
||||
|
||||
bool MatchesNamespace(const wr::FontKey& aFontKey) const {
|
||||
return aFontKey.mNamespace == mIdNamespace;
|
||||
}
|
||||
|
||||
@@ -144,6 +144,12 @@ inline auto TiedFields<mozilla::wr::BlobImageKey>(
|
||||
return std::tie(a._0);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline auto TiedFields<mozilla::wr::SnapshotImageKey>(
|
||||
mozilla::wr::SnapshotImageKey& a) {
|
||||
return std::tie(a._0);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline auto TiedFields<mozilla::wr::FontKey>(mozilla::wr::FontKey& a) {
|
||||
return std::tie(a.mNamespace, a.mHandle);
|
||||
@@ -340,6 +346,10 @@ template <>
|
||||
struct ParamTraits<mozilla::wr::BlobImageKey>
|
||||
: public ParamTraits_TiedFields<mozilla::wr::BlobImageKey> {};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::wr::SnapshotImageKey>
|
||||
: public ParamTraits_TiedFields<mozilla::wr::SnapshotImageKey> {};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::wr::FontKey>
|
||||
: public ParamTraits_TiedFields<mozilla::wr::FontKey> {};
|
||||
|
||||
@@ -113,9 +113,10 @@ template struct mozilla::wr::Box2D<int, mozilla::wr::LayoutPixel>;
|
||||
namespace mozilla {
|
||||
namespace wr {
|
||||
|
||||
// Cast a blob image key into a regular image for use in
|
||||
// a display item.
|
||||
// Cast a blob image key into a regular image for use in a display item.
|
||||
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 mozilla
|
||||
|
||||
@@ -221,7 +221,7 @@ nsIFrame* NS_NewXULImageFrame(PresShell*, ComputedStyle*);
|
||||
nsIFrame* NS_NewImageFrameForContentProperty(PresShell*, ComputedStyle*);
|
||||
nsIFrame* NS_NewImageFrameForGeneratedContentIndex(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.
|
||||
static inline bool IsAnonymousItem(const nsIFrame* aFrame) {
|
||||
@@ -3493,10 +3493,11 @@ nsCSSFrameConstructor::FindHTMLData(const Element& aElement,
|
||||
return &sComboboxLabelData;
|
||||
}
|
||||
}
|
||||
if (aElement.GetPseudoElementType() == PseudoStyleType::viewTransitionOld) {
|
||||
static constexpr FrameConstructionData sViewTransitionOldData(
|
||||
NS_NewImageFrameForViewTransitionOld);
|
||||
return &sViewTransitionOldData;
|
||||
if (aStyle.GetPseudoType() == PseudoStyleType::viewTransitionOld ||
|
||||
aStyle.GetPseudoType() == PseudoStyleType::viewTransitionNew) {
|
||||
static constexpr FrameConstructionData sViewTransitionData(
|
||||
NS_NewImageFrameForViewTransition);
|
||||
return &sViewTransitionData;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "mozilla/DisplayPortUtils.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "mozilla/FocusModel.h"
|
||||
#include "mozilla/StaticPrefs_dom.h"
|
||||
#include "mozilla/dom/CSSAnimation.h"
|
||||
#include "mozilla/dom/CSSTransition.h"
|
||||
#include "mozilla/dom/ContentVisibilityAutoStateChangeEvent.h"
|
||||
@@ -3366,16 +3367,11 @@ void nsIFrame::BuildDisplayListForStackingContext(
|
||||
// outside to inside.
|
||||
enum class ContainerItemType : uint8_t {
|
||||
None = 0,
|
||||
OwnLayerIfNeeded,
|
||||
BlendMode,
|
||||
FixedPosition,
|
||||
OwnLayerForTransformWithRoundedClip,
|
||||
Perspective,
|
||||
Transform,
|
||||
SeparatorTransforms,
|
||||
Opacity,
|
||||
Filter,
|
||||
BlendContainer
|
||||
};
|
||||
|
||||
nsDisplayListBuilder::AutoContainerASRTracker contASRTracker(aBuilder);
|
||||
@@ -3579,6 +3575,18 @@ void nsIFrame::BuildDisplayListForStackingContext(
|
||||
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
|
||||
// (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
|
||||
|
||||
@@ -107,6 +107,8 @@ using namespace mozilla::layers;
|
||||
|
||||
using mozilla::layout::TextDrawTarget;
|
||||
|
||||
static constexpr wr::ImageKey kNoKey{{0}, 0};
|
||||
|
||||
class nsDisplayGradient final : public nsPaintedDisplayItem {
|
||||
public:
|
||||
nsDisplayGradient(nsDisplayListBuilder* aBuilder, nsImageFrame* aFrame)
|
||||
@@ -399,10 +401,10 @@ nsIFrame* NS_NewImageFrameForListStyleImage(PresShell* aPresShell,
|
||||
nsImageFrame::Kind::ListStyleImage);
|
||||
}
|
||||
|
||||
nsIFrame* NS_NewImageFrameForViewTransitionOld(PresShell* aPresShell,
|
||||
nsIFrame* NS_NewImageFrameForViewTransition(PresShell* aPresShell,
|
||||
ComputedStyle* aStyle) {
|
||||
return new (aPresShell) nsImageFrame(aStyle, aPresShell->GetPresContext(),
|
||||
nsImageFrame::Kind::ViewTransitionOld);
|
||||
nsImageFrame::Kind::ViewTransition);
|
||||
}
|
||||
|
||||
bool nsImageFrame::ShouldShowBrokenImageIcon() const {
|
||||
@@ -471,7 +473,7 @@ a11y::AccType nsImageFrame::AccessibleType() {
|
||||
return a11y::eNoType;
|
||||
}
|
||||
|
||||
if (mKind == Kind::ViewTransitionOld) {
|
||||
if (mKind == Kind::ViewTransition) {
|
||||
// View transitions don't show up in the a11y tree.
|
||||
return a11y::eNoType;
|
||||
}
|
||||
@@ -538,13 +540,6 @@ void nsImageFrame::Destroy(DestroyContext& aContext) {
|
||||
BrokenImageIcon::RemoveObserver(this);
|
||||
}
|
||||
|
||||
if (mViewTransitionData.HasKey()) {
|
||||
MOZ_ASSERT(mViewTransitionData.mManager);
|
||||
mViewTransitionData.mManager->AddImageKeyForDiscard(
|
||||
mViewTransitionData.mImageKey);
|
||||
mViewTransitionData = {};
|
||||
}
|
||||
|
||||
nsAtomicContainerFrame::Destroy(aContext);
|
||||
}
|
||||
|
||||
@@ -630,7 +625,7 @@ static bool SizeIsAvailable(imgIRequest* aRequest) {
|
||||
|
||||
const StyleImage* nsImageFrame::GetImageFromStyle() const {
|
||||
switch (mKind) {
|
||||
case Kind::ViewTransitionOld:
|
||||
case Kind::ViewTransition:
|
||||
break;
|
||||
case Kind::ImageLoadingContent:
|
||||
break;
|
||||
@@ -750,7 +745,7 @@ void nsImageFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
|
||||
}
|
||||
} else if (mKind == Kind::XULImage) {
|
||||
UpdateXULImage();
|
||||
} else if (mKind == Kind::ViewTransitionOld) {
|
||||
} else if (mKind == Kind::ViewTransition) {
|
||||
// View transitions have a surface directly.
|
||||
} else {
|
||||
const StyleImage* image = GetImageFromStyle();
|
||||
@@ -881,13 +876,10 @@ IntrinsicSize nsImageFrame::ComputeIntrinsicSize(
|
||||
return FinishIntrinsicSize(containAxes, intrinsicSize);
|
||||
}
|
||||
|
||||
if (auto* surf = GetViewTransitionSurface()) {
|
||||
if (auto size = GetViewTransitionSnapshotSize()) {
|
||||
IntrinsicSize intrinsicSize;
|
||||
auto devPx = LayoutDeviceIntSize::FromUnknownSize(surf->GetSize());
|
||||
auto size = LayoutDeviceIntSize::ToAppUnits(
|
||||
devPx, PresContext()->AppUnitsPerDevPixel());
|
||||
intrinsicSize.width.emplace(size.width);
|
||||
intrinsicSize.height.emplace(size.height);
|
||||
intrinsicSize.width.emplace(size->width);
|
||||
intrinsicSize.height.emplace(size->height);
|
||||
return FinishIntrinsicSize(containAxes, intrinsicSize);
|
||||
}
|
||||
|
||||
@@ -950,18 +942,47 @@ bool nsImageFrame::UpdateIntrinsicSize() {
|
||||
return mIntrinsicSize != oldIntrinsicSize;
|
||||
}
|
||||
|
||||
gfx::DataSourceSurface* nsImageFrame::GetViewTransitionSurface() const {
|
||||
if (mKind != Kind::ViewTransitionOld) {
|
||||
return nullptr;
|
||||
}
|
||||
auto* vt = PresContext()->Document()->GetActiveViewTransition();
|
||||
if (NS_WARN_IF(!vt)) {
|
||||
nsAtom* nsImageFrame::GetViewTransitionName() const {
|
||||
if (mKind != Kind::ViewTransition) {
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(GetContent()->AsElement()->HasName());
|
||||
nsAtom* name =
|
||||
GetContent()->AsElement()->GetParsedAttr(nsGkAtoms::name)->GetAtomValue();
|
||||
return vt->GetOldSurface(name);
|
||||
return GetContent()
|
||||
->AsElement()
|
||||
->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(
|
||||
@@ -976,8 +997,8 @@ AspectRatio nsImageFrame::ComputeIntrinsicRatioForImage(
|
||||
}
|
||||
}
|
||||
|
||||
if (auto* surf = GetViewTransitionSurface()) {
|
||||
return AspectRatio::FromSize(surf->GetSize());
|
||||
if (auto size = GetViewTransitionSnapshotSize()) {
|
||||
return AspectRatio::FromSize(*size);
|
||||
}
|
||||
|
||||
if (ShouldUseMappedAspectRatio()) {
|
||||
@@ -2344,35 +2365,17 @@ void nsDisplayImage::MaybeCreateWebRenderCommandsForViewTransition(
|
||||
nsDisplayListBuilder* aDisplayListBuilder) {
|
||||
auto* frame = Frame();
|
||||
MOZ_ASSERT(!frame->mImage);
|
||||
auto* surf = frame->GetViewTransitionSurface();
|
||||
if (NS_WARN_IF(!surf)) {
|
||||
auto key = frame->GetViewTransitionImageKey(aManager, aResources);
|
||||
if (NS_WARN_IF(key == kNoKey)) {
|
||||
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 int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
const auto destRect =
|
||||
wr::ToLayoutRect(LayoutDeviceRect::FromAppUnits(destAppUnits, factor));
|
||||
auto rendering = wr::ToImageRendering(frame->UsedImageRendering());
|
||||
aBuilder.PushImage(destRect, destRect, !BackfaceIsHidden(),
|
||||
/* aForceAntiAliasing = */ false, rendering,
|
||||
frame->mViewTransitionData.mImageKey);
|
||||
/* aForceAntiAliasing = */ false, rendering, key);
|
||||
}
|
||||
|
||||
bool nsDisplayImage::CreateWebRenderCommands(
|
||||
@@ -2576,7 +2579,7 @@ void nsImageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
aBuilder, this, clipFlags);
|
||||
|
||||
if (!mComputedSize.IsEmpty()) {
|
||||
const bool isViewTransition = mKind == Kind::ViewTransitionOld;
|
||||
const bool isViewTransition = mKind == Kind::ViewTransition;
|
||||
const bool imageOK = mKind != Kind::ImageLoadingContent ||
|
||||
ImageOk(mContent->AsElement()->State());
|
||||
|
||||
|
||||
@@ -196,8 +196,9 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback {
|
||||
ContentPropertyAtIndex,
|
||||
// For a list-style-image ::marker.
|
||||
ListStyleImage,
|
||||
// For a ::view-transition-old pseudo-element
|
||||
ViewTransitionOld,
|
||||
// For a ::view-transition-old or ::view-transition-new pseudo-element.
|
||||
// Which one of the two is determined by the PseudoStyleType applying to us.
|
||||
ViewTransition,
|
||||
};
|
||||
|
||||
// Creates a suitable continuing frame for this frame.
|
||||
@@ -216,7 +217,7 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback {
|
||||
ComputedStyle*);
|
||||
friend nsIFrame* NS_NewImageFrameForListStyleImage(mozilla::PresShell*,
|
||||
ComputedStyle*);
|
||||
friend nsIFrame* NS_NewImageFrameForViewTransitionOld(mozilla::PresShell*,
|
||||
friend nsIFrame* NS_NewImageFrameForViewTransition(mozilla::PresShell*,
|
||||
ComputedStyle*);
|
||||
|
||||
nsImageFrame(ComputedStyle* aStyle, nsPresContext* aPresContext, Kind aKind)
|
||||
@@ -306,7 +307,11 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback {
|
||||
// and height="".
|
||||
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.
|
||||
@@ -398,15 +403,6 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback {
|
||||
nsCOMPtr<imgIContainer> mImage;
|
||||
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
|
||||
// reflow.
|
||||
nsSize mComputedSize;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "mozilla/dom/HTMLCanvasElement.h"
|
||||
#include "mozilla/dom/RemoteBrowser.h"
|
||||
#include "mozilla/dom/Selection.h"
|
||||
#include "mozilla/dom/ViewTransition.h"
|
||||
#include "mozilla/dom/ServiceWorkerRegistrar.h"
|
||||
#include "mozilla/dom/ServiceWorkerRegistration.h"
|
||||
#include "mozilla/dom/SVGElement.h"
|
||||
@@ -5203,7 +5204,8 @@ bool nsDisplayOwnLayer::CreateWebRenderCommands(
|
||||
const StackingContextHelper& aSc, RenderRootStateManager* aManager,
|
||||
nsDisplayListBuilder* aDisplayListBuilder) {
|
||||
Maybe<wr::WrAnimationProperty> prop;
|
||||
bool needsProp = aManager->LayerManager()->AsyncPanZoomEnabled() &&
|
||||
Maybe<wr::SnapshotInfo> snapshot;
|
||||
const bool needsProp = aManager->LayerManager()->AsyncPanZoomEnabled() &&
|
||||
(IsScrollThumbLayer() || IsZoomingLayer() ||
|
||||
ShouldGetFixedAnimationId() ||
|
||||
(IsRootScrollbarContainer() && HasDynamicToolbar()));
|
||||
@@ -5228,12 +5230,33 @@ bool nsDisplayOwnLayer::CreateWebRenderCommands(
|
||||
params.animation = prop.ptrOr(nullptr);
|
||||
params.clip =
|
||||
wr::WrStackingContextClip::ClipChain(aBuilder.CurrentClipChainId());
|
||||
if (IsScrollbarContainer() && IsRootScrollbarContainer()) {
|
||||
const bool rootScrollbarContainer = IsRootScrollbarContainer();
|
||||
if (rootScrollbarContainer) {
|
||||
params.prim_flags |= wr::PrimitiveFlags::IS_SCROLLBAR_CONTAINER;
|
||||
}
|
||||
if (IsZoomingLayer() ||
|
||||
(ShouldGetFixedAnimationId() ||
|
||||
(IsRootScrollbarContainer() && HasDynamicToolbar()))) {
|
||||
if (mFrame->HasAnyStateBits(NS_FRAME_CAPTURED_IN_VIEW_TRANSITION)) {
|
||||
auto key = [&]() -> Maybe<wr::SnapshotImageKey> {
|
||||
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.should_snap = true;
|
||||
}
|
||||
|
||||
@@ -5380,7 +5380,7 @@ class nsDisplayOwnLayer : public nsDisplayWrapList {
|
||||
public:
|
||||
enum OwnLayerType {
|
||||
OwnLayerForTransformWithRoundedClip,
|
||||
OwnLayerForStackingContext,
|
||||
OwnLayerForViewTransitionCapture,
|
||||
OwnLayerForScrollbar,
|
||||
OwnLayerForScrollThumb,
|
||||
OwnLayerForSubdoc,
|
||||
|
||||
@@ -4923,6 +4923,12 @@
|
||||
value: false
|
||||
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?
|
||||
# Disabled everywhere, but not removed.
|
||||
- name: dom.vr.enabled
|
||||
|
||||
Reference in New Issue
Block a user