Bug 1922335 - Implement basic support for DataSourceSurface-based snapshotting of old contents. r=nical
This implements some basic snapshotting functionality, and hooks it to the ::view-transition-old pseudo-elements. Some tests that now fail because we start rendering the old snapshot, but not at the right position, as for now the view transition pseudo tree is all statically-positioned. That's all expected for now until we implement the right styling for them, the top layer behavior, etc. Main remaining question is how to get a hand on the right layer manager from nsImageFrame::Destroy. Differential Revision: https://phabricator.services.mozilla.com/D231977
This commit is contained in:
@@ -3,22 +3,22 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ViewTransition.h"
|
||||
#include "nsPresContext.h"
|
||||
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/dom/BindContext.h"
|
||||
#include "mozilla/dom/DocumentInlines.h"
|
||||
#include "mozilla/dom/Promise-inl.h"
|
||||
#include "mozilla/dom/ViewTransitionBinding.h"
|
||||
#include "mozilla/webrender/WebRenderAPI.h"
|
||||
#include "mozilla/ServoStyleConsts.h"
|
||||
#include "mozilla/SVGIntegrationUtils.h"
|
||||
#include "mozilla/WritingModes.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "Units.h"
|
||||
|
||||
static inline void ImplCycleCollectionTraverse(
|
||||
nsCycleCollectionTraversalCallback&, const nsRefPtrHashKey<nsAtom>&,
|
||||
const char* aName, uint32_t aFlags = 0) {
|
||||
// Nothing, but needed to compile.
|
||||
}
|
||||
|
||||
namespace mozilla::dom {
|
||||
|
||||
// Set capture's old transform to a <transform-function> that would map
|
||||
@@ -48,9 +48,40 @@ static CSSToCSSMatrix4x4Flagged EffectiveTransform(nsIFrame* aFrame) {
|
||||
return matrix;
|
||||
}
|
||||
|
||||
static RefPtr<gfx::DataSourceSurface> CaptureFallbackSnapshot(
|
||||
nsIFrame* aFrame) {
|
||||
const nsRect rect = aFrame->InkOverflowRectRelativeToSelf();
|
||||
const auto surfaceRect = LayoutDeviceIntRect::FromAppUnitsToOutside(
|
||||
rect, aFrame->PresContext()->AppUnitsPerDevPixel());
|
||||
|
||||
// TODO: Should we use the DrawTargetRecorder infra or what not?
|
||||
const auto format = gfx::SurfaceFormat::B8G8R8A8;
|
||||
RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateDrawTarget(
|
||||
gfxPlatform::GetPlatform()->GetSoftwareBackend(),
|
||||
surfaceRect.Size().ToUnknownSize(), format);
|
||||
if (NS_WARN_IF(!dt) || NS_WARN_IF(!dt->IsValid())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
{
|
||||
using PaintFrameFlags = nsLayoutUtils::PaintFrameFlags;
|
||||
gfxContext thebes(dt);
|
||||
// TODO: This matches the drawable code we use for -moz-element(), but is
|
||||
// this right?
|
||||
const PaintFrameFlags flags = PaintFrameFlags::InTransform;
|
||||
nsLayoutUtils::PaintFrame(&thebes, aFrame, rect, NS_RGBA(0, 0, 0, 0),
|
||||
nsDisplayListBuilderMode::Painting, flags);
|
||||
}
|
||||
|
||||
RefPtr<gfx::SourceSurface> surf = dt->GetBackingSurface();
|
||||
if (NS_WARN_IF(!surf)) {
|
||||
return nullptr;
|
||||
}
|
||||
return surf->GetDataSurface();
|
||||
}
|
||||
|
||||
struct CapturedElementOldState {
|
||||
// TODO: mImage
|
||||
bool mHasImage = false;
|
||||
RefPtr<gfx::DataSourceSurface> mImage;
|
||||
|
||||
// Encompasses width and height.
|
||||
nsSize mSize;
|
||||
@@ -63,7 +94,7 @@ struct CapturedElementOldState {
|
||||
|
||||
CapturedElementOldState(nsIFrame* aFrame,
|
||||
const nsSize& aSnapshotContainingBlockSize)
|
||||
: mHasImage(true),
|
||||
: mImage(CaptureFallbackSnapshot(aFrame)),
|
||||
mSize(aFrame->Style()->IsRootElementStyle()
|
||||
? aSnapshotContainingBlockSize
|
||||
: aFrame->GetRect().Size()),
|
||||
@@ -92,9 +123,9 @@ struct ViewTransition::CapturedElement {
|
||||
|
||||
static inline void ImplCycleCollectionTraverse(
|
||||
nsCycleCollectionTraversalCallback& aCb,
|
||||
const UniquePtr<ViewTransition::CapturedElement>& aField, const char* aName,
|
||||
const ViewTransition::CapturedElement& aField, const char* aName,
|
||||
uint32_t aFlags = 0) {
|
||||
ImplCycleCollectionTraverse(aCb, aField->mNewElement, aName, aFlags);
|
||||
ImplCycleCollectionTraverse(aCb, aField.mNewElement, aName, aFlags);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ViewTransition, mDocument,
|
||||
@@ -117,6 +148,14 @@ ViewTransition::ViewTransition(Document& aDoc,
|
||||
|
||||
ViewTransition::~ViewTransition() { ClearTimeoutTimer(); }
|
||||
|
||||
gfx::DataSourceSurface* ViewTransition::GetOldSurface(nsAtom* aName) const {
|
||||
auto el = mNamedElements.Get(aName);
|
||||
if (NS_WARN_IF(!el)) {
|
||||
return nullptr;
|
||||
}
|
||||
return el->mOldState.mImage;
|
||||
}
|
||||
|
||||
nsIGlobalObject* ViewTransition::GetParentObject() const {
|
||||
return mDocument ? mDocument->GetParentObject() : nullptr;
|
||||
}
|
||||
@@ -325,7 +364,7 @@ void ViewTransition::SetupTransitionPseudoElements() {
|
||||
// Append imagePair to group.
|
||||
group->AppendChildTo(imagePair, kNotify, IgnoreErrors());
|
||||
// If capturedElement's old image is not null, then:
|
||||
if (capturedElement.mOldState.mHasImage) {
|
||||
if (capturedElement.mOldState.mImage) {
|
||||
// Let old be a new ::view-transition-old(), with its view transition
|
||||
// name set to transitionName, displaying capturedElement's old image as
|
||||
// its replaced content.
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
|
||||
#include "nsRect.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsTHashMap.h"
|
||||
#include "nsAtomHashKeys.h"
|
||||
#include "nsClassHashtable.h"
|
||||
|
||||
class nsIGlobalObject;
|
||||
class nsITimer;
|
||||
@@ -16,6 +17,10 @@ namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
|
||||
namespace gfx {
|
||||
class DataSourceSurface;
|
||||
}
|
||||
|
||||
namespace dom {
|
||||
|
||||
class Document;
|
||||
@@ -59,6 +64,7 @@ class ViewTransition final : public nsISupports, public nsWrapperCache {
|
||||
void PerformPendingOperations();
|
||||
|
||||
Element* GetRoot() const { return mViewTransitionRoot; }
|
||||
gfx::DataSourceSurface* GetOldSurface(nsAtom* aName) const;
|
||||
|
||||
nsIGlobalObject* GetParentObject() const;
|
||||
JSObject* WrapObject(JSContext*, JS::Handle<JSObject*> aGivenProto) override;
|
||||
@@ -91,7 +97,7 @@ class ViewTransition final : public nsISupports, public nsWrapperCache {
|
||||
RefPtr<ViewTransitionUpdateCallback> mUpdateCallback;
|
||||
|
||||
// https://drafts.csswg.org/css-view-transitions/#viewtransition-named-elements
|
||||
using NamedElements = nsTHashMap<RefPtr<nsAtom>, UniquePtr<CapturedElement>>;
|
||||
using NamedElements = nsClassHashtable<nsAtomHashKey, CapturedElement>;
|
||||
NamedElements mNamedElements;
|
||||
|
||||
// https://drafts.csswg.org/css-view-transitions/#viewtransition-initial-snapshot-containing-block-size
|
||||
|
||||
@@ -15,4 +15,6 @@ UNIFIED_SOURCES += [
|
||||
"ViewTransition.cpp",
|
||||
]
|
||||
|
||||
include("/ipc/chromium/chromium-config.mozbuild")
|
||||
|
||||
FINAL_LIBRARY = "xul"
|
||||
|
||||
@@ -221,6 +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*);
|
||||
|
||||
// Returns true if aFrame is an anonymous flex/grid item.
|
||||
static inline bool IsAnonymousItem(const nsIFrame* aFrame) {
|
||||
@@ -3449,8 +3450,8 @@ nsCSSFrameConstructor::FindHTMLData(const Element& aElement,
|
||||
aParentFrame->GetParent()->IsFieldSetFrame(),
|
||||
"Unexpected parent for fieldset content anon box");
|
||||
|
||||
if (aElement.IsInNativeAnonymousSubtree() &&
|
||||
aElement.NodeInfo()->NameAtom() == nsGkAtoms::label && aParentFrame) {
|
||||
if (aElement.IsInNativeAnonymousSubtree()) {
|
||||
if (aElement.NodeInfo()->NameAtom() == nsGkAtoms::label && aParentFrame) {
|
||||
if (aParentFrame->IsFileControlFrame()) {
|
||||
static constexpr FrameConstructionData sFileLabelData(
|
||||
NS_NewFileControlLabelFrame);
|
||||
@@ -3463,6 +3464,12 @@ nsCSSFrameConstructor::FindHTMLData(const Element& aElement,
|
||||
return &sComboboxLabelData;
|
||||
}
|
||||
}
|
||||
if (aElement.GetPseudoElementType() == PseudoStyleType::viewTransitionOld) {
|
||||
static constexpr FrameConstructionData sViewTransitionOldData(
|
||||
NS_NewImageFrameForViewTransitionOld);
|
||||
return &sViewTransitionOldData;
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr FrameConstructionDataByTag sHTMLData[] = {
|
||||
SIMPLE_TAG_CHAIN(img, nsCSSFrameConstructor::FindImgData),
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "mozilla/dom/HTMLImageElement.h"
|
||||
#include "mozilla/dom/ReferrerInfo.h"
|
||||
#include "mozilla/dom/ResponsiveImageSelector.h"
|
||||
#include "mozilla/dom/ViewTransition.h"
|
||||
#include "mozilla/dom/LargestContentfulPaint.h"
|
||||
#include "mozilla/image/WebRenderImageProvider.h"
|
||||
#include "mozilla/layers/RenderRootStateManager.h"
|
||||
@@ -126,10 +127,10 @@ class nsDisplayGradient final : public nsPaintedDisplayItem {
|
||||
|
||||
void Paint(nsDisplayListBuilder*, gfxContext* aCtx) final;
|
||||
|
||||
bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder&,
|
||||
mozilla::wr::IpcResourceUpdateQueue&,
|
||||
bool CreateWebRenderCommands(wr::DisplayListBuilder&,
|
||||
wr::IpcResourceUpdateQueue&,
|
||||
const StackingContextHelper&,
|
||||
mozilla::layers::RenderRootStateManager*,
|
||||
layers::RenderRootStateManager*,
|
||||
nsDisplayListBuilder*) final;
|
||||
|
||||
NS_DISPLAY_DECL_NAME("Gradient", TYPE_GRADIENT)
|
||||
@@ -157,8 +158,7 @@ void nsDisplayGradient::Paint(nsDisplayListBuilder* aBuilder,
|
||||
|
||||
bool nsDisplayGradient::CreateWebRenderCommands(
|
||||
wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
|
||||
const StackingContextHelper& aSc,
|
||||
mozilla::layers::RenderRootStateManager* aManager,
|
||||
const StackingContextHelper& aSc, layers::RenderRootStateManager* aManager,
|
||||
nsDisplayListBuilder* aDisplayListBuilder) {
|
||||
auto* frame = static_cast<nsImageFrame*>(Frame());
|
||||
nsImageRenderer imageRenderer(frame, frame->GetImageFromStyle(),
|
||||
@@ -399,6 +399,12 @@ nsIFrame* NS_NewImageFrameForListStyleImage(PresShell* aPresShell,
|
||||
nsImageFrame::Kind::ListStyleImage);
|
||||
}
|
||||
|
||||
nsIFrame* NS_NewImageFrameForViewTransitionOld(PresShell* aPresShell,
|
||||
ComputedStyle* aStyle) {
|
||||
return new (aPresShell) nsImageFrame(aStyle, aPresShell->GetPresContext(),
|
||||
nsImageFrame::Kind::ViewTransitionOld);
|
||||
}
|
||||
|
||||
bool nsImageFrame::ShouldShowBrokenImageIcon() const {
|
||||
// NOTE(emilio, https://github.com/w3c/csswg-drafts/issues/2832): WebKit and
|
||||
// Blink behave differently here for content: url(..), for now adapt to
|
||||
@@ -465,6 +471,11 @@ a11y::AccType nsImageFrame::AccessibleType() {
|
||||
return a11y::eNoType;
|
||||
}
|
||||
|
||||
if (mKind == Kind::ViewTransitionOld) {
|
||||
// View transitions don't show up in the a11y tree.
|
||||
return a11y::eNoType;
|
||||
}
|
||||
|
||||
// Don't use GetImageMap() to avoid reentrancy into accessibility.
|
||||
if (HasImageMap()) {
|
||||
return a11y::eHTMLImageMapType;
|
||||
@@ -527,6 +538,13 @@ void nsImageFrame::Destroy(DestroyContext& aContext) {
|
||||
BrokenImageIcon::RemoveObserver(this);
|
||||
}
|
||||
|
||||
if (mViewTransitionData.HasKey()) {
|
||||
MOZ_ASSERT(mViewTransitionData.mManager);
|
||||
mViewTransitionData.mManager->AddImageKeyForDiscard(
|
||||
mViewTransitionData.mImageKey);
|
||||
mViewTransitionData = {};
|
||||
}
|
||||
|
||||
nsAtomicContainerFrame::Destroy(aContext);
|
||||
}
|
||||
|
||||
@@ -612,6 +630,8 @@ static bool SizeIsAvailable(imgIRequest* aRequest) {
|
||||
|
||||
const StyleImage* nsImageFrame::GetImageFromStyle() const {
|
||||
switch (mKind) {
|
||||
case Kind::ViewTransitionOld:
|
||||
break;
|
||||
case Kind::ImageLoadingContent:
|
||||
break;
|
||||
case Kind::ListStyleImage:
|
||||
@@ -730,6 +750,8 @@ void nsImageFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
|
||||
}
|
||||
} else if (mKind == Kind::XULImage) {
|
||||
UpdateXULImage();
|
||||
} else if (mKind == Kind::ViewTransitionOld) {
|
||||
// View transitions have a surface directly.
|
||||
} else {
|
||||
const StyleImage* image = GetImageFromStyle();
|
||||
if (image->IsImageRequestType()) {
|
||||
@@ -859,6 +881,16 @@ IntrinsicSize nsImageFrame::ComputeIntrinsicSize(
|
||||
return FinishIntrinsicSize(containAxes, intrinsicSize);
|
||||
}
|
||||
|
||||
if (auto* surf = GetViewTransitionSurface()) {
|
||||
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);
|
||||
return FinishIntrinsicSize(containAxes, intrinsicSize);
|
||||
}
|
||||
|
||||
if (mKind == nsImageFrame::Kind::ListStyleImage) {
|
||||
// Note: images are handled above, this handles gradients etc.
|
||||
const nscoord defaultLength = ListImageDefaultLength(*this);
|
||||
@@ -918,6 +950,20 @@ 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)) {
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(GetContent()->AsElement()->HasName());
|
||||
nsAtom* name =
|
||||
GetContent()->AsElement()->GetParsedAttr(nsGkAtoms::name)->GetAtomValue();
|
||||
return vt->GetOldSurface(name);
|
||||
}
|
||||
|
||||
AspectRatio nsImageFrame::ComputeIntrinsicRatioForImage(
|
||||
imgIContainer* aImage, bool aIgnoreContainment) const {
|
||||
if (!aIgnoreContainment && GetContainSizeAxes().IsAny()) {
|
||||
@@ -929,6 +975,11 @@ AspectRatio nsImageFrame::ComputeIntrinsicRatioForImage(
|
||||
return fromImage;
|
||||
}
|
||||
}
|
||||
|
||||
if (auto* surf = GetViewTransitionSurface()) {
|
||||
return AspectRatio::FromSize(surf->GetSize());
|
||||
}
|
||||
|
||||
if (ShouldUseMappedAspectRatio()) {
|
||||
const StyleAspectRatio& ratio = StylePosition()->mAspectRatio;
|
||||
if (ratio.auto_ && ratio.HasRatio()) {
|
||||
@@ -1815,10 +1866,9 @@ class nsDisplayAltFeedback final : public nsPaintedDisplayItem {
|
||||
}
|
||||
|
||||
bool CreateWebRenderCommands(
|
||||
mozilla::wr::DisplayListBuilder& aBuilder,
|
||||
mozilla::wr::IpcResourceUpdateQueue& aResources,
|
||||
wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
|
||||
const StackingContextHelper& aSc,
|
||||
mozilla::layers::RenderRootStateManager* aManager,
|
||||
layers::RenderRootStateManager* aManager,
|
||||
nsDisplayListBuilder* aDisplayListBuilder) final {
|
||||
// Always sync decode, because these icons are UI, and since they're not
|
||||
// discardable we'll pay the price of sync decoding at most once.
|
||||
@@ -1983,10 +2033,9 @@ ImgDrawResult nsImageFrame::DisplayAltFeedback(gfxContext& aRenderingContext,
|
||||
}
|
||||
|
||||
ImgDrawResult nsImageFrame::DisplayAltFeedbackWithoutLayer(
|
||||
nsDisplayItem* aItem, mozilla::wr::DisplayListBuilder& aBuilder,
|
||||
mozilla::wr::IpcResourceUpdateQueue& aResources,
|
||||
const StackingContextHelper& aSc,
|
||||
mozilla::layers::RenderRootStateManager* aManager,
|
||||
nsDisplayItem* aItem, wr::DisplayListBuilder& aBuilder,
|
||||
wr::IpcResourceUpdateQueue& aResources, const StackingContextHelper& aSc,
|
||||
layers::RenderRootStateManager* aManager,
|
||||
nsDisplayListBuilder* aDisplayListBuilder, nsPoint aPt, uint32_t aFlags) {
|
||||
// Whether we draw the broken or loading icon.
|
||||
bool isLoading = mKind != Kind::ImageLoadingContent ||
|
||||
@@ -2020,7 +2069,7 @@ ImgDrawResult nsImageFrame::DisplayAltFeedbackWithoutLayer(
|
||||
bool textDrawResult = true;
|
||||
class AutoSaveRestore {
|
||||
public:
|
||||
explicit AutoSaveRestore(mozilla::wr::DisplayListBuilder& aBuilder,
|
||||
explicit AutoSaveRestore(wr::DisplayListBuilder& aBuilder,
|
||||
bool& aTextDrawResult)
|
||||
: mBuilder(aBuilder), mTextDrawResult(aTextDrawResult) {
|
||||
mBuilder.Save();
|
||||
@@ -2036,7 +2085,7 @@ ImgDrawResult nsImageFrame::DisplayAltFeedbackWithoutLayer(
|
||||
}
|
||||
|
||||
private:
|
||||
mozilla::wr::DisplayListBuilder& mBuilder;
|
||||
wr::DisplayListBuilder& mBuilder;
|
||||
bool& mTextDrawResult;
|
||||
};
|
||||
|
||||
@@ -2289,19 +2338,54 @@ nsRegion nsDisplayImage::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
|
||||
return nsRegion();
|
||||
}
|
||||
|
||||
bool nsDisplayImage::CreateWebRenderCommands(
|
||||
mozilla::wr::DisplayListBuilder& aBuilder,
|
||||
mozilla::wr::IpcResourceUpdateQueue& aResources,
|
||||
void nsDisplayImage::MaybeCreateWebRenderCommandsForViewTransition(
|
||||
wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
|
||||
const StackingContextHelper& aSc, RenderRootStateManager* aManager,
|
||||
nsDisplayListBuilder* aDisplayListBuilder) {
|
||||
auto* frame = Frame();
|
||||
MOZ_ASSERT(!frame->mImage);
|
||||
auto* surf = frame->GetViewTransitionSurface();
|
||||
if (NS_WARN_IF(!surf)) {
|
||||
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);
|
||||
}
|
||||
|
||||
bool nsDisplayImage::CreateWebRenderCommands(
|
||||
wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources,
|
||||
const StackingContextHelper& aSc, RenderRootStateManager* aManager,
|
||||
nsDisplayListBuilder* aDisplayListBuilder) {
|
||||
MOZ_ASSERT(mFrame->IsImageFrame() || mFrame->IsImageControlFrame());
|
||||
auto* frame = Frame();
|
||||
auto* image = frame->mImage.get();
|
||||
if (!image) {
|
||||
// TODO: View transitions.
|
||||
MaybeCreateWebRenderCommandsForViewTransition(
|
||||
aBuilder, aResources, aSc, aManager, aDisplayListBuilder);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (frame->HasImageMap()) {
|
||||
// Image layer doesn't support draw focus ring for image map.
|
||||
return false;
|
||||
@@ -2492,19 +2576,24 @@ void nsImageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
aBuilder, this, clipFlags);
|
||||
|
||||
if (!mComputedSize.IsEmpty()) {
|
||||
const bool isViewTransition = mKind == Kind::ViewTransitionOld;
|
||||
const bool imageOK = mKind != Kind::ImageLoadingContent ||
|
||||
ImageOk(mContent->AsElement()->State());
|
||||
|
||||
nsCOMPtr<imgIRequest> currentRequest = GetCurrentRequest();
|
||||
|
||||
const bool isImageFromStyle =
|
||||
mKind != Kind::ImageLoadingContent && mKind != Kind::XULImage;
|
||||
const bool isImageFromStyle = mKind != Kind::ImageLoadingContent &&
|
||||
mKind != Kind::XULImage && !isViewTransition;
|
||||
const bool drawAltFeedback = [&] {
|
||||
if (!imageOK) {
|
||||
return true;
|
||||
}
|
||||
// If we're a gradient, we don't need to draw alt feedback.
|
||||
if (isImageFromStyle && !GetImageFromStyle()->IsImageRequestType()) {
|
||||
// If we're a gradient, we don't need to draw alt feedback.
|
||||
return false;
|
||||
}
|
||||
if (isViewTransition) {
|
||||
// Same for view transitions.
|
||||
return false;
|
||||
}
|
||||
// XXX(seth): The SizeIsAvailable check here should not be necessary - the
|
||||
@@ -2533,7 +2622,7 @@ void nsImageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (mImage) {
|
||||
if (mImage || isViewTransition) {
|
||||
aLists.Content()->AppendNewToTop<nsDisplayImage>(aBuilder, this);
|
||||
} else if (isImageFromStyle) {
|
||||
aLists.Content()->AppendNewToTop<nsDisplayGradient>(aBuilder, this);
|
||||
|
||||
@@ -196,6 +196,8 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback {
|
||||
ContentPropertyAtIndex,
|
||||
// For a list-style-image ::marker.
|
||||
ListStyleImage,
|
||||
// For a ::view-transition-old pseudo-element
|
||||
ViewTransitionOld,
|
||||
};
|
||||
|
||||
// Creates a suitable continuing frame for this frame.
|
||||
@@ -214,6 +216,8 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback {
|
||||
ComputedStyle*);
|
||||
friend nsIFrame* NS_NewImageFrameForListStyleImage(mozilla::PresShell*,
|
||||
ComputedStyle*);
|
||||
friend nsIFrame* NS_NewImageFrameForViewTransitionOld(mozilla::PresShell*,
|
||||
ComputedStyle*);
|
||||
|
||||
nsImageFrame(ComputedStyle* aStyle, nsPresContext* aPresContext, Kind aKind)
|
||||
: nsImageFrame(aStyle, aPresContext, kClassID, aKind) {}
|
||||
@@ -302,6 +306,8 @@ class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback {
|
||||
// and height="".
|
||||
bool ShouldUseMappedAspectRatio() const;
|
||||
|
||||
mozilla::gfx::DataSourceSurface* GetViewTransitionSurface() const;
|
||||
|
||||
/**
|
||||
* Notification that aRequest will now be the current request.
|
||||
*/
|
||||
@@ -392,6 +398,15 @@ 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;
|
||||
@@ -458,6 +473,11 @@ class nsDisplayImage final : public nsPaintedDisplayItem {
|
||||
mozilla::layers::RenderRootStateManager*,
|
||||
nsDisplayListBuilder*) final;
|
||||
|
||||
void MaybeCreateWebRenderCommandsForViewTransition(
|
||||
mozilla::wr::DisplayListBuilder&, mozilla::wr::IpcResourceUpdateQueue&,
|
||||
const StackingContextHelper&, mozilla::layers::RenderRootStateManager*,
|
||||
nsDisplayListBuilder*);
|
||||
|
||||
nsImageFrame* Frame() const {
|
||||
MOZ_ASSERT(mFrame->IsImageFrame() || mFrame->IsImageControlFrame());
|
||||
return static_cast<nsImageFrame*>(mFrame);
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
[active-view-transition-on-non-root.html]
|
||||
expected: FAIL
|
||||
@@ -0,0 +1,2 @@
|
||||
[fractional-translation-from-position.html]
|
||||
expected: FAIL
|
||||
@@ -0,0 +1,2 @@
|
||||
[fractional-translation-from-transform.html]
|
||||
expected: FAIL
|
||||
@@ -0,0 +1,2 @@
|
||||
[border-offset-with-padding-inline.tentative.html]
|
||||
expected: FAIL
|
||||
@@ -1,5 +1,2 @@
|
||||
[massive-element-left-of-viewport-partially-onscreen-new.html]
|
||||
# Might need meta viewport.
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
PASS
|
||||
expected: FAIL
|
||||
|
||||
@@ -1,5 +1,2 @@
|
||||
[massive-element-left-of-viewport-partially-onscreen-old.html]
|
||||
# Might need meta viewport.
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
PASS
|
||||
expected: FAIL
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
[named-element-with-fix-pos-child-old.html]
|
||||
expected: FAIL
|
||||
@@ -0,0 +1,2 @@
|
||||
[new-and-old-sizes-match.html]
|
||||
expected: FAIL
|
||||
@@ -0,0 +1,2 @@
|
||||
[no-root-capture.html]
|
||||
expected: FAIL
|
||||
@@ -5,3 +5,8 @@
|
||||
[:only-child should match because ::view-transition-old is not generated (none to element)]
|
||||
expected: FAIL
|
||||
|
||||
[:only-child should not match because ::view-transition-old is generated (element to root)]
|
||||
expected: FAIL
|
||||
|
||||
[:only-child should not match because ::view-transition-old is generated (element to element)]
|
||||
expected: FAIL
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
[rtl-with-scrollbar.html]
|
||||
expected: FAIL
|
||||
@@ -0,0 +1,2 @@
|
||||
[scroller-child-abspos.html]
|
||||
expected: FAIL
|
||||
@@ -0,0 +1,2 @@
|
||||
[scroller-child.html]
|
||||
expected: FAIL
|
||||
@@ -0,0 +1,2 @@
|
||||
[scroller.html]
|
||||
expected: FAIL
|
||||
@@ -0,0 +1,2 @@
|
||||
[transformed-element-scroll-transform.html]
|
||||
expected: FAIL
|
||||
Reference in New Issue
Block a user