Backed out 13 changesets (bug 1711061) on devs request. CLOSED TREE

Backed out changeset c4f073f7e3a3 (bug 1711061)
Backed out changeset aced4b672fb4 (bug 1711061)
Backed out changeset 3687e798f665 (bug 1711061)
Backed out changeset 7b471990ea86 (bug 1711061)
Backed out changeset 1014a95f540e (bug 1711061)
Backed out changeset a37b3091281d (bug 1711061)
Backed out changeset 96a0ef35881b (bug 1711061)
Backed out changeset 38890cc266fb (bug 1711061)
Backed out changeset be73004c0850 (bug 1711061)
Backed out changeset b964576ae53d (bug 1711061)
Backed out changeset d453c5219255 (bug 1711061)
Backed out changeset 0145b538175b (bug 1711061)
Backed out changeset 41ba2e2a2d13 (bug 1711061)
This commit is contained in:
Sandor Molnar 2021-10-29 00:36:30 +03:00
parent 555899fe9b
commit f5bbecdcc2
54 changed files with 1374 additions and 998 deletions

View File

@ -28,6 +28,7 @@
#include "mozilla/layers/LayersMessages.h"
#include "mozilla/layers/SharedPlanarYCbCrImage.h"
#include "mozilla/layers/SharedRGBImage.h"
#include "mozilla/layers/SharedSurfacesChild.h" // for SharedSurfacesAnimation
#include "mozilla/layers/TextureClientRecycleAllocator.h"
#include "nsProxyRelease.h"
#include "nsISupportsUtils.h" // for NS_IF_ADDREF
@ -174,6 +175,13 @@ void ImageContainer::EnsureImageClient() {
}
}
SharedSurfacesAnimation* ImageContainer::EnsureSharedSurfacesAnimation() {
if (!mSharedAnimation) {
mSharedAnimation = new SharedSurfacesAnimation();
}
return mSharedAnimation;
}
ImageContainer::ImageContainer(Mode flag)
: mRecursiveMutex("ImageContainer.mRecursiveMutex"),
mGenerationCounter(++sGenerationCounter),
@ -212,6 +220,9 @@ ImageContainer::~ImageContainer() {
imageBridge->ForgetImageContainer(mAsyncContainerHandle);
}
}
if (mSharedAnimation) {
mSharedAnimation->Destroy();
}
}
Maybe<SurfaceDescriptor> Image::GetDesc() { return {}; }

View File

@ -48,6 +48,7 @@ class ImageCompositeNotification;
class ImageContainer;
class ImageContainerChild;
class SharedPlanarYCbCrImage;
class SharedSurfacesAnimation;
class SurfaceDescriptor;
class PlanarYCbCrImage;
class TextureClient;
@ -528,6 +529,12 @@ class ImageContainer final : public SupportsThreadSafeWeakPtr<ImageContainer> {
void DropImageClient();
SharedSurfacesAnimation* GetSharedSurfacesAnimation() const {
return mSharedAnimation;
}
SharedSurfacesAnimation* EnsureSharedSurfacesAnimation();
private:
typedef mozilla::RecursiveMutex RecursiveMutex;
@ -592,6 +599,8 @@ class ImageContainer final : public SupportsThreadSafeWeakPtr<ImageContainer> {
// than asynchronusly using the ImageBridge IPDL protocol.
RefPtr<ImageClient> mImageClient;
RefPtr<SharedSurfacesAnimation> mSharedAnimation;
bool mIsAsync;
CompositableHandle mAsyncContainerHandle;

View File

@ -8,6 +8,7 @@
#include "SharedSurfacesParent.h"
#include "CompositorManagerChild.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/image/SourceSurfaceBlobImage.h"
#include "mozilla/layers/IpcResourceUpdateQueue.h"
#include "mozilla/layers/SourceSurfaceSharedData.h"
#include "mozilla/layers/WebRenderBridgeChild.h"
@ -323,6 +324,90 @@ nsresult SharedSurfacesChild::Share(SourceSurface* aSurface,
return Share(sharedSurface, aManager, aResources, aKey);
}
/* static */
nsresult SharedSurfacesChild::Share(ImageContainer* aContainer,
RenderRootStateManager* aManager,
wr::IpcResourceUpdateQueue& aResources,
wr::ImageKey& aKey,
ContainerProducerID aProducerId) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aContainer);
MOZ_ASSERT(aManager);
if (aContainer->IsAsync()) {
return NS_ERROR_NOT_IMPLEMENTED;
}
AutoTArray<ImageContainer::OwningImage, 4> images;
aContainer->GetCurrentImages(&images);
if (images.IsEmpty()) {
return NS_ERROR_NOT_AVAILABLE;
}
if (aProducerId != kContainerProducerID_Invalid &&
images[0].mProducerID != aProducerId) {
// If the producer ID of the surface in the container does not match the
// expected producer ID, then we do not want to proceed with sharing. This
// is useful for when callers are unsure if given container is for the same
// producer / underlying image request.
return NS_ERROR_FAILURE;
}
RefPtr<gfx::SourceSurface> surface = images[0].mImage->GetAsSourceSurface();
if (!surface) {
return NS_ERROR_NOT_IMPLEMENTED;
}
auto sharedSurface = AsSourceSurfaceSharedData(surface);
if (!sharedSurface) {
return NS_ERROR_NOT_IMPLEMENTED;
}
SharedSurfacesAnimation* anim = aContainer->GetSharedSurfacesAnimation();
if (anim) {
return anim->UpdateKey(sharedSurface, aManager, aResources, aKey);
}
return Share(sharedSurface, aManager, aResources, aKey);
}
/* static */
nsresult SharedSurfacesChild::ShareBlob(ImageContainer* aContainer,
RenderRootStateManager* aManager,
wr::IpcResourceUpdateQueue& aResources,
wr::BlobImageKey& aKey) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aContainer);
MOZ_ASSERT(aManager);
if (aContainer->IsAsync()) {
return NS_ERROR_NOT_IMPLEMENTED;
}
AutoTArray<ImageContainer::OwningImage, 4> images;
aContainer->GetCurrentImages(&images);
if (images.IsEmpty()) {
return NS_ERROR_NOT_AVAILABLE;
}
RefPtr<gfx::SourceSurface> surface = images[0].mImage->GetAsSourceSurface();
if (!surface || surface->GetType() != SurfaceType::BLOB_IMAGE) {
return NS_ERROR_NOT_IMPLEMENTED;
}
auto* blobSurface =
static_cast<image::SourceSurfaceBlobImage*>(surface.get());
Maybe<wr::BlobImageKey> key =
blobSurface->UpdateKey(aManager->LayerManager(), aResources);
if (!key) {
return NS_ERROR_FAILURE;
}
aKey = key.value();
return NS_OK;
}
/* static */
nsresult SharedSurfacesChild::Share(SourceSurface* aSurface,
wr::ExternalImageId& aId) {
@ -392,6 +477,28 @@ void SharedSurfacesChild::Unshare(const wr::ExternalImageId& aId,
return Some(data->Id());
}
/* static */
nsresult SharedSurfacesChild::UpdateAnimation(ImageContainer* aContainer,
SourceSurface* aSurface,
const IntRect& aDirtyRect) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aContainer);
MOZ_ASSERT(!aContainer->IsAsync());
MOZ_ASSERT(aSurface);
// If we aren't using shared surfaces, then is nothing to do.
auto sharedSurface = SharedSurfacesChild::AsSourceSurfaceSharedData(aSurface);
if (!sharedSurface) {
MOZ_ASSERT(!aContainer->GetSharedSurfacesAnimation());
return NS_ERROR_NOT_IMPLEMENTED;
}
SharedSurfacesAnimation* anim = aContainer->EnsureSharedSurfacesAnimation();
MOZ_ASSERT(anim);
return anim->SetCurrentFrame(sharedSurface, aDirtyRect);
}
AnimationImageKeyData::AnimationImageKeyData(RenderRootStateManager* aManager,
const wr::ImageKey& aImageKey)
: SharedSurfacesChild::ImageKeyData(aManager, aImageKey) {}

View File

@ -44,6 +44,7 @@ class IpcResourceUpdateQueue;
namespace layers {
class CompositorManagerChild;
class ImageContainer;
class RenderRootStateManager;
class SharedSurfacesChild {
@ -84,6 +85,23 @@ class SharedSurfacesChild {
wr::IpcResourceUpdateQueue& aResources,
wr::ImageKey& aKey);
/**
* Request that the first surface in the image container's current images be
* mapped into the compositor thread's memory space, and a valid ImageKey be
* generated for it for use with WebRender. If a different method should be
* used to share the image data for this particular container, it will return
* NS_ERROR_NOT_IMPLEMENTED. This must be called from the main thread.
*/
static nsresult Share(ImageContainer* aContainer,
RenderRootStateManager* aManager,
wr::IpcResourceUpdateQueue& aResources,
wr::ImageKey& aKey, ContainerProducerID aProducerId);
static nsresult ShareBlob(ImageContainer* aContainer,
RenderRootStateManager* aManager,
wr::IpcResourceUpdateQueue& aResources,
wr::BlobImageKey& aKey);
/**
* Get the external ID, if any, bound to the shared surface. Used for memory
* reporting purposes.
@ -98,6 +116,10 @@ class SharedSurfacesChild {
static gfx::SourceSurfaceSharedData* AsSourceSurfaceSharedData(
gfx::SourceSurface* aSurface);
static nsresult UpdateAnimation(ImageContainer* aContainer,
gfx::SourceSurface* aSurface,
const gfx::IntRect& aDirtyRect);
class ImageKeyData {
public:
ImageKeyData(RenderRootStateManager* aManager,

View File

@ -17,7 +17,6 @@
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/image/WebRenderImageProvider.h"
#include "mozilla/layers/AnimationHelper.h"
#include "mozilla/layers/ClipManager.h"
#include "mozilla/layers/ImageClient.h"
@ -41,7 +40,6 @@ namespace mozilla {
namespace layers {
using namespace gfx;
using namespace image;
static int sIndent;
#include <stdarg.h>
#include <stdio.h>
@ -2011,22 +2009,24 @@ bool WebRenderCommandBuilder::PushImage(
return true;
}
Maybe<wr::ImageKey> WebRenderCommandBuilder::CreateImageProviderKey(
nsDisplayItem* aItem, image::WebRenderImageProvider* aProvider,
Maybe<wr::BlobImageKey> WebRenderCommandBuilder::CreateBlobImageKey(
nsDisplayItem* aItem, ImageContainer* aContainer,
mozilla::wr::IpcResourceUpdateQueue& aResources) {
RefPtr<WebRenderImageProviderData> imageData =
CreateOrRecycleWebRenderUserData<WebRenderImageProviderData>(aItem);
MOZ_ASSERT(!aContainer->IsAsync());
RefPtr<WebRenderBlobImageData> imageData =
CreateOrRecycleWebRenderUserData<WebRenderBlobImageData>(aItem);
MOZ_ASSERT(imageData);
return imageData->UpdateImageKey(aProvider, aResources);
return imageData->UpdateImageKey(aContainer, aResources);
}
bool WebRenderCommandBuilder::PushImageProvider(
nsDisplayItem* aItem, image::WebRenderImageProvider* aProvider,
bool WebRenderCommandBuilder::PushBlobImage(
nsDisplayItem* aItem, ImageContainer* aContainer,
mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const LayoutDeviceRect& aRect, const LayoutDeviceRect& aClip) {
Maybe<wr::ImageKey> key =
CreateImageProviderKey(aItem, aProvider, aResources);
Maybe<wr::BlobImageKey> key =
CreateBlobImageKey(aItem, aContainer, aResources);
if (!key) {
return false;
}
@ -2034,7 +2034,8 @@ bool WebRenderCommandBuilder::PushImageProvider(
auto rendering = wr::ToImageRendering(aItem->Frame()->UsedImageRendering());
auto r = wr::ToLayoutRect(aRect);
auto c = wr::ToLayoutRect(aClip);
aBuilder.PushImage(r, c, !aItem->BackfaceIsHidden(), rendering, key.value());
aBuilder.PushImage(r, c, !aItem->BackfaceIsHidden(), rendering,
wr::AsImageKey(key.value()));
return true;
}

View File

@ -21,10 +21,6 @@
namespace mozilla {
namespace image {
class WebRenderImageProvider;
}
namespace layers {
class ImageClient;
@ -69,8 +65,8 @@ class WebRenderCommandBuilder final {
mozilla::wr::ImageRendering aRendering, const StackingContextHelper& aSc,
gfx::IntSize& aSize, const Maybe<LayoutDeviceRect>& aAsyncImageBounds);
Maybe<wr::ImageKey> CreateImageProviderKey(
nsDisplayItem* aItem, image::WebRenderImageProvider* aProvider,
Maybe<wr::BlobImageKey> CreateBlobImageKey(
nsDisplayItem* aItem, ImageContainer* aContainer,
mozilla::wr::IpcResourceUpdateQueue& aResources);
WebRenderUserDataRefTable* GetWebRenderUserDataTable() {
@ -83,12 +79,11 @@ class WebRenderCommandBuilder final {
const StackingContextHelper& aSc,
const LayoutDeviceRect& aRect, const LayoutDeviceRect& aClip);
bool PushImageProvider(nsDisplayItem* aItem,
image::WebRenderImageProvider* aProvider,
mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const LayoutDeviceRect& aRect,
const LayoutDeviceRect& aClip);
bool PushBlobImage(nsDisplayItem* aItem, ImageContainer* aContainer,
mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const LayoutDeviceRect& aRect,
const LayoutDeviceRect& aClip);
Maybe<wr::ImageMask> BuildWrMaskImage(
nsDisplayMasksAndClipPaths* aMaskItem, wr::DisplayListBuilder& aBuilder,

View File

@ -6,7 +6,6 @@
#include "WebRenderUserData.h"
#include "mozilla/image/WebRenderImageProvider.h"
#include "mozilla/layers/AnimationHelper.h"
#include "mozilla/layers/CompositorBridgeChild.h"
#include "mozilla/layers/ImageClient.h"
@ -20,8 +19,6 @@
#include "nsIFrame.h"
#include "WebRenderCanvasRenderer.h"
using namespace mozilla::image;
namespace mozilla {
namespace layers {
@ -45,9 +42,8 @@ bool WebRenderUserData::SupportsAsyncUpdate(nsIFrame* aFrame) {
}
/* static */
bool WebRenderUserData::ProcessInvalidateForImage(nsIFrame* aFrame,
DisplayItemType aType,
ImageProviderId aProviderId) {
bool WebRenderUserData::ProcessInvalidateForImage(
nsIFrame* aFrame, DisplayItemType aType, ContainerProducerID aProducerId) {
MOZ_ASSERT(aFrame);
if (!aFrame->HasProperty(WebRenderUserDataProperty::Key())) {
@ -63,9 +59,9 @@ bool WebRenderUserData::ProcessInvalidateForImage(nsIFrame* aFrame,
return true;
}
RefPtr<WebRenderImageProviderData> image =
GetWebRenderUserData<WebRenderImageProviderData>(aFrame, type);
if (image && image->Invalidate(aProviderId)) {
RefPtr<WebRenderImageData> image =
GetWebRenderUserData<WebRenderImageData>(aFrame, type);
if (image && image->UsingSharedSurface(aProducerId)) {
return true;
}
@ -99,12 +95,12 @@ WebRenderBridgeChild* WebRenderUserData::WrBridge() const {
WebRenderImageData::WebRenderImageData(RenderRootStateManager* aManager,
nsDisplayItem* aItem)
: WebRenderUserData(aManager, aItem) {}
: WebRenderUserData(aManager, aItem), mOwnsKey(false) {}
WebRenderImageData::WebRenderImageData(RenderRootStateManager* aManager,
uint32_t aDisplayItemKey,
nsIFrame* aFrame)
: WebRenderUserData(aManager, aDisplayItemKey, aFrame) {}
: WebRenderUserData(aManager, aDisplayItemKey, aFrame), mOwnsKey(false) {}
WebRenderImageData::~WebRenderImageData() {
ClearImageKey();
@ -114,15 +110,35 @@ WebRenderImageData::~WebRenderImageData() {
}
}
bool WebRenderImageData::UsingSharedSurface(
ContainerProducerID aProducerId) const {
if (!mContainer || !mKey || mOwnsKey) {
return false;
}
// If this is just an update with the same image key, then we know that the
// share request initiated an asynchronous update so that we don't need to
// rebuild the scene.
wr::ImageKey key;
nsresult rv = SharedSurfacesChild::Share(
mContainer, mManager, mManager->AsyncResourceUpdates(), key, aProducerId);
return NS_SUCCEEDED(rv) && mKey.ref() == key;
}
void WebRenderImageData::ClearImageKey() {
if (mKey) {
mManager->AddImageKeyForDiscard(mKey.value());
if (mTextureOfImage) {
WrBridge()->ReleaseTextureOfImage(mKey.value());
mTextureOfImage = nullptr;
// If we don't own the key, then the owner is responsible for discarding the
// key when appropriate.
if (mOwnsKey) {
mManager->AddImageKeyForDiscard(mKey.value());
if (mTextureOfImage) {
WrBridge()->ReleaseTextureOfImage(mKey.value());
mTextureOfImage = nullptr;
}
}
mKey.reset();
}
mOwnsKey = false;
MOZ_ASSERT(!mTextureOfImage);
}
@ -135,6 +151,26 @@ Maybe<wr::ImageKey> WebRenderImageData::UpdateImageKey(
mContainer = aContainer;
}
wr::WrImageKey key;
if (!aFallback) {
nsresult rv = SharedSurfacesChild::Share(aContainer, mManager, aResources,
key, kContainerProducerID_Invalid);
if (NS_SUCCEEDED(rv)) {
// Ensure that any previously owned keys are released before replacing. We
// don't own this key, the surface itself owns it, so that it can be
// shared across multiple elements.
ClearImageKey();
mKey = Some(key);
return mKey;
}
if (rv != NS_ERROR_NOT_IMPLEMENTED) {
// We should be using the shared surface but somehow sharing it failed.
ClearImageKey();
return Nothing();
}
}
CreateImageClientIfNeeded();
if (!mImageClient) {
return Nothing();
@ -175,13 +211,15 @@ Maybe<wr::ImageKey> WebRenderImageData::UpdateImageKey(
extId.ref(), mKey.ref(), currentTexture, /* aIsUpdate */ true);
} else {
ClearImageKey();
wr::WrImageKey key = WrBridge()->GetNextImageKey();
key = WrBridge()->GetNextImageKey();
aResources.PushExternalImageForTexture(extId.ref(), key, currentTexture,
/* aIsUpdate */ false);
mKey = Some(key);
}
mTextureOfImage = currentTexture;
mOwnsKey = true;
return mKey;
}
@ -243,43 +281,33 @@ void WebRenderImageData::CreateImageClientIfNeeded() {
}
}
WebRenderImageProviderData::WebRenderImageProviderData(
RenderRootStateManager* aManager, nsDisplayItem* aItem)
WebRenderBlobImageData::WebRenderBlobImageData(RenderRootStateManager* aManager,
nsDisplayItem* aItem)
: WebRenderUserData(aManager, aItem) {}
WebRenderImageProviderData::WebRenderImageProviderData(
RenderRootStateManager* aManager, uint32_t aDisplayItemKey,
nsIFrame* aFrame)
WebRenderBlobImageData::WebRenderBlobImageData(RenderRootStateManager* aManager,
uint32_t aDisplayItemKey,
nsIFrame* aFrame)
: WebRenderUserData(aManager, aDisplayItemKey, aFrame) {}
WebRenderImageProviderData::~WebRenderImageProviderData() = default;
Maybe<wr::BlobImageKey> WebRenderBlobImageData::UpdateImageKey(
ImageContainer* aContainer, wr::IpcResourceUpdateQueue& aResources) {
MOZ_ASSERT(aContainer);
Maybe<wr::ImageKey> WebRenderImageProviderData::UpdateImageKey(
WebRenderImageProvider* aProvider, wr::IpcResourceUpdateQueue& aResources) {
MOZ_ASSERT(aProvider);
if (mProvider != aProvider) {
mProvider = aProvider;
if (mContainer != aContainer) {
mContainer = aContainer;
}
wr::ImageKey key = {};
nsresult rv = mProvider->UpdateKey(mManager, aResources, key);
if (NS_FAILED(rv)) {
return Nothing();
}
return Some(key);
}
bool WebRenderImageProviderData::Invalidate(ImageProviderId aProviderId) const {
if (!aProviderId || mProvider->GetProviderId() != aProviderId) {
return false;
}
wr::ImageKey key = {};
wr::BlobImageKey key = {};
nsresult rv =
mProvider->UpdateKey(mManager, mManager->AsyncResourceUpdates(), key);
return NS_SUCCEEDED(rv);
SharedSurfacesChild::ShareBlob(aContainer, mManager, aResources, key);
if (NS_SUCCEEDED(rv)) {
mKey = Some(key);
} else {
mKey.reset();
}
return mKey;
}
WebRenderFallbackData::WebRenderFallbackData(RenderRootStateManager* aManager,

View File

@ -9,7 +9,6 @@
#include <vector>
#include "mozilla/webrender/WebRenderAPI.h"
#include "mozilla/image/WebRenderImageProvider.h"
#include "mozilla/layers/AnimationInfo.h"
#include "mozilla/dom/RemoteBrowser.h"
#include "mozilla/UniquePtr.h"
@ -45,7 +44,6 @@ class WebRenderCanvasData;
class WebRenderCanvasRenderer;
class WebRenderCanvasRendererAsync;
class WebRenderImageData;
class WebRenderImageProviderData;
class WebRenderFallbackData;
class WebRenderLocalCanvasData;
class RenderRootStateManager;
@ -71,7 +69,7 @@ class WebRenderUserData {
static bool SupportsAsyncUpdate(nsIFrame* aFrame);
static bool ProcessInvalidateForImage(nsIFrame* aFrame, DisplayItemType aType,
image::ImageProviderId aProviderId);
ContainerProducerID aProducerId);
NS_INLINE_DECL_REFCOUNTING(WebRenderUserData)
@ -80,7 +78,6 @@ class WebRenderUserData {
nsIFrame* aFrame);
virtual WebRenderImageData* AsImageData() { return nullptr; }
virtual WebRenderImageProviderData* AsImageProviderData() { return nullptr; }
virtual WebRenderFallbackData* AsFallbackData() { return nullptr; }
virtual WebRenderCanvasData* AsCanvasData() { return nullptr; }
virtual WebRenderLocalCanvasData* AsLocalCanvasData() { return nullptr; }
@ -96,7 +93,7 @@ class WebRenderUserData {
eRemote,
eGroup,
eMask,
eImageProvider, // ImageLib
eBlobImage, // SVG image
};
virtual UserDataType GetType() = 0;
@ -172,6 +169,8 @@ class WebRenderImageData : public WebRenderUserData {
bool IsAsync() { return mPipelineId.isSome(); }
bool UsingSharedSurface(ContainerProducerID aProducerId) const;
void ClearImageKey();
protected:
@ -180,29 +179,33 @@ class WebRenderImageData : public WebRenderUserData {
RefPtr<ImageClient> mImageClient;
Maybe<wr::PipelineId> mPipelineId;
RefPtr<ImageContainer> mContainer;
// The key can be owned by a shared surface that is used by several elements.
// when this is the case the shared surface is responsible for managing the
// destruction of the key.
// TODO: we surely can come up with a simpler/safer way to model this.
bool mOwnsKey;
};
/// Holds some data used to share ImageLib results with the parent process.
/// This may be either in the form of a blob recording or a rasterized surface.
class WebRenderImageProviderData final : public WebRenderUserData {
/// Holds some data used to share blob recordings from VectorImages with the
/// parent process.
class WebRenderBlobImageData : public WebRenderUserData {
public:
WebRenderImageProviderData(RenderRootStateManager* aManager,
nsDisplayItem* aItem);
WebRenderImageProviderData(RenderRootStateManager* aManager,
uint32_t aDisplayItemKey, nsIFrame* aFrame);
~WebRenderImageProviderData() override;
WebRenderBlobImageData(RenderRootStateManager* aManager,
nsDisplayItem* aItem);
WebRenderBlobImageData(RenderRootStateManager* aManager,
uint32_t aDisplayItemKey, nsIFrame* aFrame);
virtual ~WebRenderBlobImageData() {}
WebRenderImageProviderData* AsImageProviderData() override { return this; }
UserDataType GetType() override { return UserDataType::eImageProvider; }
static UserDataType Type() { return UserDataType::eImageProvider; }
UserDataType GetType() override { return UserDataType::eBlobImage; }
static UserDataType Type() { return UserDataType::eBlobImage; }
Maybe<wr::BlobImageKey> GetImageKey() { return mKey; }
Maybe<wr::ImageKey> UpdateImageKey(image::WebRenderImageProvider* aProvider,
wr::IpcResourceUpdateQueue& aResources);
bool Invalidate(image::ImageProviderId aProviderId) const;
Maybe<wr::BlobImageKey> UpdateImageKey(
ImageContainer* aContainer, wr::IpcResourceUpdateQueue& aResources);
protected:
RefPtr<image::WebRenderImageProvider> mProvider;
Maybe<wr::BlobImageKey> mKey;
RefPtr<ImageContainer> mContainer;
};
/// Used for fallback rendering.

View File

@ -60,7 +60,6 @@ bool AnimationFrameRetainedBuffer::ResetInternal() {
bool AnimationFrameRetainedBuffer::MarkComplete(
const gfx::IntRect& aFirstFrameRefreshArea) {
MOZ_ASSERT(!mSizeKnown);
mFirstFrameRefreshArea = aFirstFrameRefreshArea;
mSizeKnown = true;
mPending = 0;
mFrames.Compact();
@ -193,11 +192,6 @@ bool AnimationFrameDiscardingQueue::MarkComplete(
mPending = 0;
}
// If we encounter a redecode error, just make the first frame refresh area to
// be the full frame, because we don't really know what we can safely recycle.
mFirstFrameRefreshArea =
mRedecodeError ? mFirstFrame->GetRect() : aFirstFrameRefreshArea;
// We reached the end of the animation, the next frame we get, if we get
// another, will be the first frame again.
mInsertIndex = 0;
@ -467,5 +461,17 @@ RawAccessFrameRef AnimationFrameRecyclingQueue::RecycleFrame(
return recycledFrame;
}
bool AnimationFrameRecyclingQueue::MarkComplete(
const gfx::IntRect& aFirstFrameRefreshArea) {
bool continueDecoding =
AnimationFrameDiscardingQueue::MarkComplete(aFirstFrameRefreshArea);
// If we encounter a redecode error, just make the first frame refresh area to
// be the full frame, because we don't really know what we can safely recycle.
mFirstFrameRefreshArea =
mRedecodeError ? mFirstFrame->GetRect() : aFirstFrameRefreshArea;
return continueDecoding;
}
} // namespace image
} // namespace mozilla

View File

@ -103,14 +103,6 @@ class AnimationFrameBuffer {
*/
size_t Size() const { return mSize; }
/**
* @returns The first frame refresh area. This is used instead of the dirty
* rect for the last frame when transitioning back to the first frame.
*/
const gfx::IntRect& FirstFrameRefreshArea() const {
return mFirstFrameRefreshArea;
}
/**
* @returns True if encountered an error during redecode which should cause
* the caller to stop inserting frames.
@ -294,10 +286,6 @@ class AnimationFrameBuffer {
*/
virtual bool ResetInternal() = 0;
/// The first frame refresh area. This is used instead of the dirty rect for
/// the last frame when transitioning back to the first frame.
gfx::IntRect mFirstFrameRefreshArea;
// The total number of frames in the animation. If mSizeKnown is true, it is
// the actual total regardless of how many frames are available, otherwise it
// is the total number of inserted frames.
@ -432,6 +420,7 @@ class AnimationFrameRecyclingQueue final
public:
explicit AnimationFrameRecyclingQueue(AnimationFrameRetainedBuffer&& aQueue);
bool MarkComplete(const gfx::IntRect& aFirstFrameRefreshArea) override;
void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
const AddSizeOfCb& aCallback) override;
@ -458,6 +447,9 @@ class AnimationFrameRecyclingQueue final
};
const std::deque<RecycleEntry>& Recycle() const { return mRecycle; }
const gfx::IntRect& FirstFrameRefreshArea() const {
return mFirstFrameRefreshArea;
}
protected:
void AdvanceInternal() override;
@ -468,6 +460,10 @@ class AnimationFrameRecyclingQueue final
/// is adjacent to the first frame in the mDisplay queue.
std::deque<RecycleEntry> mRecycle;
/// The first frame refresh area. This is used instead of the dirty rect for
/// the last frame when transitioning back to the first frame.
gfx::IntRect mFirstFrameRefreshArea;
/// Force recycled frames to use the first frame refresh area as their dirty
/// rect. This is used when we are recycling frames from the end of an
/// animation to produce frames at the beginning of an animation.

View File

@ -7,15 +7,12 @@
#include "mozilla/StaticPrefs_image.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/layers/SharedSurfacesChild.h"
#include "mozilla/layers/SourceSurfaceSharedData.h"
#include "nsProxyRelease.h"
#include "DecodePool.h"
#include "Decoder.h"
using namespace mozilla::gfx;
using namespace mozilla::layers;
namespace mozilla {
namespace image {
@ -28,9 +25,7 @@ AnimationSurfaceProvider::AnimationSurfaceProvider(
mImage(aImage.get()),
mDecodingMutex("AnimationSurfaceProvider::mDecoder"),
mDecoder(aDecoder.get()),
mFramesMutex("AnimationSurfaceProvider::mFrames"),
mCompositedFrameRequested(false),
mSharedAnimation(MakeRefPtr<SharedSurfacesAnimation>()) {
mFramesMutex("AnimationSurfaceProvider::mFrames") {
MOZ_ASSERT(!mDecoder->IsMetadataDecode(),
"Use MetadataDecodingTask for metadata decodes");
MOZ_ASSERT(!mDecoder->IsFirstFrameDecode(),
@ -52,7 +47,6 @@ AnimationSurfaceProvider::AnimationSurfaceProvider(
AnimationSurfaceProvider::~AnimationSurfaceProvider() {
DropImageReference();
mSharedAnimation->Destroy();
if (mDecoder) {
mDecoder->SetFrameRecycler(nullptr);
}
@ -121,32 +115,15 @@ void AnimationSurfaceProvider::Reset() {
void AnimationSurfaceProvider::Advance(size_t aFrame) {
bool restartDecoder;
RefPtr<SourceSurface> surface;
IntRect dirtyRect;
{
// Typical advancement of a frame.
MutexAutoLock lock(mFramesMutex);
restartDecoder = mFrames->AdvanceTo(aFrame);
imgFrame* frame = mFrames->Get(aFrame, /* aForDisplay */ true);
MOZ_ASSERT(frame);
if (aFrame != 0) {
dirtyRect = frame->GetDirtyRect();
} else {
MOZ_ASSERT(mFrames->SizeKnown());
dirtyRect = mFrames->FirstFrameRefreshArea();
}
surface = frame->GetSourceSurface();
MOZ_ASSERT(surface);
}
if (restartDecoder) {
DecodePool::Singleton()->AsyncRun(this);
}
mCompositedFrameRequested = false;
auto* sharedSurface = static_cast<SourceSurfaceSharedData*>(surface.get());
mSharedAnimation->SetCurrentFrame(sharedSurface, dirtyRect);
}
DrawableFrameRef AnimationSurfaceProvider::DrawableRef(size_t aFrame) {
@ -508,27 +485,5 @@ RawAccessFrameRef AnimationSurfaceProvider::RecycleFrame(
return mFrames->RecycleFrame(aRecycleRect);
}
nsresult AnimationSurfaceProvider::UpdateKey(
layers::RenderRootStateManager* aManager,
wr::IpcResourceUpdateQueue& aResources, wr::ImageKey& aKey) {
MOZ_ASSERT(NS_IsMainThread());
RefPtr<SourceSurface> surface;
{
MutexAutoLock lock(mFramesMutex);
imgFrame* frame =
mFrames->Get(mFrames->Displayed(), /* aForDisplay */ true);
if (!frame) {
return NS_ERROR_NOT_AVAILABLE;
}
surface = frame->GetSourceSurface();
}
mCompositedFrameRequested = true;
auto* sharedSurface = static_cast<SourceSurfaceSharedData*>(surface.get());
return mSharedAnimation->UpdateKey(sharedSurface, aManager, aResources, aKey);
}
} // namespace image
} // namespace mozilla

View File

@ -19,10 +19,6 @@
#include "AnimationFrameBuffer.h"
namespace mozilla {
namespace layers {
class SharedSurfacesAnimation;
}
namespace image {
/**
@ -45,6 +41,12 @@ class AnimationSurfaceProvider final : public ISurfaceProvider,
//////////////////////////////////////////////////////////////////////////////
public:
// We use the ISurfaceProvider constructor of DrawableSurface to indicate that
// our surfaces are computed lazily.
DrawableSurface Surface() override {
return DrawableSurface(WrapNotNull(this));
}
bool IsFinished() const override;
bool IsFullyDecoded() const override;
size_t LogicalSizeInBytes() const override;
@ -52,8 +54,6 @@ class AnimationSurfaceProvider final : public ISurfaceProvider,
const AddSizeOfCb& aCallback) override;
void Reset() override;
void Advance(size_t aFrame) override;
bool MayAdvance() const override { return mCompositedFrameRequested; }
void MarkMayAdvance() override { mCompositedFrameRequested = true; }
protected:
DrawableFrameRef DrawableRef(size_t aFrame) override;
@ -86,15 +86,6 @@ class AnimationSurfaceProvider final : public ISurfaceProvider,
public:
RawAccessFrameRef RecycleFrame(gfx::IntRect& aRecycleRect) override;
//////////////////////////////////////////////////////////////////////////////
// IDecoderFrameRecycler implementation.
//////////////////////////////////////////////////////////////////////////////
public:
nsresult UpdateKey(layers::RenderRootStateManager* aManager,
wr::IpcResourceUpdateQueue& aResources,
wr::ImageKey& aKey) override;
private:
virtual ~AnimationSurfaceProvider();
@ -123,13 +114,6 @@ class AnimationSurfaceProvider final : public ISurfaceProvider,
/// The frames of this animation, in order.
UniquePtr<AnimationFrameBuffer> mFrames;
/// Whether the current frame was requested for display since the last time we
/// advanced the animation.
bool mCompositedFrameRequested;
///
RefPtr<layers::SharedSurfacesAnimation> mSharedAnimation;
};
} // namespace image

View File

@ -298,12 +298,12 @@ ClippedImage::IsImageContainerAvailable(WindowRenderer* aRenderer,
}
NS_IMETHODIMP_(ImgDrawResult)
ClippedImage::GetImageProvider(WindowRenderer* aRenderer,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion,
uint32_t aFlags,
WebRenderImageProvider** aProvider) {
ClippedImage::GetImageContainerAtSize(WindowRenderer* aRenderer,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion,
uint32_t aFlags,
layers::ImageContainer** aOutContainer) {
// XXX(seth): We currently don't have a way of clipping the result of
// GetImageContainer. We work around this by always returning null, but if it
// ever turns out that ClippedImage is widely used on codepaths that can
@ -311,8 +311,8 @@ ClippedImage::GetImageProvider(WindowRenderer* aRenderer,
// that method for performance reasons.
if (!ShouldClip()) {
return InnerImage()->GetImageProvider(aRenderer, aSize, aSVGContext,
aRegion, aFlags, aProvider);
return InnerImage()->GetImageContainerAtSize(
aRenderer, aSize, aSVGContext, aRegion, aFlags, aOutContainer);
}
return ImgDrawResult::NOT_SUPPORTED;

View File

@ -46,10 +46,10 @@ class ClippedImage : public ImageWrapper {
IsImageContainerAvailable(WindowRenderer* aRenderer,
uint32_t aFlags) override;
NS_IMETHOD_(ImgDrawResult)
GetImageProvider(WindowRenderer* aRenderer, const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion, uint32_t aFlags,
WebRenderImageProvider** aProvider) override;
GetImageContainerAtSize(WindowRenderer* aRenderer, const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion, uint32_t aFlags,
layers::ImageContainer** aOutContainer) override;
NS_IMETHOD_(ImgDrawResult)
Draw(gfxContext* aContext, const nsIntSize& aSize, const ImageRegion& aRegion,
uint32_t aWhichFrame, gfx::SamplingFilter aSamplingFilter,

View File

@ -6,13 +6,11 @@
#include "DecodedSurfaceProvider.h"
#include "mozilla/StaticPrefs_image.h"
#include "mozilla/layers/SharedSurfacesChild.h"
#include "nsProxyRelease.h"
#include "Decoder.h"
using namespace mozilla::gfx;
using namespace mozilla::layers;
namespace mozilla {
namespace image {
@ -207,28 +205,5 @@ bool DecodedSurfaceProvider::ShouldPreferSyncRun() const {
StaticPrefs::image_mem_decode_bytes_at_a_time_AtStartup());
}
nsresult DecodedSurfaceProvider::UpdateKey(
layers::RenderRootStateManager* aManager,
wr::IpcResourceUpdateQueue& aResources, wr::ImageKey& aKey) {
MOZ_ASSERT(mSurface);
RefPtr<SourceSurface> surface = mSurface->GetSourceSurface();
if (!surface) {
return NS_ERROR_FAILURE;
}
return SharedSurfacesChild::Share(surface, aManager, aResources, aKey);
}
nsresult SimpleSurfaceProvider::UpdateKey(
layers::RenderRootStateManager* aManager,
wr::IpcResourceUpdateQueue& aResources, wr::ImageKey& aKey) {
RefPtr<SourceSurface> surface = mSurface->GetSourceSurface();
if (!surface) {
return NS_ERROR_FAILURE;
}
return SharedSurfacesChild::Share(surface, aManager, aResources, aKey);
}
} // namespace image
} // namespace mozilla

View File

@ -55,15 +55,6 @@ class DecodedSurfaceProvider final : public ISurfaceProvider,
// don't block layout or page load.
TaskPriority Priority() const override { return TaskPriority::eLow; }
//////////////////////////////////////////////////////////////////////////////
// WebRenderImageProvider implementation.
//////////////////////////////////////////////////////////////////////////////
public:
nsresult UpdateKey(layers::RenderRootStateManager* aManager,
wr::IpcResourceUpdateQueue& aResources,
wr::ImageKey& aKey) override;
private:
virtual ~DecodedSurfaceProvider();

View File

@ -123,7 +123,7 @@ DynamicImage::GetType(uint16_t* aType) {
}
NS_IMETHODIMP
DynamicImage::GetProviderId(uint32_t* aId) {
DynamicImage::GetProducerId(uint32_t* aId) {
*aId = 0;
return NS_OK;
}
@ -170,12 +170,12 @@ DynamicImage::IsImageContainerAvailable(WindowRenderer* aRenderer,
}
NS_IMETHODIMP_(ImgDrawResult)
DynamicImage::GetImageProvider(WindowRenderer* aRenderer,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion,
uint32_t aFlags,
WebRenderImageProvider** aProvider) {
DynamicImage::GetImageContainerAtSize(WindowRenderer* aRenderer,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion,
uint32_t aFlags,
layers::ImageContainer** aContainer) {
return ImgDrawResult::NOT_SUPPORTED;
}

View File

@ -318,6 +318,7 @@ RefreshResult FrameAnimator::AdvanceFrame(AnimationState& aState,
// Set currentAnimationFrameIndex at the last possible moment
aState.mCurrentAnimationFrameIndex = nextFrameIndex;
aState.mCompositedFrameRequested = false;
aCurrentFrame = std::move(nextFrame);
aFrames.Advance(nextFrameIndex);
@ -394,7 +395,7 @@ RefreshResult FrameAnimator::RequestRefresh(AnimationState& aState,
// If nothing has accessed the composited frame since the last time we
// advanced, then there is no point in continuing to advance the animation.
// This has the effect of freezing the animation while not in view.
if (!result.Surface().MayAdvance() &&
if (!aState.mCompositedFrameRequested &&
aState.MaybeAdvanceAnimationFrameTime(aTime)) {
return ret;
}
@ -442,18 +443,13 @@ RefreshResult FrameAnimator::RequestRefresh(AnimationState& aState,
LookupResult FrameAnimator::GetCompositedFrame(AnimationState& aState,
bool aMarkUsed) {
aState.mCompositedFrameRequested = true;
LookupResult result = SurfaceCache::Lookup(
ImageKey(mImage),
RasterSurfaceKey(mSize, DefaultSurfaceFlags(), PlaybackType::eAnimated),
aMarkUsed);
if (result) {
// If we are getting the frame directly (e.g. through tests or canvas), we
// need to ensure the animation is marked to allow advancing to the next
// frame.
result.Surface().MarkMayAdvance();
}
if (aState.mCompositedFrameInvalid) {
MOZ_ASSERT(StaticPrefs::image_mem_animated_discardable_AtStartup());
MOZ_ASSERT(aState.GetHasRequestedDecode());

View File

@ -35,6 +35,7 @@ class AnimationState {
mHasRequestedDecode(false),
mIsCurrentlyDecoded(false),
mCompositedFrameInvalid(false),
mCompositedFrameRequested(false),
mDiscarded(false) {}
/**
@ -239,6 +240,10 @@ class AnimationState {
//! valid to draw to the screen.
bool mCompositedFrameInvalid;
//! Whether the composited frame was requested from the animator since the
//! last time we advanced the animation.
bool mCompositedFrameRequested;
//! Whether this image is currently discarded. Only set to true after the
//! image has been decoded at least once.
bool mDiscarded;

View File

@ -60,15 +60,15 @@ FrozenImage::IsImageContainerAvailable(WindowRenderer* aRenderer,
}
NS_IMETHODIMP_(ImgDrawResult)
FrozenImage::GetImageProvider(WindowRenderer* aRenderer,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion,
uint32_t aFlags,
WebRenderImageProvider** aProvider) {
FrozenImage::GetImageContainerAtSize(WindowRenderer* aRenderer,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion,
uint32_t aFlags,
layers::ImageContainer** aOutContainer) {
if (IsNonAnimated()) {
return InnerImage()->GetImageProvider(aRenderer, aSize, aSVGContext,
aRegion, aFlags, aProvider);
return InnerImage()->GetImageContainerAtSize(
aRenderer, aSize, aSVGContext, aRegion, aFlags, aOutContainer);
}
// XXX(seth): GetImageContainer does not currently support anything but the

View File

@ -45,10 +45,10 @@ class FrozenImage : public ImageWrapper {
IsImageContainerAvailable(WindowRenderer* aRenderer,
uint32_t aFlags) override;
NS_IMETHOD_(ImgDrawResult)
GetImageProvider(WindowRenderer* aRenderer, const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion, uint32_t aFlags,
WebRenderImageProvider** aProvider) override;
GetImageContainerAtSize(WindowRenderer* aRenderer, const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion, uint32_t aFlags,
layers::ImageContainer** aOutContainer) override;
NS_IMETHOD_(ImgDrawResult)
Draw(gfxContext* aContext, const nsIntSize& aSize, const ImageRegion& aRegion,
uint32_t aWhichFrame, gfx::SamplingFilter aSamplingFilter,

View File

@ -17,7 +17,6 @@
#include "mozilla/NotNull.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/image/WebRenderImageProvider.h"
#include "imgFrame.h"
#include "SurfaceCache.h"
@ -32,7 +31,7 @@ class DrawableSurface;
* An interface for objects which can either store a surface or dynamically
* generate one.
*/
class ISurfaceProvider : public WebRenderImageProvider {
class ISurfaceProvider {
public:
// Subclasses may or may not be XPCOM classes, so we just require that they
// implement AddRef and Release.
@ -46,8 +45,8 @@ class ISurfaceProvider : public WebRenderImageProvider {
/// entry in the surface cache.
const SurfaceKey& GetSurfaceKey() const { return mSurfaceKey; }
/// @return a drawable reference to a surface.
DrawableSurface Surface();
/// @return a (potentially lazily computed) drawable reference to a surface.
virtual DrawableSurface Surface();
/// @return true if DrawableRef() will return a completely decoded surface.
virtual bool IsFinished() const = 0;
@ -82,8 +81,6 @@ class ISurfaceProvider : public WebRenderImageProvider {
virtual void Reset() {}
virtual void Advance(size_t aFrame) {}
virtual bool MayAdvance() const { return false; }
virtual void MarkMayAdvance() {}
/// @return the availability state of this ISurfaceProvider, which indicates
/// whether DrawableRef() could successfully return a surface. Should only be
@ -95,8 +92,7 @@ class ISurfaceProvider : public WebRenderImageProvider {
protected:
ISurfaceProvider(const ImageKey aImageKey, const SurfaceKey& aSurfaceKey,
AvailabilityState aAvailability)
: WebRenderImageProvider(aImageKey),
mImageKey(aImageKey),
: mImageKey(aImageKey),
mSurfaceKey(aSurfaceKey),
mAvailability(aAvailability) {
MOZ_ASSERT(aImageKey, "Must have a valid image key");
@ -149,6 +145,10 @@ class MOZ_STACK_CLASS DrawableSurface final {
public:
DrawableSurface() : mHaveSurface(false) {}
explicit DrawableSurface(DrawableFrameRef&& aDrawableRef)
: mDrawableRef(std::move(aDrawableRef)),
mHaveSurface(bool(mDrawableRef)) {}
explicit DrawableSurface(NotNull<ISurfaceProvider*> aProvider)
: mProvider(aProvider), mHaveSurface(true) {}
@ -222,24 +222,6 @@ class MOZ_STACK_CLASS DrawableSurface final {
mProvider->Advance(aFrame);
}
bool MayAdvance() const {
if (!mProvider) {
MOZ_ASSERT_UNREACHABLE("Trying to advance a static DrawableSurface?");
return false;
}
return mProvider->MayAdvance();
}
void MarkMayAdvance() {
if (!mProvider) {
MOZ_ASSERT_UNREACHABLE("Trying to advance a static DrawableSurface?");
return;
}
mProvider->MarkMayAdvance();
}
bool IsFullyDecoded() const {
if (!mProvider) {
MOZ_ASSERT_UNREACHABLE(
@ -250,10 +232,6 @@ class MOZ_STACK_CLASS DrawableSurface final {
return mProvider->IsFullyDecoded();
}
void TakeProvider(WebRenderImageProvider** aOutProvider) {
mProvider.forget(aOutProvider);
}
explicit operator bool() const { return mHaveSurface; }
imgFrame* operator->() { return DrawableRef().get(); }
@ -283,9 +261,10 @@ class MOZ_STACK_CLASS DrawableSurface final {
};
// Surface() is implemented here so that DrawableSurface's definition is
// visible.
// visible. This default implementation eagerly obtains a DrawableFrameRef for
// the first frame and is intended for static ISurfaceProviders.
inline DrawableSurface ISurfaceProvider::Surface() {
return DrawableSurface(WrapNotNull(this));
return DrawableSurface(DrawableRef(/* aFrame = */ 0));
}
/**
@ -310,10 +289,6 @@ class SimpleSurfaceProvider final : public ISurfaceProvider {
return size.width * size.height * mSurface->GetBytesPerPixel();
}
nsresult UpdateKey(layers::RenderRootStateManager* aManager,
wr::IpcResourceUpdateQueue& aResources,
wr::ImageKey& aKey) override;
protected:
DrawableFrameRef DrawableRef(size_t aFrame) override {
MOZ_ASSERT(aFrame == 0,

View File

@ -7,11 +7,9 @@
#include "imgRequest.h"
#include "Layers.h" // for LayerManager
#include "WebRenderImageProvider.h"
#include "nsIObserverService.h"
#include "nsRefreshDriver.h"
#include "nsContentUtils.h"
#include "mozilla/Atomics.h"
#include "mozilla/gfx/Point.h"
#include "mozilla/gfx/Rect.h"
#include "mozilla/gfx/SourceSurfaceRawData.h"
@ -20,19 +18,11 @@
#include "mozilla/TimeStamp.h"
#include "mozilla/Tuple.h" // for Tie
#include "mozilla/layers/SharedSurfacesChild.h"
#include "SourceSurfaceBlobImage.h"
namespace mozilla {
namespace image {
WebRenderImageProvider::WebRenderImageProvider(const ImageResource* aImage)
: mProviderId(aImage->GetImageProviderId()) {}
/* static */ ImageProviderId WebRenderImageProvider::AllocateProviderId() {
// Callable on all threads.
static Atomic<ImageProviderId> sProviderId(0u);
return ++sProviderId;
}
///////////////////////////////////////////////////////////////////////////////
// Memory Reporting
///////////////////////////////////////////////////////////////////////////////
@ -120,10 +110,329 @@ bool ImageResource::GetSpecTruncatedTo1k(nsCString& aSpec) const {
return false;
}
void ImageResource::SetCurrentImage(layers::ImageContainer* aContainer,
gfx::SourceSurface* aSurface,
const Maybe<gfx::IntRect>& aDirtyRect) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aContainer);
if (!aSurface) {
// The OS threw out some or all of our buffer. We'll need to wait for the
// redecode (which was automatically triggered by GetFrame) to complete.
return;
}
// |image| holds a reference to a SourceSurface which in turn holds a lock on
// the current frame's data buffer, ensuring that it doesn't get freed as
// long as the layer system keeps this ImageContainer alive.
RefPtr<layers::Image> image = new layers::SourceSurfaceImage(aSurface);
// We can share the producer ID with other containers because it is only
// used internally to validate the frames given to a particular container
// so that another object cannot add its own. Similarly the frame ID is
// only used internally to ensure it is always increasing, and skipping
// IDs from an individual container's perspective is acceptable.
AutoTArray<layers::ImageContainer::NonOwningImage, 1> imageList;
imageList.AppendElement(layers::ImageContainer::NonOwningImage(
image, TimeStamp(), mLastFrameID++, mImageProducerID));
if (aDirtyRect) {
aContainer->SetCurrentImagesInTransaction(imageList);
} else {
aContainer->SetCurrentImages(imageList);
}
// If we are animated, then we should request that the image container be
// treated as such, to avoid display list rebuilding to update frames for
// WebRender.
if (mProgressTracker->GetProgress() & FLAG_IS_ANIMATED) {
if (aDirtyRect) {
layers::SharedSurfacesChild::UpdateAnimation(aContainer, aSurface,
aDirtyRect.ref());
} else {
gfx::IntRect dirtyRect(gfx::IntPoint(0, 0), aSurface->GetSize());
layers::SharedSurfacesChild::UpdateAnimation(aContainer, aSurface,
dirtyRect);
}
}
}
ImgDrawResult ImageResource::GetImageContainerImpl(
WindowRenderer* aRenderer, const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion, uint32_t aFlags,
layers::ImageContainer** aOutContainer) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aRenderer);
MOZ_ASSERT((aFlags &
~(FLAG_SYNC_DECODE | FLAG_SYNC_DECODE_IF_FAST | FLAG_RECORD_BLOB |
FLAG_ASYNC_NOTIFY | FLAG_HIGH_QUALITY_SCALING)) == FLAG_NONE,
"Unsupported flag passed to GetImageContainer");
ImgDrawResult drawResult;
gfx::IntSize size;
Tie(drawResult, size) = GetImageContainerSize(aRenderer, aSize, aFlags);
if (drawResult != ImgDrawResult::SUCCESS) {
return drawResult;
}
MOZ_ASSERT(!size.IsEmpty());
if (mAnimationConsumers == 0) {
SendOnUnlockedDraw(aFlags);
}
uint32_t flags = (aFlags & ~(FLAG_SYNC_DECODE | FLAG_SYNC_DECODE_IF_FAST)) |
FLAG_ASYNC_NOTIFY;
RefPtr<layers::ImageContainer> container;
ImageContainerEntry* entry = nullptr;
int i = mImageContainers.Length() - 1;
for (; i >= 0; --i) {
entry = &mImageContainers[i];
if (size == entry->mSize && flags == entry->mFlags &&
aSVGContext == entry->mSVGContext && aRegion == entry->mRegion) {
// Lack of a container is handled below.
container = RefPtr<layers::ImageContainer>(entry->mContainer);
break;
} else if (entry->mContainer.IsDead()) {
// Stop tracking if our weak pointer to the image container was freed.
mImageContainers.RemoveElementAt(i);
}
}
if (container) {
switch (entry->mLastDrawResult) {
case ImgDrawResult::SUCCESS:
case ImgDrawResult::BAD_IMAGE:
case ImgDrawResult::BAD_ARGS:
case ImgDrawResult::NOT_SUPPORTED:
container.forget(aOutContainer);
return entry->mLastDrawResult;
case ImgDrawResult::NOT_READY:
case ImgDrawResult::INCOMPLETE:
case ImgDrawResult::TEMPORARY_ERROR:
// Temporary conditions where we need to rerequest the frame to recover.
break;
case ImgDrawResult::WRONG_SIZE:
// Unused by GetFrameInternal
default:
MOZ_ASSERT_UNREACHABLE("Unhandled ImgDrawResult type!");
container.forget(aOutContainer);
return entry->mLastDrawResult;
}
}
AutoProfilerImagePaintMarker PROFILER_RAII(this);
#ifdef DEBUG
NotifyDrawingObservers();
#endif
gfx::IntSize bestSize;
RefPtr<gfx::SourceSurface> surface;
Tie(drawResult, bestSize, surface) = GetFrameInternal(
size, aSVGContext, aRegion, FRAME_CURRENT, aFlags | FLAG_ASYNC_NOTIFY);
// The requested size might be refused by the surface cache (i.e. due to
// factor-of-2 mode). In that case we don't want to create an entry for this
// specific size, but rather re-use the entry for the substituted size.
if (bestSize != size) {
MOZ_ASSERT(!bestSize.IsEmpty());
// We can only remove the entry if we no longer have a container, because if
// there are strong references to it remaining, we need to still update it
// in UpdateImageContainer.
if (i >= 0 && !container) {
mImageContainers.RemoveElementAt(i);
}
// Forget about the stale container, if any. This lets the entry creation
// logic do its job below, if it turns out there is no existing best entry
// or the best entry doesn't have a container.
container = nullptr;
// We need to do the entry search again for the new size. We skip pruning
// because we did this above once already, but ImageContainer is threadsafe,
// so there is a remote possibility it got freed.
i = mImageContainers.Length() - 1;
for (; i >= 0; --i) {
entry = &mImageContainers[i];
if (bestSize == entry->mSize && flags == entry->mFlags &&
aSVGContext == entry->mSVGContext && aRegion == entry->mRegion) {
container = RefPtr<layers::ImageContainer>(entry->mContainer);
if (container) {
switch (entry->mLastDrawResult) {
case ImgDrawResult::SUCCESS:
case ImgDrawResult::BAD_IMAGE:
case ImgDrawResult::BAD_ARGS:
case ImgDrawResult::NOT_SUPPORTED:
container.forget(aOutContainer);
return entry->mLastDrawResult;
case ImgDrawResult::NOT_READY:
case ImgDrawResult::INCOMPLETE:
case ImgDrawResult::TEMPORARY_ERROR:
// Temporary conditions where we need to rerequest the frame to
// recover. We have already done so!
break;
case ImgDrawResult::WRONG_SIZE:
// Unused by GetFrameInternal
default:
MOZ_ASSERT_UNREACHABLE("Unhandled DrawResult type!");
container.forget(aOutContainer);
return entry->mLastDrawResult;
}
}
break;
}
}
}
if (!container) {
// We need a new ImageContainer, so create one.
container = MakeAndAddRef<layers::ImageContainer>();
if (i >= 0) {
entry->mContainer = container;
} else {
entry = mImageContainers.AppendElement(ImageContainerEntry(
bestSize, aSVGContext, aRegion, container.get(), flags));
}
}
SetCurrentImage(container, surface, Nothing());
entry->mLastDrawResult = drawResult;
container.forget(aOutContainer);
return drawResult;
}
bool ImageResource::UpdateImageContainer(
const Maybe<gfx::IntRect>& aDirtyRect) {
MOZ_ASSERT(NS_IsMainThread());
for (int i = mImageContainers.Length() - 1; i >= 0; --i) {
ImageContainerEntry& entry = mImageContainers[i];
RefPtr<layers::ImageContainer> container(entry.mContainer);
if (container) {
// Blob recordings should just be marked as dirty. We will regenerate the
// recording when the display list update comes around.
if (entry.mFlags & FLAG_RECORD_BLOB) {
AutoTArray<layers::ImageContainer::OwningImage, 1> images;
container->GetCurrentImages(&images);
if (images.IsEmpty()) {
MOZ_ASSERT_UNREACHABLE("Empty container!");
continue;
}
RefPtr<gfx::SourceSurface> surface =
images[0].mImage->GetAsSourceSurface();
if (!surface || surface->GetType() != gfx::SurfaceType::BLOB_IMAGE) {
MOZ_ASSERT_UNREACHABLE("No/wrong surface in container!");
continue;
}
static_cast<SourceSurfaceBlobImage*>(surface.get())->MarkDirty();
continue;
}
gfx::IntSize bestSize;
RefPtr<gfx::SourceSurface> surface;
Tie(entry.mLastDrawResult, bestSize, surface) =
GetFrameInternal(entry.mSize, entry.mSVGContext, entry.mRegion,
FRAME_CURRENT, entry.mFlags);
// It is possible that this is a factor-of-2 substitution. Since we
// managed to convert the weak reference into a strong reference, that
// means that an imagelib user still is holding onto the container. thus
// we cannot consolidate and must keep updating the duplicate container.
if (aDirtyRect) {
SetCurrentImage(container, surface, aDirtyRect);
} else {
gfx::IntRect dirtyRect(gfx::IntPoint(0, 0), bestSize);
SetCurrentImage(container, surface, Some(dirtyRect));
}
} else {
// Stop tracking if our weak pointer to the image container was freed.
mImageContainers.RemoveElementAt(i);
}
}
return !mImageContainers.IsEmpty();
}
void ImageResource::CollectSizeOfSurfaces(
nsTArray<SurfaceMemoryCounter>& aCounters,
MallocSizeOf aMallocSizeOf) const {
SurfaceCache::CollectSizeOfSurfaces(ImageKey(this), aCounters, aMallocSizeOf);
MOZ_ASSERT(NS_IsMainThread());
for (const auto& entry : mImageContainers) {
RefPtr<layers::ImageContainer> container(entry.mContainer);
if (!container) {
continue;
}
AutoTArray<layers::ImageContainer::OwningImage, 1> images;
container->GetCurrentImages(&images);
if (images.IsEmpty()) {
continue;
}
RefPtr<gfx::SourceSurface> surface = images[0].mImage->GetAsSourceSurface();
if (!surface) {
MOZ_ASSERT_UNREACHABLE("No surface in container!");
continue;
}
// The surface might be wrapping another.
bool isMappedSurface = surface->GetType() == gfx::SurfaceType::DATA_MAPPED;
const gfx::SourceSurface* actualSurface =
isMappedSurface
? static_cast<gfx::SourceSurfaceMappedData*>(surface.get())
->GetScopedSurface()
: surface.get();
// Check if the surface is already in the report. Ignore if so.
bool found = false;
for (const auto& counter : aCounters) {
if (counter.Surface() == actualSurface) {
found = true;
break;
}
}
if (found) {
continue;
}
// The surface isn't in the report, so it isn't stored in SurfaceCache. We
// need to add our own entry here so that it will be included in the memory
// report.
gfx::SourceSurface::SizeOfInfo info;
surface->SizeOfExcludingThis(aMallocSizeOf, info);
uint32_t heapBytes = aMallocSizeOf(actualSurface);
if (isMappedSurface) {
heapBytes += aMallocSizeOf(surface.get());
}
SurfaceKey key = ContainerSurfaceKey(surface->GetSize(), entry.mSVGContext,
ToSurfaceFlags(entry.mFlags));
SurfaceMemoryCounter counter(key, actualSurface, /* aIsLocked */ false,
/* aCannotSubstitute */ false,
/* aIsFactor2 */ false, /* aFinished */ true,
SurfaceMemoryCounterType::CONTAINER);
counter.Values().SetDecodedHeap(info.mHeapBytes + heapBytes);
counter.Values().SetDecodedNonHeap(info.mNonHeapBytes);
counter.Values().SetDecodedUnknown(info.mUnknownBytes);
counter.Values().SetExternalHandles(info.mExternalHandles);
counter.Values().SetExternalId(info.mExternalId);
counter.Values().SetSurfaceTypes(info.mTypes);
aCounters.AppendElement(counter);
}
}
void ImageResource::ReleaseImageContainer() {
MOZ_ASSERT(NS_IsMainThread());
mImageContainers.Clear();
}
// Constructor
@ -135,7 +444,8 @@ ImageResource::ImageResource(nsIURI* aURI)
mInitialized(false),
mAnimating(false),
mError(false),
mProviderId(WebRenderImageProvider::AllocateProviderId()) {}
mImageProducerID(layers::ImageContainer::AllocateProducerID()),
mLastFrameID(0) {}
ImageResource::~ImageResource() {
// Ask our ProgressTracker to drop its weak reference to us.

View File

@ -22,7 +22,6 @@
#include "nsStringFwd.h"
#include "ProgressTracker.h"
#include "SurfaceCache.h"
#include "WebRenderImageProvider.h"
class imgRequest;
class nsIRequest;
@ -90,10 +89,11 @@ enum class SurfaceMemoryCounterType { NORMAL, CONTAINER };
struct SurfaceMemoryCounter {
SurfaceMemoryCounter(
const SurfaceKey& aKey, bool aIsLocked, bool aCannotSubstitute,
bool aIsFactor2, bool aFinished,
const SurfaceKey& aKey, const gfx::SourceSurface* aSurface,
bool aIsLocked, bool aCannotSubstitute, bool aIsFactor2, bool aFinished,
SurfaceMemoryCounterType aType = SurfaceMemoryCounterType::NORMAL)
: mKey(aKey),
mSurface(aSurface),
mType(aType),
mIsLocked(aIsLocked),
mCannotSubstitute(aCannotSubstitute),
@ -101,6 +101,7 @@ struct SurfaceMemoryCounter {
mFinished(aFinished) {}
const SurfaceKey& Key() const { return mKey; }
const gfx::SourceSurface* Surface() const { return mSurface; }
MemoryCounter& Values() { return mValues; }
const MemoryCounter& Values() const { return mValues; }
SurfaceMemoryCounterType Type() const { return mType; }
@ -111,6 +112,7 @@ struct SurfaceMemoryCounter {
private:
const SurfaceKey mKey;
const gfx::SourceSurface* MOZ_NON_OWNING_REF mSurface;
MemoryCounter mValues;
const SurfaceMemoryCounterType mType;
const bool mIsLocked;
@ -329,12 +331,14 @@ class ImageResource : public Image {
void CollectSizeOfSurfaces(nsTArray<SurfaceMemoryCounter>& aCounters,
MallocSizeOf aMallocSizeOf) const override;
ImageProviderId GetImageProviderId() const { return mProviderId; }
protected:
explicit ImageResource(nsIURI* aURI);
~ImageResource();
layers::ContainerProducerID GetImageProducerId() const {
return mImageProducerID;
}
bool GetSpecTruncatedTo1k(nsCString& aSpec) const;
// Shared functionality for implementors of imgIContainer. Every
@ -388,6 +392,60 @@ class ImageResource : public Image {
bool mAnimating : 1; // Are we currently animating?
bool mError : 1; // Error handling
/**
* Attempt to find a matching cached surface in the SurfaceCache, and if not
* available, request the production of such a surface (either synchronously
* or asynchronously).
*
* If the draw result is BAD_IMAGE, BAD_ARGS or NOT_READY, the size will be
* the same as aSize. If it is TEMPORARY_ERROR, INCOMPLETE, or SUCCESS, the
* size is a hint as to what we expect the surface size to be, once the best
* fitting size is available. It may or may not match the size of the surface
* returned at this moment. This is useful for choosing how to store the final
* result (e.g. if going into an ImageContainer, ideally we would share the
* same container for many requested sizes, if they all end up with the same
* best fit size in the end).
*
* A valid surface should only be returned for SUCCESS and INCOMPLETE.
*
* Any other draw result is invalid.
*/
virtual Tuple<ImgDrawResult, gfx::IntSize, RefPtr<gfx::SourceSurface>>
GetFrameInternal(const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion, uint32_t aWhichFrame,
uint32_t aFlags) {
return MakeTuple(ImgDrawResult::BAD_IMAGE, aSize,
RefPtr<gfx::SourceSurface>());
}
/**
* Calculate the estimated size to use for an image container with the given
* parameters. It may not be the same as the given size, and it may not be
* the same as the size of the surface in the image container, but it is the
* best effort estimate.
*/
virtual Tuple<ImgDrawResult, gfx::IntSize> GetImageContainerSize(
WindowRenderer* aRenderer, const gfx::IntSize& aSize, uint32_t aFlags) {
return MakeTuple(ImgDrawResult::NOT_SUPPORTED, gfx::IntSize(0, 0));
}
ImgDrawResult GetImageContainerImpl(WindowRenderer* aRenderer,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion,
uint32_t aFlags,
layers::ImageContainer** aContainer);
/**
* Re-requests the appropriate frames for each image container using
* GetFrameInternal.
* @returns True if any image containers were updated, else false.
*/
bool UpdateImageContainer(const Maybe<gfx::IntRect>& aDirtyRect);
void ReleaseImageContainer();
class MOZ_RAII AutoProfilerImagePaintMarker {
public:
explicit AutoProfilerImagePaintMarker(ImageResource* self)
@ -416,7 +474,39 @@ class ImageResource : public Image {
};
private:
ImageProviderId mProviderId;
void SetCurrentImage(layers::ImageContainer* aContainer,
gfx::SourceSurface* aSurface,
const Maybe<gfx::IntRect>& aDirtyRect);
struct ImageContainerEntry {
ImageContainerEntry(const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion,
layers::ImageContainer* aContainer, uint32_t aFlags)
: mSize(aSize),
mSVGContext(aSVGContext),
mRegion(aRegion),
mContainer(aContainer),
mLastDrawResult(ImgDrawResult::NOT_READY),
mFlags(aFlags) {}
gfx::IntSize mSize;
Maybe<SVGImageContext> mSVGContext;
Maybe<ImageIntRegion> mRegion;
// A weak pointer to our ImageContainer, which stays alive only as long as
// the layer system needs it.
ThreadSafeWeakPtr<layers::ImageContainer> mContainer;
// If mContainer is non-null, this contains the ImgDrawResult we obtained
// the last time we updated it.
ImgDrawResult mLastDrawResult;
// Cached flags to use for decoding. FLAG_ASYNC_NOTIFY should always be set
// but FLAG_HIGH_QUALITY_SCALING may vary.
uint32_t mFlags;
};
AutoTArray<ImageContainerEntry, 1> mImageContainers;
layers::ImageContainer::ProducerID mImageProducerID;
layers::ImageContainer::FrameID mLastFrameID;
};
} // namespace image

View File

@ -13,7 +13,6 @@
#include "mozilla/gfx/Matrix.h"
#include "mozilla/gfx/Types.h"
#include "nsSize.h"
#include "PLDHashTable.h" // for PLDHashNumber
namespace mozilla {
namespace image {
@ -240,12 +239,6 @@ class ImageIntRegion {
(!mIsRestricted || mRestriction.IsEqualEdges(aOther.mRestriction));
}
PLDHashNumber Hash() const {
return HashGeneric(mRect.x, mRect.y, mRect.width, mRect.height,
mRestriction.x, mRestriction.y, mRestriction.width,
mRestriction.height, mExtendMode, mIsRestricted);
}
/* ImageIntRegion() : mIsRestricted(false) { } */
private:

View File

@ -141,8 +141,8 @@ NS_IMETHODIMP
ImageWrapper::GetType(uint16_t* aType) { return mInnerImage->GetType(aType); }
NS_IMETHODIMP
ImageWrapper::GetProviderId(uint32_t* aId) {
return mInnerImage->GetProviderId(aId);
ImageWrapper::GetProducerId(uint32_t* aId) {
return mInnerImage->GetProducerId(aId);
}
NS_IMETHODIMP
@ -171,14 +171,14 @@ ImageWrapper::IsImageContainerAvailable(WindowRenderer* aRenderer,
}
NS_IMETHODIMP_(ImgDrawResult)
ImageWrapper::GetImageProvider(WindowRenderer* aRenderer,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion,
uint32_t aFlags,
WebRenderImageProvider** aProvider) {
return mInnerImage->GetImageProvider(aRenderer, aSize, aSVGContext, aRegion,
aFlags, aProvider);
ImageWrapper::GetImageContainerAtSize(WindowRenderer* aRenderer,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion,
uint32_t aFlags,
layers::ImageContainer** aOutContainer) {
return mInnerImage->GetImageContainerAtSize(aRenderer, aSize, aSVGContext,
aRegion, aFlags, aOutContainer);
}
NS_IMETHODIMP_(ImgDrawResult)

View File

@ -156,12 +156,11 @@ OrientedImage::IsImageContainerAvailable(WindowRenderer* aRenderer,
}
NS_IMETHODIMP_(ImgDrawResult)
OrientedImage::GetImageProvider(WindowRenderer* aRenderer,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion,
uint32_t aFlags,
WebRenderImageProvider** aProvider) {
OrientedImage::GetImageContainerAtSize(
WindowRenderer* aRenderer, const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion, uint32_t aFlags,
layers::ImageContainer** aOutContainer) {
// XXX(seth): We currently don't have a way of orienting the result of
// GetImageContainer. We work around this by always returning null, but if it
// ever turns out that OrientedImage is widely used on codepaths that can
@ -169,8 +168,8 @@ OrientedImage::GetImageProvider(WindowRenderer* aRenderer,
// that method for performance reasons.
if (mOrientation.IsIdentity()) {
return InnerImage()->GetImageProvider(aRenderer, aSize, aSVGContext,
aRegion, aFlags, aProvider);
return InnerImage()->GetImageContainerAtSize(
aRenderer, aSize, aSVGContext, aRegion, aFlags, aOutContainer);
}
return ImgDrawResult::NOT_SUPPORTED;

View File

@ -41,10 +41,10 @@ class OrientedImage : public ImageWrapper {
IsImageContainerAvailable(WindowRenderer* aRenderer,
uint32_t aFlags) override;
NS_IMETHOD_(ImgDrawResult)
GetImageProvider(WindowRenderer* aRenderer, const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion, uint32_t aFlags,
WebRenderImageProvider** aProvider) override;
GetImageContainerAtSize(WindowRenderer* aRenderer, const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion, uint32_t aFlags,
layers::ImageContainer** aOutContainer) override;
NS_IMETHOD_(ImgDrawResult)
Draw(gfxContext* aContext, const nsIntSize& aSize, const ImageRegion& aRegion,
uint32_t aWhichFrame, gfx::SamplingFilter aSamplingFilter,

View File

@ -273,10 +273,10 @@ RasterImage::GetType(uint16_t* aType) {
}
NS_IMETHODIMP
RasterImage::GetProviderId(uint32_t* aId) {
RasterImage::GetProducerId(uint32_t* aId) {
NS_ENSURE_ARG_POINTER(aId);
*aId = ImageResource::GetImageProviderId();
*aId = ImageResource::GetImageProducerId();
return NS_OK;
}
@ -479,6 +479,7 @@ void RasterImage::OnSurfaceDiscardedInternal(bool aAnimatedFramesDiscarded) {
if (aAnimatedFramesDiscarded && mAnimationState) {
MOZ_ASSERT(StaticPrefs::image_mem_animated_discardable_AtStartup());
ReleaseImageContainer();
IntRect rect = mAnimationState->UpdateState(this, mSize.ToUnknownSize());
@ -545,30 +546,91 @@ RasterImage::GetFrame(uint32_t aWhichFrame, uint32_t aFlags) {
NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
RasterImage::GetFrameAtSize(const IntSize& aSize, uint32_t aWhichFrame,
uint32_t aFlags) {
MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE);
AutoProfilerImagePaintMarker PROFILER_RAII(this);
#ifdef DEBUG
NotifyDrawingObservers();
#endif
if (aSize.IsEmpty() || aWhichFrame > FRAME_MAX_VALUE || mError) {
return nullptr;
}
auto result =
GetFrameInternal(aSize, Nothing(), Nothing(), aWhichFrame, aFlags);
return mozilla::Get<2>(result).forget();
}
Tuple<ImgDrawResult, IntSize, RefPtr<SourceSurface>>
RasterImage::GetFrameInternal(const IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion,
uint32_t aWhichFrame, uint32_t aFlags) {
MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE);
auto size = OrientedIntSize::FromUnknownSize(aSize);
if (aSize.IsEmpty() || aWhichFrame > FRAME_MAX_VALUE) {
return MakeTuple(ImgDrawResult::BAD_ARGS, aSize, RefPtr<SourceSurface>());
}
if (mError) {
return MakeTuple(ImgDrawResult::BAD_IMAGE, aSize, RefPtr<SourceSurface>());
}
// Get the frame. If it's not there, it's probably the caller's fault for
// not waiting for the data to be loaded from the network or not passing
// FLAG_SYNC_DECODE.
LookupResult result = LookupFrame(size, aFlags, ToPlaybackType(aWhichFrame),
/* aMarkUsed = */ true);
// The surface cache may have suggested we use a different size than the
// given size in the future. This may or may not be accompanied by an
// actual surface, depending on what it has in its cache.
auto suggestedSize = OrientedIntSize::FromUnknownSize(result.SuggestedSize());
if (suggestedSize.IsEmpty()) {
suggestedSize = size;
}
MOZ_ASSERT_IF(result.Type() == MatchType::SUBSTITUTE_BECAUSE_BEST,
suggestedSize != size);
if (!result) {
// The OS threw this frame away and we couldn't redecode it.
return nullptr;
return MakeTuple(ImgDrawResult::TEMPORARY_ERROR,
suggestedSize.ToUnknownSize(), RefPtr<SourceSurface>());
}
return result.Surface()->GetSourceSurface();
RefPtr<SourceSurface> surface = result.Surface()->GetSourceSurface();
if (!result.Surface()->IsFinished()) {
return MakeTuple(ImgDrawResult::INCOMPLETE, suggestedSize.ToUnknownSize(),
std::move(surface));
}
return MakeTuple(ImgDrawResult::SUCCESS, suggestedSize.ToUnknownSize(),
std::move(surface));
}
Tuple<ImgDrawResult, IntSize> RasterImage::GetImageContainerSize(
WindowRenderer* aRenderer, const IntSize& aRequestedSize, uint32_t aFlags) {
if (!LoadHasSize()) {
return MakeTuple(ImgDrawResult::NOT_READY, IntSize(0, 0));
}
if (aRequestedSize.IsEmpty()) {
return MakeTuple(ImgDrawResult::BAD_ARGS, IntSize(0, 0));
}
// We check the minimum size because while we support downscaling, we do not
// support upscaling. If aRequestedSize > mSize, we will never give a larger
// surface than mSize. If mSize > aRequestedSize, and mSize > maxTextureSize,
// we still want to use image containers if aRequestedSize <= maxTextureSize.
int32_t maxTextureSize = aRenderer->GetMaxTextureSize();
if (min(mSize.width, aRequestedSize.width) > maxTextureSize ||
min(mSize.height, aRequestedSize.height) > maxTextureSize) {
return MakeTuple(ImgDrawResult::NOT_SUPPORTED, IntSize(0, 0));
}
auto requestedSize = OrientedIntSize::FromUnknownSize(aRequestedSize);
if (!CanDownscaleDuringDecode(requestedSize, aFlags)) {
return MakeTuple(ImgDrawResult::SUCCESS, mSize.ToUnknownSize());
}
return MakeTuple(ImgDrawResult::SUCCESS, aRequestedSize);
}
NS_IMETHODIMP_(bool)
@ -578,60 +640,17 @@ RasterImage::IsImageContainerAvailable(WindowRenderer* aRenderer,
}
NS_IMETHODIMP_(ImgDrawResult)
RasterImage::GetImageProvider(WindowRenderer* aRenderer,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion,
uint32_t aFlags,
WebRenderImageProvider** aProvider) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aRenderer);
if (mError) {
return ImgDrawResult::BAD_IMAGE;
}
if (!LoadHasSize()) {
return ImgDrawResult::NOT_READY;
}
if (aSize.IsEmpty()) {
return ImgDrawResult::BAD_ARGS;
}
// We check the minimum size because while we support downscaling, we do not
// support upscaling. If aRequestedSize > mSize, we will never give a larger
// surface than mSize. If mSize > aRequestedSize, and mSize > maxTextureSize,
// we still want to use image containers if aRequestedSize <= maxTextureSize.
int32_t maxTextureSize = aRenderer->GetMaxTextureSize();
if (min(mSize.width, aSize.width) > maxTextureSize ||
min(mSize.height, aSize.height) > maxTextureSize) {
return ImgDrawResult::NOT_SUPPORTED;
}
AutoProfilerImagePaintMarker PROFILER_RAII(this);
#ifdef DEBUG
NotifyDrawingObservers();
#endif
// Get the frame. If it's not there, it's probably the caller's fault for
// not waiting for the data to be loaded from the network or not passing
// FLAG_SYNC_DECODE.
LookupResult result = LookupFrame(OrientedIntSize::FromUnknownSize(aSize),
aFlags, PlaybackType::eAnimated,
/* aMarkUsed = */ true);
if (!result) {
// The OS threw this frame away and we couldn't redecode it.
return ImgDrawResult::NOT_READY;
}
if (!result.Surface()->IsFinished()) {
result.Surface().TakeProvider(aProvider);
return ImgDrawResult::INCOMPLETE;
}
result.Surface().TakeProvider(aProvider);
return ImgDrawResult::SUCCESS;
RasterImage::GetImageContainerAtSize(WindowRenderer* aRenderer,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion,
uint32_t aFlags,
layers::ImageContainer** aOutContainer) {
// We do not pass in the given SVG context because in theory it could differ
// between calls, but actually have no impact on the actual contents of the
// image container.
return GetImageContainerImpl(aRenderer, aSize, Nothing(), Nothing(), aFlags,
aOutContainer);
}
size_t RasterImage::SizeOfSourceWithComputedFallback(
@ -640,6 +659,13 @@ size_t RasterImage::SizeOfSourceWithComputedFallback(
aState.mMallocSizeOf);
}
void RasterImage::CollectSizeOfSurfaces(
nsTArray<SurfaceMemoryCounter>& aCounters,
MallocSizeOf aMallocSizeOf) const {
SurfaceCache::CollectSizeOfSurfaces(ImageKey(this), aCounters, aMallocSizeOf);
ImageResource::CollectSizeOfSurfaces(aCounters, aMallocSizeOf);
}
bool RasterImage::SetMetadata(const ImageMetadata& aMetadata,
bool aFromMetadataDecode) {
MOZ_ASSERT(NS_IsMainThread());
@ -967,6 +993,8 @@ void RasterImage::Discard() {
SurfaceCache::RemoveImage(ImageKey(this));
if (mAnimationState) {
ReleaseImageContainer();
IntRect rect = mAnimationState->UpdateState(this, mSize.ToUnknownSize());
auto dirtyRect = OrientedIntRect::FromUnknownRect(rect);
@ -1570,6 +1598,13 @@ void RasterImage::NotifyProgress(
}
}
const bool wasDefaultFlags = aSurfaceFlags == DefaultSurfaceFlags();
if (!invalidRect.IsEmpty() && wasDefaultFlags) {
// Update our image container since we're invalidating.
UpdateImageContainer(Some(invalidRect.ToUnknownRect()));
}
// Tell the observers what happened.
image->mProgressTracker->SyncNotifyProgress(aProgress,
invalidRect.ToUnknownRect());

View File

@ -166,6 +166,8 @@ class RasterImage final : public ImageResource,
virtual size_t SizeOfSourceWithComputedFallback(
SizeOfState& aState) const override;
virtual void CollectSizeOfSurfaces(nsTArray<SurfaceMemoryCounter>& aCounters,
MallocSizeOf aMallocSizeOf) const override;
/* Triggers discarding. */
void Discard();
@ -292,6 +294,16 @@ class RasterImage final : public ImageResource,
gfx::SamplingFilter aSamplingFilter,
uint32_t aFlags, float aOpacity);
Tuple<ImgDrawResult, gfx::IntSize, RefPtr<gfx::SourceSurface>>
GetFrameInternal(const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion, uint32_t aWhichFrame,
uint32_t aFlags) override;
Tuple<ImgDrawResult, gfx::IntSize> GetImageContainerSize(
WindowRenderer* aRenderer, const gfx::IntSize& aSize,
uint32_t aFlags) override;
//////////////////////////////////////////////////////////////////////////////
// Decoding.
//////////////////////////////////////////////////////////////////////////////

View File

@ -4,7 +4,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "BlobSurfaceProvider.h"
#include "SourceSurfaceBlobImage.h"
#include "AutoRestoreSVGState.h"
#include "ImageRegion.h"
#include "SVGDocumentWrapper.h"
@ -20,18 +20,23 @@ using namespace mozilla::layers;
namespace mozilla::image {
BlobSurfaceProvider::BlobSurfaceProvider(
const ImageKey aImageKey, const SurfaceKey& aSurfaceKey,
image::SVGDocumentWrapper* aSVGDocumentWrapper, uint32_t aImageFlags)
: ISurfaceProvider(aImageKey, aSurfaceKey,
AvailabilityState::StartAvailable()),
mSVGDocumentWrapper(aSVGDocumentWrapper),
SourceSurfaceBlobImage::SourceSurfaceBlobImage(
image::SVGDocumentWrapper* aSVGDocumentWrapper,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion, const IntSize& aSize,
uint32_t aWhichFrame, uint32_t aImageFlags)
: mSVGDocumentWrapper(aSVGDocumentWrapper),
mSVGContext(aSVGContext),
mRegion(aRegion),
mSize(aSize),
mWhichFrame(aWhichFrame),
mImageFlags(aImageFlags) {
MOZ_ASSERT(mSVGDocumentWrapper);
MOZ_ASSERT(aWhichFrame <= imgIContainer::FRAME_MAX_VALUE);
MOZ_ASSERT(aImageFlags & imgIContainer::FLAG_RECORD_BLOB);
}
BlobSurfaceProvider::~BlobSurfaceProvider() {
SourceSurfaceBlobImage::~SourceSurfaceBlobImage() {
if (NS_IsMainThread()) {
DestroyKeys(mKeys);
return;
@ -44,7 +49,7 @@ BlobSurfaceProvider::~BlobSurfaceProvider() {
[keys = std::move(mKeys)] { DestroyKeys(keys); }));
}
/* static */ void BlobSurfaceProvider::DestroyKeys(
/* static */ void SourceSurfaceBlobImage::DestroyKeys(
const AutoTArray<BlobImageKeyData, 1>& aKeys) {
for (const auto& entry : aKeys) {
if (!entry.mManager->IsDestroyed()) {
@ -54,14 +59,10 @@ BlobSurfaceProvider::~BlobSurfaceProvider() {
}
}
nsresult BlobSurfaceProvider::UpdateKey(
layers::RenderRootStateManager* aManager,
wr::IpcResourceUpdateQueue& aResources, wr::ImageKey& aKey) {
Maybe<wr::BlobImageKey> SourceSurfaceBlobImage::UpdateKey(
WebRenderLayerManager* aManager, wr::IpcResourceUpdateQueue& aResources) {
MOZ_ASSERT(NS_IsMainThread());
layers::WebRenderLayerManager* manager = aManager->LayerManager();
MOZ_ASSERT(manager);
Maybe<wr::BlobImageKey> key;
auto i = mKeys.Length();
while (i > 0) {
@ -69,8 +70,8 @@ nsresult BlobSurfaceProvider::UpdateKey(
BlobImageKeyData& entry = mKeys[i];
if (entry.mManager->IsDestroyed()) {
mKeys.RemoveElementAt(i);
} else if (entry.mManager == manager) {
WebRenderBridgeChild* wrBridge = manager->WrBridge();
} else if (entry.mManager == aManager) {
WebRenderBridgeChild* wrBridge = aManager->WrBridge();
MOZ_ASSERT(wrBridge);
bool ownsKey = wrBridge->MatchesNamespace(entry.mBlobKey);
@ -83,11 +84,12 @@ nsresult BlobSurfaceProvider::UpdateKey(
// can change state. Either our namespace differs, and our old key has
// already been discarded, or the blob has changed. Either way, we need
// to rerecord it.
auto newEntry = RecordDrawing(manager, aResources,
auto newEntry = RecordDrawing(aManager, aResources,
ownsKey ? Some(entry.mBlobKey) : Nothing());
if (!newEntry) {
if (ownsKey) {
aManager->AddBlobImageKeyForDiscard(entry.mBlobKey);
aManager->GetRenderRootStateManager()->AddBlobImageKeyForDiscard(
entry.mBlobKey);
}
mKeys.RemoveElementAt(i);
continue;
@ -101,22 +103,17 @@ nsresult BlobSurfaceProvider::UpdateKey(
// We didn't find an entry. Attempt to record the blob with a new key.
if (!key) {
auto newEntry = RecordDrawing(manager, aResources, Nothing());
auto newEntry = RecordDrawing(aManager, aResources, Nothing());
if (newEntry) {
key.emplace(newEntry.ref().mBlobKey);
mKeys.AppendElement(std::move(newEntry.ref()));
}
}
if (key) {
aKey = wr::AsImageKey(key.value());
return NS_OK;
}
return NS_ERROR_FAILURE;
return key;
}
void BlobSurfaceProvider::InvalidateRecording() {
void SourceSurfaceBlobImage::MarkDirty() {
MOZ_ASSERT(NS_IsMainThread());
auto i = mKeys.Length();
@ -131,7 +128,7 @@ void BlobSurfaceProvider::InvalidateRecording() {
}
}
Maybe<BlobImageKeyData> BlobSurfaceProvider::RecordDrawing(
Maybe<BlobImageKeyData> SourceSurfaceBlobImage::RecordDrawing(
WebRenderLayerManager* aManager, wr::IpcResourceUpdateQueue& aResources,
Maybe<wr::BlobImageKey> aBlobKey) {
MOZ_ASSERT(!aManager->IsDestroyed());
@ -145,11 +142,8 @@ Maybe<BlobImageKeyData> BlobSurfaceProvider::RecordDrawing(
auto* rootManager = aManager->GetRenderRootStateManager();
auto* wrBridge = aManager->WrBridge();
const auto& size = GetSurfaceKey().Size();
const auto& region = GetSurfaceKey().Region();
const auto& svgContext = GetSurfaceKey().SVGContext();
IntRect imageRect = region ? region->Rect() : IntRect(IntPoint(0, 0), size);
IntRect imageRect =
mRegion ? mRegion->Rect() : IntRect(IntPoint(0, 0), mSize);
IntRect imageRectOrigin = imageRect - imageRect.TopLeft();
std::vector<RefPtr<ScaledFont>> fonts;
@ -184,15 +178,15 @@ Maybe<BlobImageKeyData> BlobSurfaceProvider::RecordDrawing(
return Nothing();
}
bool contextPaint = svgContext && svgContext->GetContextPaint();
bool contextPaint = mSVGContext && mSVGContext->GetContextPaint();
float animTime = (GetSurfaceKey().Playback() == PlaybackType::eStatic)
float animTime = (mWhichFrame == imgIContainer::FRAME_FIRST)
? 0.0f
: mSVGDocumentWrapper->GetCurrentTimeAsFloat();
IntSize viewportSize = size;
if (svgContext) {
auto cssViewportSize = svgContext->GetViewportSize();
IntSize viewportSize = mSize;
if (mSVGContext) {
auto cssViewportSize = mSVGContext->GetViewportSize();
if (cssViewportSize) {
// XXX losing unit
viewportSize.SizeTo(cssViewportSize->width, cssViewportSize->height);
@ -212,11 +206,11 @@ Maybe<BlobImageKeyData> BlobSurfaceProvider::RecordDrawing(
AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING(
"SVG Image recording", GRAPHICS,
nsPrintfCString("(%d,%d) %dx%d from %dx%d %s", imageRect.x, imageRect.y,
imageRect.width, imageRect.height, size.width,
size.height,
imageRect.width, imageRect.height, mSize.width,
mSize.height,
uri ? uri->GetSpecOrDefault().get() : "N/A"));
AutoRestoreSVGState autoRestore(svgContext, animTime, mSVGDocumentWrapper,
AutoRestoreSVGState autoRestore(mSVGContext, animTime, mSVGDocumentWrapper,
contextPaint);
mSVGDocumentWrapper->UpdateViewportBounds(viewportSize);
@ -227,9 +221,9 @@ Maybe<BlobImageKeyData> BlobSurfaceProvider::RecordDrawing(
nsRect svgRect;
auto auPerDevPixel = presContext->AppUnitsPerDevPixel();
if (size != viewportSize) {
auto scaleX = double(size.width) / viewportSize.width;
auto scaleY = double(size.height) / viewportSize.height;
if (mSize != viewportSize) {
auto scaleX = double(mSize.width) / viewportSize.width;
auto scaleY = double(mSize.height) / viewportSize.height;
ctx->SetMatrix(Matrix::Scaling(float(scaleX), float(scaleY)));
auto scaledVisibleRect = IntRectToRect(imageRect);

View File

@ -4,15 +4,14 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MOZILLA_IMAGE_BLOBSURFACEPROVIDER_H_
#define MOZILLA_IMAGE_BLOBSURFACEPROVIDER_H_
#ifndef MOZILLA_IMAGE_SOURCESURFACEBLOBIMAGE_H_
#define MOZILLA_IMAGE_SOURCESURFACEBLOBIMAGE_H_
#include "mozilla/Maybe.h"
#include "mozilla/SVGImageContext.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/layers/WebRenderLayerManager.h"
#include "ImageRegion.h"
#include "ISurfaceProvider.h"
#include <vector>
@ -71,56 +70,45 @@ namespace image {
class SVGDocumentWrapper;
/**
* An ISurfaceProvider that manages blob recordings of SVG images. Unlike the
* rasterized ISurfaceProviders, it only provides a recording which may be
* replayed in the compositor process by WebRender. It may be invalidated
* directly in order to reuse the resource ids and underlying buffers when the
* SVG image has changed (e.g. it is animated).
* This class is used to wrap blob recordings stored in ImageContainers, used
* by SVG images. Unlike rasterized images stored in SourceSurfaceSharedData,
* each SourceSurfaceBlobImage can only be used by one WebRenderLayerManager
* because the recording is tied to a particular instance.
*/
class BlobSurfaceProvider final : public ISurfaceProvider {
class SourceSurfaceBlobImage final : public gfx::SourceSurface {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BlobSurfaceProvider, override)
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceBlobImage, override)
BlobSurfaceProvider(ImageKey aImageKey, const SurfaceKey& aSurfaceKey,
SVGDocumentWrapper* aSVGDocumentWrapper,
uint32_t aImageFlags);
SourceSurfaceBlobImage(SVGDocumentWrapper* aSVGDocumentWrapper,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion,
const gfx::IntSize& aSize, uint32_t aWhichFrame,
uint32_t aImageFlags);
bool IsFinished() const override { return true; }
Maybe<wr::BlobImageKey> UpdateKey(layers::WebRenderLayerManager* aManager,
wr::IpcResourceUpdateQueue& aResources);
size_t LogicalSizeInBytes() const override {
const gfx::IntSize& size = GetSurfaceKey().Size();
return size.width * size.height * sizeof(uint32_t);
void MarkDirty();
gfx::SurfaceType GetType() const override {
return gfx::SurfaceType::BLOB_IMAGE;
}
gfx::IntSize GetSize() const override { return mSize; }
gfx::SurfaceFormat GetFormat() const override {
return gfx::SurfaceFormat::OS_RGBA;
}
already_AddRefed<gfx::DataSourceSurface> GetDataSurface() override {
return nullptr;
}
nsresult UpdateKey(layers::RenderRootStateManager* aManager,
wr::IpcResourceUpdateQueue& aResources,
wr::ImageKey& aKey) override;
void InvalidateRecording() override;
void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
const AddSizeOfCb& aCallback) override {
AddSizeOfCbData metadata;
metadata.mFinished = true;
metadata.mHeapBytes += mKeys.ShallowSizeOfExcludingThis(aMallocSizeOf);
gfx::SourceSurface::SizeOfInfo info;
info.AddType(gfx::SurfaceType::BLOB_IMAGE);
metadata.Accumulate(info);
aCallback(metadata);
void SizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
SizeOfInfo& aInfo) const override {
aInfo.AddType(gfx::SurfaceType::BLOB_IMAGE);
aInfo.mHeapBytes += mKeys.ShallowSizeOfExcludingThis(aMallocSizeOf);
}
protected:
DrawableFrameRef DrawableRef(size_t aFrame) override {
MOZ_ASSERT_UNREACHABLE("BlobSurfaceProvider::DrawableRef not supported!");
return DrawableFrameRef();
}
bool IsLocked() const override { return true; }
void SetLocked(bool) override {}
private:
~BlobSurfaceProvider() override;
~SourceSurfaceBlobImage() override;
Maybe<BlobImageKeyData> RecordDrawing(layers::WebRenderLayerManager* aManager,
wr::IpcResourceUpdateQueue& aResources,
@ -131,10 +119,14 @@ class BlobSurfaceProvider final : public ISurfaceProvider {
AutoTArray<BlobImageKeyData, 1> mKeys;
RefPtr<image::SVGDocumentWrapper> mSVGDocumentWrapper;
Maybe<SVGImageContext> mSVGContext;
Maybe<ImageIntRegion> mRegion;
gfx::IntSize mSize;
uint32_t mWhichFrame;
uint32_t mImageFlags;
};
} // namespace image
} // namespace mozilla
#endif /* MOZILLA_IMAGE_BLOBSURFACEPROVIDER_H_ */
#endif /* MOZILLA_IMAGE_SOURCESURFACEBLOBIMAGE_H_ */

View File

@ -176,8 +176,6 @@ class CachedSurface {
return aMallocSizeOf(this) + aMallocSizeOf(mProvider.get());
}
void InvalidateRecording() { mProvider->InvalidateRecording(); }
// A helper type used by SurfaceCacheImpl::CollectSizeOfSurfaces.
struct MOZ_STACK_CLASS SurfaceMemoryReport {
SurfaceMemoryReport(nsTArray<SurfaceMemoryCounter>& aCounters,
@ -195,10 +193,10 @@ class CachedSurface {
// for surfaces with PlaybackType::eAnimated.)
aCachedSurface->mProvider->AddSizeOfExcludingThis(
mMallocSizeOf, [&](ISurfaceProvider::AddSizeOfCbData& aMetadata) {
SurfaceMemoryCounter counter(aCachedSurface->GetSurfaceKey(),
aCachedSurface->IsLocked(),
aCachedSurface->CannotSubstitute(),
aIsFactor2, aMetadata.mFinished);
SurfaceMemoryCounter counter(
aCachedSurface->GetSurfaceKey(), aMetadata.mSurface,
aCachedSurface->IsLocked(), aCachedSurface->CannotSubstitute(),
aIsFactor2, aMetadata.mFinished);
counter.Values().SetDecodedHeap(aMetadata.mHeapBytes);
counter.Values().SetDecodedNonHeap(aMetadata.mNonHeapBytes);
@ -278,14 +276,8 @@ class ImageSurfaceCache {
[[nodiscard]] bool Insert(NotNull<CachedSurface*> aSurface) {
MOZ_ASSERT(!mLocked || aSurface->IsPlaceholder() || aSurface->IsLocked(),
"Inserting an unlocked surface for a locked image");
const auto& surfaceKey = aSurface->GetSurfaceKey();
if (surfaceKey.Region()) {
// We don't allow substitutes for surfaces with regions, so we don't want
// to allow factor of 2 mode pruning to release these surfaces.
aSurface->SetCannotSubstitute();
}
return mSurfaces.InsertOrUpdate(surfaceKey, RefPtr<CachedSurface>{aSurface},
fallible);
return mSurfaces.InsertOrUpdate(aSurface->GetSurfaceKey(),
RefPtr<CachedSurface>{aSurface}, fallible);
}
already_AddRefed<CachedSurface> Remove(NotNull<CachedSurface*> aSurface) {
@ -334,10 +326,6 @@ class ImageSurfaceCache {
if (exactMatch->IsDecoded()) {
return MakeTuple(exactMatch.forget(), MatchType::EXACT, IntSize());
}
} else if (aIdealKey.Region()) {
// We cannot substitute if we have a region. Allow it to create an exact
// match.
return MakeTuple(exactMatch.forget(), MatchType::NOT_FOUND, IntSize());
} else if (!mFactor2Mode) {
// If no exact match is found, and we are not in factor of 2 mode, then
// we know that we will trigger a decode because at best we will provide
@ -365,8 +353,8 @@ class ImageSurfaceCache {
NotNull<CachedSurface*> current = WrapNotNull(value);
const SurfaceKey& currentKey = current->GetSurfaceKey();
// We never match a placeholder or a surface with a region.
if (current->IsPlaceholder() || currentKey.Region()) {
// We never match a placeholder.
if (current->IsPlaceholder()) {
continue;
}
// Matching the playback type and SVG context is required.
@ -542,28 +530,6 @@ class ImageSurfaceCache {
AfterMaybeRemove();
}
template <typename Function>
bool Invalidate(Function&& aRemoveCallback) {
// Remove all non-blob recordings from the cache. Invalidate any blob
// recordings.
bool foundRecording = false;
for (auto iter = mSurfaces.Iter(); !iter.Done(); iter.Next()) {
NotNull<CachedSurface*> current = WrapNotNull(iter.UserData());
if (current->GetSurfaceKey().Flags() & SurfaceFlags::RECORD_BLOB) {
foundRecording = true;
current->InvalidateRecording();
continue;
}
aRemoveCallback(current);
iter.Remove();
}
AfterMaybeRemove();
return foundRecording;
}
IntSize SuggestedSize(const IntSize& aSize) const {
IntSize suggestedSize = SuggestedSizeInternal(aSize);
if (mIsVectorImage) {
@ -1050,8 +1016,7 @@ class SurfaceCacheImpl final : public nsIMemoryReporter {
MOZ_ASSERT_IF(
matchType == MatchType::SUBSTITUTE_BECAUSE_NOT_FOUND ||
matchType == MatchType::SUBSTITUTE_BECAUSE_PENDING,
surface->GetSurfaceKey().Region() == aSurfaceKey.Region() &&
surface->GetSurfaceKey().SVGContext() == aSurfaceKey.SVGContext() &&
surface->GetSurfaceKey().SVGContext() == aSurfaceKey.SVGContext() &&
surface->GetSurfaceKey().Playback() == aSurfaceKey.Playback() &&
surface->GetSurfaceKey().Flags() == aSurfaceKey.Flags());
@ -1167,24 +1132,6 @@ class SurfaceCacheImpl final : public nsIMemoryReporter {
MaybeRemoveEmptyCache(aImageKey, cache);
}
bool InvalidateImage(const ImageKey aImageKey,
const StaticMutexAutoLock& aAutoLock) {
RefPtr<ImageSurfaceCache> cache = GetImageCache(aImageKey);
if (!cache) {
return false; // No cached surfaces for this image, so nothing to do.
}
bool rv = cache->Invalidate(
[this, &aAutoLock](NotNull<CachedSurface*> aSurface) -> void {
StopTracking(aSurface, /* aIsTracked */ true, aAutoLock);
// Individual surfaces must be freed outside the lock.
mCachedSurfacesDiscard.AppendElement(aSurface);
});
MaybeRemoveEmptyCache(aImageKey, cache);
return rv;
}
void DiscardAll(const StaticMutexAutoLock& aAutoLock) {
// Remove in order of cost because mCosts is an array and the other data
// structures are all hash tables. Note that locked surfaces are not
@ -1770,20 +1717,6 @@ void SurfaceCache::PruneImage(const ImageKey aImageKey) {
}
}
/* static */
bool SurfaceCache::InvalidateImage(const ImageKey aImageKey) {
nsTArray<RefPtr<CachedSurface>> discard;
bool rv = false;
{
StaticMutexAutoLock lock(sInstanceMutex);
if (sInstance) {
rv = sInstance->InvalidateImage(aImageKey, lock);
sInstance->TakeDiscard(discard, lock);
}
}
return rv;
}
/* static */
void SurfaceCache::DiscardAll() {
nsTArray<RefPtr<CachedSurface>> discard;

View File

@ -21,14 +21,13 @@
#include "gfx2DGlue.h"
#include "gfxPoint.h" // for gfxSize
#include "nsCOMPtr.h" // for already_AddRefed
#include "ImageRegion.h"
#include "PlaybackType.h"
#include "SurfaceFlags.h"
namespace mozilla {
namespace image {
class ImageResource;
class Image;
class ISurfaceProvider;
class LookupResult;
class SurfaceCacheImpl;
@ -38,7 +37,7 @@ struct SurfaceMemoryCounter;
* ImageKey contains the information we need to look up all SurfaceCache entries
* for a particular image.
*/
using ImageKey = ImageResource*;
typedef Image* ImageKey;
/*
* SurfaceKey contains the information we need to look up a specific
@ -53,43 +52,34 @@ class SurfaceKey {
public:
bool operator==(const SurfaceKey& aOther) const {
return aOther.mSize == mSize && aOther.mRegion == mRegion &&
aOther.mSVGContext == mSVGContext && aOther.mPlayback == mPlayback &&
aOther.mFlags == mFlags;
return aOther.mSize == mSize && aOther.mSVGContext == mSVGContext &&
aOther.mPlayback == mPlayback && aOther.mFlags == mFlags;
}
PLDHashNumber Hash() const {
PLDHashNumber hash = HashGeneric(mSize.width, mSize.height);
hash = AddToHash(hash, mRegion.map(HashIIR).valueOr(0));
hash = AddToHash(hash, mSVGContext.map(HashSIC).valueOr(0));
hash = AddToHash(hash, uint8_t(mPlayback), uint32_t(mFlags));
return hash;
}
SurfaceKey CloneWithSize(const IntSize& aSize) const {
return SurfaceKey(aSize, mRegion, mSVGContext, mPlayback, mFlags);
return SurfaceKey(aSize, mSVGContext, mPlayback, mFlags);
}
const IntSize& Size() const { return mSize; }
const Maybe<ImageIntRegion>& Region() const { return mRegion; }
const Maybe<SVGImageContext>& SVGContext() const { return mSVGContext; }
PlaybackType Playback() const { return mPlayback; }
SurfaceFlags Flags() const { return mFlags; }
private:
SurfaceKey(const IntSize& aSize, const Maybe<ImageIntRegion>& aRegion,
const Maybe<SVGImageContext>& aSVGContext, PlaybackType aPlayback,
SurfaceFlags aFlags)
SurfaceKey(const IntSize& aSize, const Maybe<SVGImageContext>& aSVGContext,
PlaybackType aPlayback, SurfaceFlags aFlags)
: mSize(aSize),
mRegion(aRegion),
mSVGContext(aSVGContext),
mPlayback(aPlayback),
mFlags(aFlags) {}
static PLDHashNumber HashIIR(const ImageIntRegion& aIIR) {
return aIIR.Hash();
}
static PLDHashNumber HashSIC(const SVGImageContext& aSIC) {
return aSIC.Hash();
}
@ -98,13 +88,11 @@ class SurfaceKey {
PlaybackType);
friend SurfaceKey VectorSurfaceKey(const IntSize&,
const Maybe<SVGImageContext>&);
friend SurfaceKey VectorSurfaceKey(const IntSize&,
const Maybe<ImageIntRegion>&,
const Maybe<SVGImageContext>&,
SurfaceFlags, PlaybackType);
friend SurfaceKey ContainerSurfaceKey(
const gfx::IntSize& aSize, const Maybe<SVGImageContext>& aSVGContext,
SurfaceFlags aFlags);
IntSize mSize;
Maybe<ImageIntRegion> mRegion;
Maybe<SVGImageContext> mSVGContext;
PlaybackType mPlayback;
SurfaceFlags mFlags;
@ -113,15 +101,7 @@ class SurfaceKey {
inline SurfaceKey RasterSurfaceKey(const gfx::IntSize& aSize,
SurfaceFlags aFlags,
PlaybackType aPlayback) {
return SurfaceKey(aSize, Nothing(), Nothing(), aPlayback, aFlags);
}
inline SurfaceKey VectorSurfaceKey(const gfx::IntSize& aSize,
const Maybe<ImageIntRegion>& aRegion,
const Maybe<SVGImageContext>& aSVGContext,
SurfaceFlags aFlags,
PlaybackType aPlayback) {
return SurfaceKey(aSize, aRegion, aSVGContext, aPlayback, aFlags);
return SurfaceKey(aSize, Nothing(), aPlayback, aFlags);
}
inline SurfaceKey VectorSurfaceKey(const gfx::IntSize& aSize,
@ -131,10 +111,16 @@ inline SurfaceKey VectorSurfaceKey(const gfx::IntSize& aSize,
// *does* affect how a VectorImage renders, we'll have to change this.
// Similarly, we don't accept a PlaybackType parameter because we don't
// currently cache frames of animated SVG images.
return SurfaceKey(aSize, Nothing(), aSVGContext, PlaybackType::eStatic,
return SurfaceKey(aSize, aSVGContext, PlaybackType::eStatic,
DefaultSurfaceFlags());
}
inline SurfaceKey ContainerSurfaceKey(const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
SurfaceFlags aFlags) {
return SurfaceKey(aSize, aSVGContext, PlaybackType::eStatic, aFlags);
}
/**
* AvailabilityState is used to track whether an ISurfaceProvider has a surface
* available or is just a placeholder.
@ -423,17 +409,6 @@ struct SurfaceCache {
*/
static void PruneImage(const ImageKey aImageKey);
/**
* Removes all rasterized cache entries (including placeholders) associated
* with the given image from the cache. Any blob recordings are marked as
* dirty and must be regenerated.
*
* @param aImageKey The image whose cache which should be regenerated.
*
* @returns true if any recordings were invalidated, else false.
*/
static bool InvalidateImage(const ImageKey aImageKey);
/**
* Evicts all evictable entries from the cache.
*

View File

@ -20,8 +20,7 @@ namespace image {
enum class SurfaceFlags : uint8_t {
NO_PREMULTIPLY_ALPHA = 1 << 0,
NO_COLORSPACE_CONVERSION = 1 << 1,
TO_SRGB_COLORSPACE = 1 << 2,
RECORD_BLOB = 1 << 3,
TO_SRGB_COLORSPACE = 2 << 1,
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(SurfaceFlags)
@ -45,9 +44,6 @@ inline SurfaceFlags ToSurfaceFlags(uint32_t aFlags) {
if (aFlags & imgIContainer::FLAG_DECODE_TO_SRGB_COLORSPACE) {
flags |= SurfaceFlags::TO_SRGB_COLORSPACE;
}
if (aFlags & imgIContainer::FLAG_RECORD_BLOB) {
flags |= SurfaceFlags::RECORD_BLOB;
}
return flags;
}
@ -66,9 +62,6 @@ inline uint32_t FromSurfaceFlags(SurfaceFlags aFlags) {
if (aFlags & SurfaceFlags::TO_SRGB_COLORSPACE) {
flags |= imgIContainer::FLAG_DECODE_TO_SRGB_COLORSPACE;
}
if (aFlags & SurfaceFlags::RECORD_BLOB) {
flags |= imgIContainer::FLAG_RECORD_BLOB;
}
return flags;
}

View File

@ -37,16 +37,15 @@
#include "ISurfaceProvider.h"
#include "LookupResult.h"
#include "Orientation.h"
#include "SourceSurfaceBlobImage.h"
#include "SVGDocumentWrapper.h"
#include "SVGDrawingCallback.h"
#include "SVGDrawingParameters.h"
#include "nsIDOMEventListener.h"
#include "SurfaceCache.h"
#include "BlobSurfaceProvider.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/DocumentInlines.h"
#include "mozilla/image/Resolution.h"
#include "WindowRenderer.h"
namespace mozilla {
@ -372,6 +371,13 @@ size_t VectorImage::SizeOfSourceWithComputedFallback(
return windowSizes.getTotalSize();
}
void VectorImage::CollectSizeOfSurfaces(
nsTArray<SurfaceMemoryCounter>& aCounters,
MallocSizeOf aMallocSizeOf) const {
SurfaceCache::CollectSizeOfSurfaces(ImageKey(this), aCounters, aMallocSizeOf);
ImageResource::CollectSizeOfSurfaces(aCounters, aMallocSizeOf);
}
nsresult VectorImage::OnImageDataComplete(nsIRequest* aRequest,
nsISupports* aContext,
nsresult aStatus, bool aLastPart) {
@ -515,10 +521,12 @@ void VectorImage::SendInvalidationNotifications() {
// notifications indirectly in |InvalidateObservers...|.
mHasPendingInvalidation = false;
SurfaceCache::RemoveImage(ImageKey(this));
if (SurfaceCache::InvalidateImage(ImageKey(this))) {
// If we still have recordings in the cache, make sure we handle future
// invalidations.
if (UpdateImageContainer(Nothing())) {
// If we have image containers, that means we probably won't get a Draw call
// from the owner since they are using the container. We must assume all
// invalidations need to be handled.
MOZ_ASSERT(mRenderingObserver, "Should have a rendering observer by now");
mRenderingObserver->ResumeHonoringInvalidations();
}
@ -612,10 +620,10 @@ VectorImage::GetType(uint16_t* aType) {
//******************************************************************************
NS_IMETHODIMP
VectorImage::GetProviderId(uint32_t* aId) {
VectorImage::GetProducerId(uint32_t* aId) {
NS_ENSURE_ARG_POINTER(aId);
*aId = ImageResource::GetImageProviderId();
*aId = ImageResource::GetImageProducerId();
return NS_OK;
}
@ -678,16 +686,33 @@ VectorImage::GetFrame(uint32_t aWhichFrame, uint32_t aFlags) {
NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
VectorImage::GetFrameAtSize(const IntSize& aSize, uint32_t aWhichFrame,
uint32_t aFlags) {
MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE);
AutoProfilerImagePaintMarker PROFILER_RAII(this);
#ifdef DEBUG
NotifyDrawingObservers();
#endif
if (aSize.IsEmpty() || aWhichFrame > FRAME_MAX_VALUE || mError ||
!mIsFullyLoaded) {
return nullptr;
auto result =
GetFrameInternal(aSize, Nothing(), Nothing(), aWhichFrame, aFlags);
return Get<2>(result).forget();
}
Tuple<ImgDrawResult, IntSize, RefPtr<SourceSurface>>
VectorImage::GetFrameInternal(const IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion,
uint32_t aWhichFrame, uint32_t aFlags) {
MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE);
if (aSize.IsEmpty() || aWhichFrame > FRAME_MAX_VALUE) {
return MakeTuple(ImgDrawResult::BAD_ARGS, aSize, RefPtr<SourceSurface>());
}
if (mError) {
return MakeTuple(ImgDrawResult::BAD_IMAGE, aSize, RefPtr<SourceSurface>());
}
if (!mIsFullyLoaded) {
return MakeTuple(ImgDrawResult::NOT_READY, aSize, RefPtr<SourceSurface>());
}
uint32_t whichFrame = mHaveAnimations ? aWhichFrame : FRAME_FIRST;
@ -695,44 +720,91 @@ VectorImage::GetFrameAtSize(const IntSize& aSize, uint32_t aWhichFrame,
RefPtr<SourceSurface> sourceSurface;
IntSize decodeSize;
Tie(sourceSurface, decodeSize) =
LookupCachedSurface(aSize, Nothing(), aFlags);
LookupCachedSurface(aSize, aSVGContext, aFlags);
if (sourceSurface) {
return sourceSurface.forget();
return MakeTuple(ImgDrawResult::SUCCESS, decodeSize,
std::move(sourceSurface));
}
if (mSVGDocumentWrapper->IsDrawing()) {
NS_WARNING("Refusing to make re-entrant call to VectorImage::Draw");
return nullptr;
return MakeTuple(ImgDrawResult::TEMPORARY_ERROR, decodeSize,
RefPtr<SourceSurface>());
}
float animTime = (whichFrame == FRAME_FIRST)
? 0.0f
: mSVGDocumentWrapper->GetCurrentTimeAsFloat();
// If we aren't given a region, create one that covers the whole SVG image.
ImageRegion region =
aRegion ? aRegion->ToImageRegion() : ImageRegion::Create(decodeSize);
// By using a null gfxContext, we ensure that we will always attempt to
// create a surface, even if we aren't capable of caching it (e.g. due to our
// flags, having an animation, etc). Otherwise CreateSurface will assume that
// the caller is capable of drawing directly to its own draw target if we
// cannot cache.
Maybe<SVGImageContext> svgContext;
SVGDrawingParameters params(
nullptr, decodeSize, aSize, ImageRegion::Create(decodeSize),
SamplingFilter::POINT, svgContext, animTime, aFlags, 1.0);
SVGDrawingParameters params(nullptr, decodeSize, aSize, region,
SamplingFilter::POINT, aSVGContext, animTime,
aFlags, 1.0);
// Blob recorded vector images just create a simple surface responsible for
// generating blob keys and recording bindings. The recording won't happen
// until the caller requests the key after GetImageContainerAtSize.
if (aFlags & FLAG_RECORD_BLOB) {
RefPtr<SourceSurface> surface =
new SourceSurfaceBlobImage(mSVGDocumentWrapper, aSVGContext, aRegion,
decodeSize, whichFrame, aFlags);
return MakeTuple(ImgDrawResult::SUCCESS, decodeSize, std::move(surface));
}
bool didCache; // Was the surface put into the cache?
bool contextPaint = aSVGContext && aSVGContext->GetContextPaint();
AutoRestoreSVGState autoRestore(params, mSVGDocumentWrapper,
/* aContextPaint */ false);
AutoRestoreSVGState autoRestore(params, mSVGDocumentWrapper, contextPaint);
RefPtr<gfxDrawable> svgDrawable = CreateSVGDrawable(params);
RefPtr<SourceSurface> surface = CreateSurface(params, svgDrawable, didCache);
if (!surface) {
MOZ_ASSERT(!didCache);
return nullptr;
return MakeTuple(ImgDrawResult::TEMPORARY_ERROR, decodeSize,
RefPtr<SourceSurface>());
}
SendFrameComplete(didCache, params.flags);
return surface.forget();
return MakeTuple(ImgDrawResult::SUCCESS, decodeSize, std::move(surface));
}
//******************************************************************************
Tuple<ImgDrawResult, IntSize> VectorImage::GetImageContainerSize(
WindowRenderer* aRenderer, const IntSize& aSize, uint32_t aFlags) {
if (mError) {
return MakeTuple(ImgDrawResult::BAD_IMAGE, IntSize(0, 0));
}
if (!mIsFullyLoaded) {
return MakeTuple(ImgDrawResult::NOT_READY, IntSize(0, 0));
}
if (mHaveAnimations && !StaticPrefs::image_svg_blob_image()) {
// We don't support rasterizing animation SVGs. We can put them in a blob
// recording however instead of using fallback.
return MakeTuple(ImgDrawResult::NOT_SUPPORTED, IntSize(0, 0));
}
if (aRenderer->GetBackendType() != LayersBackend::LAYERS_WR) {
return MakeTuple(ImgDrawResult::NOT_SUPPORTED, IntSize(0, 0));
}
// We don't need to check if the size is too big since we only support
// WebRender backends.
if (aSize.IsEmpty()) {
return MakeTuple(ImgDrawResult::BAD_ARGS, IntSize(0, 0));
}
return MakeTuple(ImgDrawResult::SUCCESS, aSize);
}
NS_IMETHODIMP_(bool)
@ -754,160 +826,30 @@ VectorImage::IsImageContainerAvailable(WindowRenderer* aRenderer,
//******************************************************************************
NS_IMETHODIMP_(ImgDrawResult)
VectorImage::GetImageProvider(WindowRenderer* aRenderer,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion,
uint32_t aFlags,
WebRenderImageProvider** aProvider) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aRenderer);
MOZ_ASSERT(!(aFlags & FLAG_BYPASS_SURFACE_CACHE), "Unsupported flags");
VectorImage::GetImageContainerAtSize(WindowRenderer* aRenderer,
const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion,
uint32_t aFlags,
layers::ImageContainer** aOutContainer) {
Maybe<SVGImageContext> newSVGContext;
MaybeRestrictSVGContext(newSVGContext, aSVGContext, aFlags);
// We don't need to check if the size is too big since we only support
// WebRender backends.
if (aSize.IsEmpty()) {
return ImgDrawResult::BAD_ARGS;
// The aspect ratio flag was already handled as part of the SVG context
// restriction above.
uint32_t flags = aFlags & ~(FLAG_FORCE_PRESERVEASPECTRATIO_NONE);
auto rv = GetImageContainerImpl(aRenderer, aSize,
newSVGContext ? newSVGContext : aSVGContext,
aRegion, flags, aOutContainer);
// Invalidations may still be suspended if we had a refresh tick and there
// were no image containers remaining. If we created a new container, we
// should resume invalidations to allow animations to progress.
if (*aOutContainer && mRenderingObserver) {
mRenderingObserver->ResumeHonoringInvalidations();
}
if (mError) {
return ImgDrawResult::BAD_IMAGE;
}
if (!mIsFullyLoaded) {
return ImgDrawResult::NOT_READY;
}
if (mHaveAnimations && !(aFlags & FLAG_RECORD_BLOB)) {
// We don't support rasterizing animation SVGs. We can put them in a blob
// recording however instead of using fallback.
return ImgDrawResult::NOT_SUPPORTED;
}
AutoProfilerImagePaintMarker PROFILER_RAII(this);
#ifdef DEBUG
NotifyDrawingObservers();
#endif
// Only blob recordings support a region to restrict drawing.
const bool blobRecording = aFlags & FLAG_RECORD_BLOB;
MOZ_ASSERT_IF(!blobRecording, aRegion.isNothing());
LookupResult result(MatchType::NOT_FOUND);
auto playbackType =
mHaveAnimations ? PlaybackType::eAnimated : PlaybackType::eStatic;
auto surfaceFlags = ToSurfaceFlags(aFlags);
SurfaceKey surfaceKey =
VectorSurfaceKey(aSize, aRegion, aSVGContext, surfaceFlags, playbackType);
if ((aFlags & FLAG_SYNC_DECODE) || !(aFlags & FLAG_HIGH_QUALITY_SCALING)) {
result = SurfaceCache::Lookup(ImageKey(this), surfaceKey,
/* aMarkUsed = */ true);
} else {
result = SurfaceCache::LookupBestMatch(ImageKey(this), surfaceKey,
/* aMarkUsed = */ true);
}
// Unless we get a best match (exact or factor of 2 limited), then we want to
// generate a new recording/rerasterize, even if we have a substitute.
if (result && (result.Type() == MatchType::EXACT ||
result.Type() == MatchType::SUBSTITUTE_BECAUSE_BEST)) {
result.Surface().TakeProvider(aProvider);
return ImgDrawResult::SUCCESS;
}
// Ensure we store the surface with the correct key if we switched to factor
// of 2 sizing or we otherwise got clamped.
IntSize rasterSize(aSize);
if (!result.SuggestedSize().IsEmpty()) {
rasterSize = result.SuggestedSize();
surfaceKey = surfaceKey.CloneWithSize(rasterSize);
}
// We're about to rerasterize, which may mean that some of the previous
// surfaces we've rasterized aren't useful anymore. We can allow them to
// expire from the cache by unlocking them here, and then sending out an
// invalidation. If this image is locked, any surfaces that are still useful
// will become locked again when Draw touches them, and the remainder will
// eventually expire.
bool mayCache = SurfaceCache::CanHold(rasterSize);
if (mayCache) {
SurfaceCache::UnlockEntries(ImageKey(this));
}
// Blob recorded vector images just create a provider responsible for
// generating blob keys and recording bindings. The recording won't happen
// until the caller requests the key explicitly.
RefPtr<ISurfaceProvider> provider;
if (blobRecording) {
provider = MakeRefPtr<BlobSurfaceProvider>(ImageKey(this), surfaceKey,
mSVGDocumentWrapper, aFlags);
} else {
if (mSVGDocumentWrapper->IsDrawing()) {
NS_WARNING("Refusing to make re-entrant call to VectorImage::Draw");
return ImgDrawResult::TEMPORARY_ERROR;
}
// We aren't using blobs, so we need to rasterize.
float animTime =
mHaveAnimations ? mSVGDocumentWrapper->GetCurrentTimeAsFloat() : 0.0f;
// By using a null gfxContext, we ensure that we will always attempt to
// create a surface, even if we aren't capable of caching it (e.g. due to
// our flags, having an animation, etc). Otherwise CreateSurface will assume
// that the caller is capable of drawing directly to its own draw target if
// we cannot cache.
SVGDrawingParameters params(
nullptr, rasterSize, aSize, ImageRegion::Create(rasterSize),
SamplingFilter::POINT, aSVGContext, animTime, aFlags, 1.0);
RefPtr<gfxDrawable> svgDrawable = CreateSVGDrawable(params);
bool contextPaint = aSVGContext && aSVGContext->GetContextPaint();
AutoRestoreSVGState autoRestore(params, mSVGDocumentWrapper, contextPaint);
mSVGDocumentWrapper->UpdateViewportBounds(params.viewportSize);
mSVGDocumentWrapper->FlushImageTransformInvalidation();
// Given we have no context, the default backend is fine.
BackendType backend =
gfxPlatform::GetPlatform()->GetDefaultContentBackend();
// Try to create an imgFrame, initializing the surface it contains by
// drawing our gfxDrawable into it. (We use FILTER_NEAREST since we never
// scale here.)
auto frame = MakeNotNull<RefPtr<imgFrame>>();
nsresult rv = frame->InitWithDrawable(
svgDrawable, params.size, SurfaceFormat::OS_RGBA, SamplingFilter::POINT,
params.flags, backend);
// If we couldn't create the frame, it was probably because it would end
// up way too big. Generally it also wouldn't fit in the cache, but the
// prefs could be set such that the cache isn't the limiting factor.
if (NS_FAILED(rv)) {
return ImgDrawResult::TEMPORARY_ERROR;
}
provider =
MakeRefPtr<SimpleSurfaceProvider>(ImageKey(this), surfaceKey, frame);
}
if (mayCache) {
// Attempt to cache the frame.
if (SurfaceCache::Insert(WrapNotNull(provider)) == InsertOutcome::SUCCESS) {
if (rasterSize != aSize) {
// We created a new surface that wasn't the size we requested, which
// means we entered factor-of-2 mode. We should purge any surfaces we
// no longer need rather than waiting for the cache to expire them.
SurfaceCache::PruneImage(ImageKey(this));
}
SendFrameComplete(/* aDidCache */ true, aFlags);
}
}
MOZ_ASSERT(provider);
provider.forget(aProvider);
return ImgDrawResult::SUCCESS;
return rv;
}
bool VectorImage::MaybeRestrictSVGContext(

View File

@ -41,6 +41,8 @@ class VectorImage final : public ImageResource, public nsIStreamListener {
size_t GetNativeSizesLength() const override;
virtual size_t SizeOfSourceWithComputedFallback(
SizeOfState& aState) const override;
virtual void CollectSizeOfSurfaces(nsTArray<SurfaceMemoryCounter>& aCounters,
MallocSizeOf aMallocSizeOf) const override;
virtual nsresult OnImageDataAvailable(nsIRequest* aRequest,
nsISupports* aContext,
@ -81,6 +83,16 @@ class VectorImage final : public ImageResource, public nsIStreamListener {
private:
friend class SourceSurfaceBlobImage;
Tuple<ImgDrawResult, gfx::IntSize, RefPtr<gfx::SourceSurface>>
GetFrameInternal(const gfx::IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const Maybe<ImageIntRegion>& aRegion, uint32_t aWhichFrame,
uint32_t aFlags) override;
Tuple<ImgDrawResult, gfx::IntSize> GetImageContainerSize(
WindowRenderer* aRenderer, const gfx::IntSize& aSize,
uint32_t aFlags) override;
/**
* Attempt to find a matching cached surface in the SurfaceCache. Returns the
* cached surface, if found, and the size to rasterize at, if applicable.

View File

@ -1,65 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MOZILLA_IMAGE_WEBRENDERIMAGEPROVIDER_H_
#define MOZILLA_IMAGE_WEBRENDERIMAGEPROVIDER_H_
#include "nsISupportsImpl.h"
namespace mozilla {
namespace layers {
class RenderRootStateManager;
}
namespace wr {
class IpcResourceUpdateQueue;
struct ExternalImageId;
struct ImageKey;
} // namespace wr
namespace image {
class ImageResource;
using ImageProviderId = uint32_t;
class WebRenderImageProvider {
public:
// Subclasses may or may not be XPCOM classes, so we just require that they
// implement AddRef and Release.
NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
ImageProviderId GetProviderId() const { return mProviderId; }
static ImageProviderId AllocateProviderId();
/**
* Generate an ImageKey for the given frame.
* @param aSurface The current frame. This should match what was cached via
* SetCurrentFrame, but if it does not, it will need to
* regenerate the cached ImageKey.
*/
virtual nsresult UpdateKey(layers::RenderRootStateManager* aManager,
wr::IpcResourceUpdateQueue& aResources,
wr::ImageKey& aKey) {
return NS_ERROR_NOT_AVAILABLE;
}
/**
* Invalidate if a blob recording, requiring it to be regenerated.
*/
virtual void InvalidateRecording() {}
protected:
WebRenderImageProvider(const ImageResource* aImage);
private:
ImageProviderId mProviderId;
};
} // namespace image
} // namespace mozilla
#endif /* MOZILLA_IMAGE_WEBRENDERIMAGEPROVIDER_H_ */

View File

@ -680,6 +680,7 @@ void imgFrame::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
MonitorAutoLock lock(mMonitor);
AddSizeOfCbData metadata;
metadata.mSurface = mOptSurface ? mOptSurface.get() : mRawSurface.get();
metadata.mFinished = mFinished;
if (mOptSurface) {

View File

@ -168,6 +168,7 @@ class imgFrame {
AddSizeOfCbData()
: SourceSurface::SizeOfInfo(), mIndex(0), mFinished(false) {}
const gfx::SourceSurface* mSurface;
size_t mIndex;
bool mFinished;
};

View File

@ -48,7 +48,6 @@ namespace image {
class ImageRegion;
class ImageIntRegion;
class WebRenderImageProvider;
struct Orientation;
struct Resolution;
@ -71,7 +70,6 @@ native nsSize(nsSize);
[ptr] native nsIFrame(nsIFrame);
native TempRefImageContainer(already_AddRefed<mozilla::layers::ImageContainer>);
[ptr] native ImageContainer(mozilla::layers::ImageContainer);
[ptr] native WebRenderImageProvider(mozilla::image::WebRenderImageProvider);
[ref] native ImageRegion(mozilla::image::ImageRegion);
[ptr] native WindowRenderer(mozilla::WindowRenderer);
native Orientation(mozilla::image::Orientation);
@ -170,9 +168,9 @@ interface imgIContainer : nsISupports
readonly attribute boolean animated;
/**
* Provider ID for image providers created by this image.
* Producer ID for image containers created by this image.
*/
[infallible] readonly attribute unsigned long providerId;
[infallible] readonly attribute unsigned long producerId;
/**
* Flags for imgIContainer operations.
@ -326,11 +324,13 @@ interface imgIContainer : nsISupports
in uint32_t aFlags);
/**
* Attempts to find a WebRenderImageProvider containing the current frame at
* the given size. Match the requested size is best effort; it's not
* guaranteed that the surface you get will be a perfect match. (Some reasons
* you may get a surface of a different size include: if you requested
* upscaling, or if downscale-during-decode is disabled.)
* Attempts to create an ImageContainer (and Image) containing the current
* frame at the given size. Match the requested size is best effort; it's
* not guaranteed that the surface you get will be a perfect match. (Some
* reasons you may get a surface of a different size include: if you
* requested upscaling, or if downscale-during-decode is disabled.)
*
* Avoid calling this unless you're actually going to layerize this image.
*
* @param aRenderer The WindowRenderer which will be used to render the
* ImageContainer.
@ -341,16 +341,16 @@ interface imgIContainer : nsISupports
* @param aFlags Decoding / drawing flags (in other words, FLAG_* flags).
* Currently only FLAG_SYNC_DECODE and FLAG_SYNC_DECODE_IF_FAST
* are supported.
* @param aProvider Return value for WebRenderImageProvider for the current
* frame. May be null depending on the draw result.
* @param aContainer Return value for ImageContainer for the current frame.
* May be null depending on the draw result.
* @return The draw result for the current frame.
*/
[noscript, notxpcom] ImgDrawResult getImageProvider(in WindowRenderer aRenderer,
[const] in nsIntSize aSize,
[const] in MaybeSVGImageContext aSVGContext,
[const] in MaybeImageIntRegion aRegion,
in uint32_t aFlags,
out WebRenderImageProvider aProvider);
[noscript, notxpcom] ImgDrawResult getImageContainerAtSize(in WindowRenderer aRenderer,
[const] in nsIntSize aSize,
[const] in MaybeSVGImageContext aSVGContext,
[const] in MaybeImageIntRegion aRegion,
in uint32_t aFlags,
out ImageContainer aOutContainer);
/**
* Draw the requested frame of this image onto the context specified.

View File

@ -31,9 +31,9 @@ interface imgIRequest : nsIRequest
readonly attribute imgIContainer image;
/**
* Provider ID for image providers created by this image.
* Producer ID for image containers created by this image.
*/
[infallible] readonly attribute unsigned long providerId;
[infallible] readonly attribute unsigned long producerId;
/**
* Bits set in the return value from imageStatus

View File

@ -399,39 +399,6 @@ class imgMemoryReporter final : public nsIMemoryReporter {
/* aRadix = */ 16);
}
if (counter.Key().Region()) {
const ImageIntRegion& region = counter.Key().Region().ref();
const gfx::IntRect& rect = region.Rect();
surfacePathPrefix.AppendLiteral(", region:[ rect=(");
surfacePathPrefix.AppendInt(rect.x);
surfacePathPrefix.AppendLiteral(",");
surfacePathPrefix.AppendInt(rect.y);
surfacePathPrefix.AppendLiteral(") ");
surfacePathPrefix.AppendInt(rect.width);
surfacePathPrefix.AppendLiteral("x");
surfacePathPrefix.AppendInt(rect.height);
if (region.IsRestricted()) {
const gfx::IntRect& restrict = region.Restriction();
if (restrict == rect) {
surfacePathPrefix.AppendLiteral(", restrict=rect");
} else {
surfacePathPrefix.AppendLiteral(", restrict=(");
surfacePathPrefix.AppendInt(restrict.x);
surfacePathPrefix.AppendLiteral(",");
surfacePathPrefix.AppendInt(restrict.y);
surfacePathPrefix.AppendLiteral(") ");
surfacePathPrefix.AppendInt(restrict.width);
surfacePathPrefix.AppendLiteral("x");
surfacePathPrefix.AppendInt(restrict.height);
}
}
if (region.GetExtendMode() != gfx::ExtendMode::CLAMP) {
surfacePathPrefix.AppendLiteral(", extendMode=");
surfacePathPrefix.AppendInt(int32_t(region.GetExtendMode()));
}
surfacePathPrefix.AppendLiteral("]");
}
if (counter.Key().SVGContext()) {
const SVGImageContext& context = counter.Key().SVGContext().ref();
surfacePathPrefix.AppendLiteral(", svgContext:[ ");

View File

@ -667,15 +667,15 @@ imgRequestProxy::GetImage(imgIContainer** aImage) {
}
NS_IMETHODIMP
imgRequestProxy::GetProviderId(uint32_t* aId) {
imgRequestProxy::GetProducerId(uint32_t* aId) {
NS_ENSURE_TRUE(aId, NS_ERROR_NULL_POINTER);
nsCOMPtr<imgIContainer> image;
nsresult rv = GetImage(getter_AddRefs(image));
if (NS_SUCCEEDED(rv)) {
*aId = image->GetProviderId();
*aId = image->GetProducerId();
} else {
*aId = 0;
*aId = layers::kContainerProducerID_Invalid;
}
return NS_OK;

View File

@ -65,13 +65,12 @@ EXPORTS.mozilla.image += [
"ICOFileHeaders.h",
"ImageMemoryReporter.h",
"Resolution.h",
"WebRenderImageProvider.h",
"SourceSurfaceBlobImage.h",
]
UNIFIED_SOURCES += [
"AnimationFrameBuffer.cpp",
"AnimationSurfaceProvider.cpp",
"BlobSurfaceProvider.cpp",
"ClippedImage.cpp",
"DecodedSurfaceProvider.cpp",
"Decoder.cpp",
@ -99,6 +98,7 @@ UNIFIED_SOURCES += [
"ScriptedNotificationObserver.cpp",
"ShutdownTracker.cpp",
"SourceBuffer.cpp",
"SourceSurfaceBlobImage.cpp",
"SurfaceCache.cpp",
"SurfaceCacheUtils.cpp",
"SurfacePipe.cpp",

View File

@ -0,0 +1,107 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gtest/gtest.h"
#include "WindowRenderer.h"
#include "Common.h"
#include "imgIContainer.h"
#include "ImageFactory.h"
#include "ImageContainer.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/RefPtr.h"
#include "nsIInputStream.h"
#include "nsString.h"
#include "ProgressTracker.h"
using namespace mozilla;
using namespace mozilla::gfx;
using namespace mozilla::image;
class ImageContainers : public ::testing::Test {
protected:
AutoInitializeImageLib mInit;
};
TEST_F(ImageContainers, RasterImageContainer) {
ImageTestCase testCase = GreenPNGTestCase();
// Create an image.
RefPtr<Image> image = ImageFactory::CreateAnonymousImage(
nsDependentCString(testCase.mMimeType));
ASSERT_TRUE(!image->HasError());
nsCOMPtr<nsIInputStream> inputStream = LoadFile(testCase.mPath);
ASSERT_TRUE(inputStream);
// Figure out how much data we have.
uint64_t length;
nsresult rv = inputStream->Available(&length);
ASSERT_TRUE(NS_SUCCEEDED(rv));
// Write the data into the image.
rv = image->OnImageDataAvailable(nullptr, nullptr, inputStream, 0,
static_cast<uint32_t>(length));
ASSERT_TRUE(NS_SUCCEEDED(rv));
// Let the image know we've sent all the data.
rv = image->OnImageDataComplete(nullptr, nullptr, NS_OK, true);
ASSERT_TRUE(NS_SUCCEEDED(rv));
RefPtr<ProgressTracker> tracker = image->GetProgressTracker();
tracker->SyncNotifyProgress(FLAG_LOAD_COMPLETE);
RefPtr<WindowRenderer> renderer = new FallbackRenderer;
// Get at native size.
ImgDrawResult drawResult;
RefPtr<layers::ImageContainer> nativeContainer;
drawResult = image->GetImageContainerAtSize(
renderer, testCase.mSize, Nothing(), Nothing(),
imgIContainer::FLAG_SYNC_DECODE, getter_AddRefs(nativeContainer));
EXPECT_EQ(drawResult, ImgDrawResult::SUCCESS);
ASSERT_TRUE(nativeContainer != nullptr);
IntSize containerSize = nativeContainer->GetCurrentSize();
EXPECT_EQ(testCase.mSize.width, containerSize.width);
EXPECT_EQ(testCase.mSize.height, containerSize.height);
// Upscaling should give the native size.
IntSize requestedSize = testCase.mSize;
requestedSize.Scale(2, 2);
RefPtr<layers::ImageContainer> upscaleContainer;
drawResult = image->GetImageContainerAtSize(
renderer, requestedSize, Nothing(), Nothing(),
imgIContainer::FLAG_SYNC_DECODE |
imgIContainer::FLAG_HIGH_QUALITY_SCALING,
getter_AddRefs(upscaleContainer));
EXPECT_EQ(drawResult, ImgDrawResult::SUCCESS);
ASSERT_TRUE(upscaleContainer != nullptr);
containerSize = upscaleContainer->GetCurrentSize();
EXPECT_EQ(testCase.mSize.width, containerSize.width);
EXPECT_EQ(testCase.mSize.height, containerSize.height);
// Downscaling should give the downscaled size.
requestedSize = testCase.mSize;
requestedSize.width /= 2;
requestedSize.height /= 2;
RefPtr<layers::ImageContainer> downscaleContainer;
drawResult = image->GetImageContainerAtSize(
renderer, requestedSize, Nothing(), Nothing(),
imgIContainer::FLAG_SYNC_DECODE |
imgIContainer::FLAG_HIGH_QUALITY_SCALING,
getter_AddRefs(downscaleContainer));
EXPECT_EQ(drawResult, ImgDrawResult::SUCCESS);
ASSERT_TRUE(downscaleContainer != nullptr);
containerSize = downscaleContainer->GetCurrentSize();
EXPECT_EQ(requestedSize.width, containerSize.width);
EXPECT_EQ(requestedSize.height, containerSize.height);
// Get at native size again. Should give same container.
RefPtr<layers::ImageContainer> againContainer;
drawResult = image->GetImageContainerAtSize(
renderer, testCase.mSize, Nothing(), Nothing(),
imgIContainer::FLAG_SYNC_DECODE, getter_AddRefs(againContainer));
EXPECT_EQ(drawResult, ImgDrawResult::SUCCESS);
ASSERT_EQ(nativeContainer.get(), againContainer.get());
}

View File

@ -11,6 +11,7 @@ UNIFIED_SOURCES = [
"TestADAM7InterpolatingFilter.cpp",
"TestAnimationFrameBuffer.cpp",
"TestBlendAnimationFilter.cpp",
"TestContainers.cpp",
"TestCopyOnWrite.cpp",
"TestDeinterlacingFilter.cpp",
"TestFrameAnimator.cpp",

View File

@ -6608,32 +6608,26 @@ IntSize nsLayoutUtils::ComputeImageContainerDrawingParameters(
imgIContainer::FRAME_CURRENT, samplingFilter, aFlags);
}
// We only use the region rect with blob recordings. This is because when we
// rasterize an SVG image in process, we always create a complete
// rasterization of the whole image which can be given to any caller, while
// we support partial rasterization with the blob recordings.
if (aFlags & imgIContainer::FLAG_RECORD_BLOB) {
// If the dest rect contains the fill rect, then we are only displaying part
// of the vector image. We need to calculate the restriction region to avoid
// drawing more than we need, and sampling outside the desired bounds.
LayerIntRect clipRect = SnapRectForImage(itm, scaleFactors, aFillRect);
if (destRect.Contains(clipRect)) {
LayerIntRect restrictRect = destRect.Intersect(clipRect);
restrictRect.MoveBy(-destRect.TopLeft());
// If the dest rect contains the fill rect, then we are only displaying part
// of the vector image. We need to calculate the restriction region to avoid
// drawing more than we need, and sampling outside the desired bounds.
LayerIntRect clipRect = SnapRectForImage(itm, scaleFactors, aFillRect);
if (destRect.Contains(clipRect)) {
LayerIntRect restrictRect = destRect.Intersect(clipRect);
restrictRect.MoveBy(-destRect.TopLeft());
if (restrictRect.Width() < 1) {
restrictRect.SetWidth(1);
}
if (restrictRect.Height() < 1) {
restrictRect.SetHeight(1);
}
if (restrictRect.Width() < 1) {
restrictRect.SetWidth(1);
}
if (restrictRect.Height() < 1) {
restrictRect.SetHeight(1);
}
if (restrictRect.X() != 0 || restrictRect.Y() != 0 ||
restrictRect.Size() != destRect.Size()) {
IntRect sampleRect = restrictRect.ToUnknownRect();
aRegion = Some(ImageIntRegion::CreateWithSamplingRestriction(
sampleRect, sampleRect, ExtendMode::CLAMP));
}
if (restrictRect.X() != 0 || restrictRect.Y() != 0 ||
restrictRect.Size() != destRect.Size()) {
IntRect sampleRect = restrictRect.ToUnknownRect();
aRegion = Some(ImageIntRegion::CreateWithSamplingRestriction(
sampleRect, sampleRect, ExtendMode::CLAMP));
}
}

View File

@ -26,7 +26,6 @@
#include "mozilla/dom/HTMLAreaElement.h"
#include "mozilla/dom/HTMLImageElement.h"
#include "mozilla/dom/ResponsiveImageSelector.h"
#include "mozilla/image/WebRenderImageProvider.h"
#include "mozilla/layers/RenderRootStateManager.h"
#include "mozilla/layers/WebRenderLayerManager.h"
#include "mozilla/MouseEvents.h"
@ -999,8 +998,9 @@ void nsImageFrame::InvalidateSelf(const nsIntRect* aLayerInvalidRect,
// Check if WebRender has interacted with this frame. If it has
// we need to let it know that things have changed.
const auto type = DisplayItemType::TYPE_IMAGE;
const auto providerId = mImage ? mImage->GetProviderId() : 0;
if (WebRenderUserData::ProcessInvalidateForImage(this, type, providerId)) {
const auto producerId =
mImage ? mImage->GetProducerId() : kContainerProducerID_Invalid;
if (WebRenderUserData::ProcessInvalidateForImage(this, type, producerId)) {
return;
}
@ -1843,13 +1843,13 @@ ImgDrawResult nsImageFrame::DisplayAltFeedbackWithoutLayer(
nsLayoutUtils::ComputeImageContainerDrawingParameters(
imgCon, this, destRect, destRect, aSc, aFlags, svgContext,
region);
RefPtr<image::WebRenderImageProvider> provider;
result = imgCon->GetImageProvider(aManager->LayerManager(), decodeSize,
svgContext, region, aFlags,
getter_AddRefs(provider));
if (provider) {
bool wrResult = aManager->CommandBuilder().PushImageProvider(
aItem, provider, aBuilder, aResources, destRect, bounds);
RefPtr<ImageContainer> container;
result = imgCon->GetImageContainerAtSize(
aManager->LayerManager(), decodeSize, svgContext, region, aFlags,
getter_AddRefs(container));
if (container) {
bool wrResult = aManager->CommandBuilder().PushImage(
aItem, container, aBuilder, aResources, aSc, destRect, bounds);
result &= wrResult ? ImgDrawResult::SUCCESS : ImgDrawResult::NOT_READY;
} else {
// We don't use &= here because we want the result to be NOT_READY so
@ -2098,10 +2098,10 @@ bool nsDisplayImage::CreateWebRenderCommands(
IntSize decodeSize = nsLayoutUtils::ComputeImageContainerDrawingParameters(
mImage, mFrame, destRect, destRect, aSc, flags, svgContext, region);
RefPtr<image::WebRenderImageProvider> provider;
ImgDrawResult drawResult =
mImage->GetImageProvider(aManager->LayerManager(), decodeSize, svgContext,
region, flags, getter_AddRefs(provider));
RefPtr<layers::ImageContainer> container;
ImgDrawResult drawResult = mImage->GetImageContainerAtSize(
aManager->LayerManager(), decodeSize, svgContext, region, flags,
getter_AddRefs(container));
// While we got a container, it may not contain a fully decoded surface. If
// that is the case, and we have an image we were previously displaying which
@ -2123,13 +2123,13 @@ bool nsDisplayImage::CreateWebRenderCommands(
prevFlags &= ~imgIContainer::FLAG_RECORD_BLOB;
}
RefPtr<image::WebRenderImageProvider> prevProvider;
ImgDrawResult newDrawResult = mPrevImage->GetImageProvider(
RefPtr<ImageContainer> prevContainer;
ImgDrawResult newDrawResult = mPrevImage->GetImageContainerAtSize(
aManager->LayerManager(), decodeSize, svgContext, region, prevFlags,
getter_AddRefs(prevProvider));
if (prevProvider && newDrawResult == ImgDrawResult::SUCCESS) {
getter_AddRefs(prevContainer));
if (prevContainer && newDrawResult == ImgDrawResult::SUCCESS) {
drawResult = newDrawResult;
provider = std::move(prevProvider);
container = std::move(prevContainer);
flags = prevFlags;
break;
}
@ -2156,9 +2156,14 @@ bool nsDisplayImage::CreateWebRenderCommands(
// If the image container is empty, we don't want to fallback. Any other
// failure will be due to resource constraints and fallback is unlikely to
// help us. Hence we can ignore the return value from PushImage.
if (provider) {
aManager->CommandBuilder().PushImageProvider(
this, provider, aBuilder, aResources, destRect, destRect);
if (container) {
if (flags & imgIContainer::FLAG_RECORD_BLOB) {
aManager->CommandBuilder().PushBlobImage(this, container, aBuilder,
aResources, destRect, destRect);
} else {
aManager->CommandBuilder().PushImage(this, container, aBuilder,
aResources, aSc, destRect, destRect);
}
}
nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, drawResult);

View File

@ -29,7 +29,6 @@
#include "nsStyleStruct.h"
#include "gfx2DGlue.h"
#include "gfxGradientCache.h"
#include "mozilla/image/WebRenderImageProvider.h"
#include "mozilla/layers/StackingContextHelper.h"
#include "mozilla/layers/RenderRootStateManager.h"
#include "mozilla/layers/WebRenderLayerManager.h"
@ -3629,17 +3628,20 @@ ImgDrawResult nsCSSBorderImageRenderer::CreateWebRenderCommands(
img, aForFrame, imageRect, imageRect, aSc, flags, svgContext,
region);
RefPtr<WebRenderImageProvider> provider;
drawResult = img->GetImageProvider(aManager->LayerManager(), decodeSize,
svgContext, region, flags,
getter_AddRefs(provider));
if (!provider) {
RefPtr<layers::ImageContainer> container;
drawResult = img->GetImageContainerAtSize(
aManager->LayerManager(), decodeSize, svgContext, region, flags,
getter_AddRefs(container));
if (!container) {
break;
}
Maybe<wr::ImageKey> key =
aManager->CommandBuilder().CreateImageProviderKey(aItem, provider,
aResources);
auto rendering =
wr::ToImageRendering(aItem->Frame()->UsedImageRendering());
gfx::IntSize size;
Maybe<wr::ImageKey> key = aManager->CommandBuilder().CreateImageKey(
aItem, container, aBuilder, aResources, rendering, aSc, size,
Nothing());
if (key.isNothing()) {
break;
}
@ -3654,8 +3656,6 @@ ImgDrawResult nsCSSBorderImageRenderer::CreateWebRenderCommands(
// but there are reftests that are sensible to the test going through a
// blob while the reference doesn't.
if (noVerticalBorders && noHorizontalBorders) {
auto rendering =
wr::ToImageRendering(aItem->Frame()->UsedImageRendering());
aBuilder.PushImage(dest, clip, !aItem->BackfaceIsHidden(), rendering,
key.value());
break;

View File

@ -14,7 +14,6 @@
#include "gfxDrawable.h"
#include "ImageOps.h"
#include "ImageRegion.h"
#include "mozilla/image/WebRenderImageProvider.h"
#include "mozilla/layers/RenderRootStateManager.h"
#include "mozilla/layers/StackingContextHelper.h"
#include "mozilla/layers/WebRenderLayerManager.h"
@ -622,29 +621,39 @@ ImgDrawResult nsImageRenderer::BuildWebRenderDisplayItems(
mImageContainer, mForFrame, destRect, clipRect, aSc,
containerFlags, svgContext, region);
RefPtr<image::WebRenderImageProvider> provider;
drawResult = mImageContainer->GetImageProvider(
if (extendMode != ExtendMode::CLAMP) {
region = Nothing();
}
RefPtr<layers::ImageContainer> container;
drawResult = mImageContainer->GetImageContainerAtSize(
aManager->LayerManager(), decodeSize, svgContext, region,
containerFlags, getter_AddRefs(provider));
if (!provider) {
containerFlags, getter_AddRefs(container));
if (!container) {
NS_WARNING("Failed to get image container");
break;
}
Maybe<wr::ImageKey> key =
aManager->CommandBuilder().CreateImageProviderKey(aItem, provider,
aResources);
if (key.isNothing()) {
if (containerFlags & imgIContainer::FLAG_RECORD_BLOB) {
MOZ_ASSERT(extendMode == ExtendMode::CLAMP);
aManager->CommandBuilder().PushBlobImage(
aItem, container, aBuilder, aResources, clipRect, clipRect);
break;
}
auto rendering =
wr::ToImageRendering(aItem->Frame()->UsedImageRendering());
wr::LayoutRect clip = wr::ToLayoutRect(clipRect);
gfx::IntSize size;
Maybe<wr::ImageKey> key = aManager->CommandBuilder().CreateImageKey(
aItem, container, aBuilder, aResources, rendering, aSc, size,
Nothing());
// If we provided a region to the provider, then it already took the
// dest rect into account when it did the recording.
wr::LayoutRect dest = region ? clip : wr::ToLayoutRect(destRect);
if (key.isNothing()) {
break;
}
wr::LayoutRect dest = wr::ToLayoutRect(destRect);
wr::LayoutRect clip = wr::ToLayoutRect(clipRect);
if (extendMode == ExtendMode::CLAMP) {
// The image is not repeating. Just push as a regular image.

View File

@ -540,9 +540,9 @@ static void InvalidateImages(nsIFrame* aFrame, imgIRequest* aRequest,
static_cast<layers::WebRenderMaskData*>(data.get())->Invalidate();
invalidateFrame = true;
break;
case layers::WebRenderUserData::UserDataType::eImageProvider:
if (static_cast<layers::WebRenderImageProviderData*>(data.get())
->Invalidate(aRequest->GetProviderId())) {
case layers::WebRenderUserData::UserDataType::eImage:
if (static_cast<layers::WebRenderImageData*>(data.get())
->UsingSharedSurface(aRequest->GetProducerId())) {
break;
}
[[fallthrough]];

View File

@ -10,7 +10,6 @@
#include "gfxContext.h"
#include "gfxPlatform.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/image/WebRenderImageProvider.h"
#include "mozilla/layers/RenderRootStateManager.h"
#include "mozilla/layers/WebRenderLayerManager.h"
#include "imgIContainer.h"
@ -621,10 +620,10 @@ bool SVGImageFrame::CreateWebRenderCommands(
mImageContainer, this, destRect, clipRect, aSc, flags, svgContext,
region);
RefPtr<image::WebRenderImageProvider> provider;
ImgDrawResult drawResult = mImageContainer->GetImageProvider(
RefPtr<layers::ImageContainer> container;
ImgDrawResult drawResult = mImageContainer->GetImageContainerAtSize(
aManager->LayerManager(), decodeSize, svgContext, region, flags,
getter_AddRefs(provider));
getter_AddRefs(container));
// While we got a container, it may not contain a fully decoded surface. If
// that is the case, and we have an image we were previously displaying which
@ -648,9 +647,14 @@ bool SVGImageFrame::CreateWebRenderCommands(
// If the image container is empty, we don't want to fallback. Any other
// failure will be due to resource constraints and fallback is unlikely to
// help us. Hence we can ignore the return value from PushImage.
if (provider) {
aManager->CommandBuilder().PushImageProvider(
aItem, provider, aBuilder, aResources, destRect, clipRect);
if (container) {
if (flags & imgIContainer::FLAG_RECORD_BLOB) {
aManager->CommandBuilder().PushBlobImage(
aItem, container, aBuilder, aResources, destRect, clipRect);
} else {
aManager->CommandBuilder().PushImage(
aItem, container, aBuilder, aResources, aSc, destRect, clipRect);
}
}
nsDisplayItemGenericImageGeometry::UpdateDrawResult(aItem, drawResult);

View File

@ -51,7 +51,6 @@
#include "mozilla/StaticPrefs_image.h"
#include "mozilla/SVGImageContext.h"
#include "Units.h"
#include "mozilla/image/WebRenderImageProvider.h"
#include "mozilla/layers/RenderRootStateManager.h"
#include "mozilla/layers/WebRenderLayerManager.h"
#include "mozilla/dom/ImageTracker.h"
@ -429,25 +428,39 @@ ImgDrawResult nsImageBoxFrame::CreateWebRenderCommands(
imgCon, aItem->Frame(), fillRect, fillRect, aSc, aFlags, svgContext,
region);
RefPtr<image::WebRenderImageProvider> provider;
result =
imgCon->GetImageProvider(aManager->LayerManager(), decodeSize, svgContext,
region, aFlags, getter_AddRefs(provider));
if (!provider) {
NS_WARNING("Failed to get image provider");
RefPtr<layers::ImageContainer> container;
result = imgCon->GetImageContainerAtSize(aManager->LayerManager(), decodeSize,
svgContext, region, aFlags,
getter_AddRefs(container));
if (!container) {
NS_WARNING("Failed to get image container");
return result;
}
auto rendering = wr::ToImageRendering(aItem->Frame()->UsedImageRendering());
wr::LayoutRect fill = wr::ToLayoutRect(fillRect);
Maybe<wr::ImageKey> key = aManager->CommandBuilder().CreateImageProviderKey(
aItem, provider, aResources);
if (aFlags & imgIContainer::FLAG_RECORD_BLOB) {
Maybe<wr::BlobImageKey> key = aManager->CommandBuilder().CreateBlobImageKey(
aItem, container, aResources);
if (key.isNothing()) {
return result;
}
aBuilder.PushImage(fill, fill, !BackfaceIsHidden(), rendering,
wr::AsImageKey(key.value()));
return result;
}
gfx::IntSize size;
Maybe<wr::ImageKey> key = aManager->CommandBuilder().CreateImageKey(
aItem, container, aBuilder, aResources, rendering, aSc, size, Nothing());
if (key.isNothing()) {
return result;
}
aBuilder.PushImage(fill, fill, !BackfaceIsHidden(), rendering, key.value());
return result;
}
@ -828,8 +841,8 @@ void nsImageBoxFrame::OnFrameUpdate(imgIRequest* aRequest) {
// Check if WebRender has interacted with this frame. If it has
// we need to let it know that things have changed.
const auto type = DisplayItemType::TYPE_XUL_IMAGE;
const auto providerId = aRequest->GetProviderId();
if (WebRenderUserData::ProcessInvalidateForImage(this, type, providerId)) {
const auto producerId = aRequest->GetProducerId();
if (WebRenderUserData::ProcessInvalidateForImage(this, type, producerId)) {
return;
}