Bug 1125055 - Sync decode layerized images if necessary. r=roc,tn

This commit is contained in:
Seth Fowler 2015-03-17 19:40:16 -07:00
Родитель 38b5cf43f0
Коммит 726d770b60
16 изменённых файлов: 142 добавлений и 100 удалений

Просмотреть файл

@ -98,7 +98,7 @@ native nsIntRectByVal(nsIntRect);
[ref] native nsIntSize(nsIntSize);
native nsSize(nsSize);
[ptr] native nsIFrame(nsIFrame);
[ptr] native ImageContainer(mozilla::layers::ImageContainer);
native TempRefImageContainer(already_AddRefed<mozilla::layers::ImageContainer>);
[ref] native ImageRegion(mozilla::image::ImageRegion);
[ptr] native LayerManager(mozilla::layers::LayerManager);
native Orientation(mozilla::image::Orientation);
@ -116,7 +116,7 @@ native nsIntSizeByVal(nsIntSize);
*
* Internally, imgIContainer also manages animation of images.
*/
[scriptable, builtinclass, uuid(9a43298b-bf49-44fc-9abe-9ff702f1bd25)]
[scriptable, builtinclass, uuid(44fbd7d5-e417-4d31-ae4a-8ad61d07eb3c)]
interface imgIContainer : nsISupports
{
/**
@ -277,8 +277,17 @@ interface imgIContainer : nsISupports
/**
* Attempts to create an ImageContainer (and Image) containing the current
* frame. Only valid for RASTER type images.
*
* @param aManager The LayerManager which will be used to create the
* ImageContainer.
* @param aFlags Decoding / drawing flags (in other words, FLAG_* flags).
* Currently only FLAG_SYNC_DECODE and FLAG_SYNC_DECODE_IF_FAST
* are supported.
* @return An ImageContainer for the current frame, or nullptr if one could
* not be created.
*/
[noscript] ImageContainer getImageContainer(in LayerManager aManager);
[noscript, notxpcom] TempRefImageContainer getImageContainer(in LayerManager aManager,
in uint32_t aFlags);
/**
* Draw the requested frame of this image onto the context specified.

Просмотреть файл

@ -266,8 +266,8 @@ ClippedImage::GetFrameInternal(const nsIntSize& aSize,
return mCachedSurface->Surface();
}
NS_IMETHODIMP
ClippedImage::GetImageContainer(LayerManager* aManager, ImageContainer** _retval)
NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
ClippedImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
{
// 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
@ -276,11 +276,10 @@ ClippedImage::GetImageContainer(LayerManager* aManager, ImageContainer** _retval
// that method for performance reasons.
if (!ShouldClip()) {
return InnerImage()->GetImageContainer(aManager, _retval);
return InnerImage()->GetImageContainer(aManager, aFlags);
}
*_retval = nullptr;
return NS_OK;
return nullptr;
}
static bool

Просмотреть файл

@ -37,8 +37,9 @@ public:
NS_IMETHOD GetIntrinsicRatio(nsSize* aRatio) MOZ_OVERRIDE;
NS_IMETHOD_(TemporaryRef<SourceSurface>)
GetFrame(uint32_t aWhichFrame, uint32_t aFlags) MOZ_OVERRIDE;
NS_IMETHOD GetImageContainer(layers::LayerManager* aManager,
layers::ImageContainer** _retval) MOZ_OVERRIDE;
NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)
GetImageContainer(layers::LayerManager* aManager,
uint32_t aFlags) MOZ_OVERRIDE;
NS_IMETHOD_(DrawResult) Draw(gfxContext* aContext,
const nsIntSize& aSize,
const ImageRegion& aRegion,

Просмотреть файл

@ -205,12 +205,10 @@ DynamicImage::IsOpaque()
return false;
}
NS_IMETHODIMP
DynamicImage::GetImageContainer(LayerManager* aManager,
ImageContainer** _retval)
NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
DynamicImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
{
*_retval = nullptr;
return NS_OK;
return nullptr;
}
NS_IMETHODIMP_(DrawResult)

Просмотреть файл

@ -44,18 +44,15 @@ FrozenImage::GetFrame(uint32_t aWhichFrame,
return InnerImage()->GetFrame(FRAME_FIRST, aFlags);
}
NS_IMETHODIMP
FrozenImage::GetImageContainer(layers::LayerManager* aManager,
layers::ImageContainer** _retval)
NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
FrozenImage::GetImageContainer(layers::LayerManager* aManager, uint32_t aFlags)
{
// XXX(seth): GetImageContainer does not currently support anything but the
// current frame. We work around this by always returning null, but if it ever
// turns out that FrozenImage is widely used on codepaths that can actually
// benefit from GetImageContainer, it would be a good idea to fix that method
// for performance reasons.
*_retval = nullptr;
return NS_OK;
return nullptr;
}
NS_IMETHODIMP_(DrawResult)

Просмотреть файл

@ -37,8 +37,9 @@ public:
NS_IMETHOD GetAnimated(bool* aAnimated) MOZ_OVERRIDE;
NS_IMETHOD_(TemporaryRef<SourceSurface>)
GetFrame(uint32_t aWhichFrame, uint32_t aFlags) MOZ_OVERRIDE;
NS_IMETHOD GetImageContainer(layers::LayerManager* aManager,
layers::ImageContainer** _retval) MOZ_OVERRIDE;
NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)
GetImageContainer(layers::LayerManager* aManager,
uint32_t aFlags) MOZ_OVERRIDE;
NS_IMETHOD_(DrawResult) Draw(gfxContext* aContext,
const nsIntSize& aSize,
const ImageRegion& aRegion,

Просмотреть файл

@ -192,11 +192,10 @@ ImageWrapper::IsOpaque()
return mInnerImage->IsOpaque();
}
NS_IMETHODIMP
ImageWrapper::GetImageContainer(LayerManager* aManager,
ImageContainer** _retval)
NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
ImageWrapper::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
{
return mInnerImage->GetImageContainer(aManager, _retval);
return mInnerImage->GetImageContainer(aManager, aFlags);
}
NS_IMETHODIMP_(DrawResult)

Просмотреть файл

@ -122,9 +122,8 @@ OrientedImage::GetFrame(uint32_t aWhichFrame,
return target->Snapshot();
}
NS_IMETHODIMP
OrientedImage::GetImageContainer(LayerManager* aManager,
ImageContainer** _retval)
NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
OrientedImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
{
// 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
@ -133,11 +132,10 @@ OrientedImage::GetImageContainer(LayerManager* aManager,
// that method for performance reasons.
if (mOrientation.IsIdentity()) {
return InnerImage()->GetImageContainer(aManager, _retval);
return InnerImage()->GetImageContainer(aManager, aFlags);
}
*_retval = nullptr;
return NS_OK;
return nullptr;
}
struct MatrixBuilder

Просмотреть файл

@ -34,8 +34,9 @@ public:
NS_IMETHOD GetIntrinsicRatio(nsSize* aRatio) MOZ_OVERRIDE;
NS_IMETHOD_(TemporaryRef<SourceSurface>)
GetFrame(uint32_t aWhichFrame, uint32_t aFlags) MOZ_OVERRIDE;
NS_IMETHOD GetImageContainer(layers::LayerManager* aManager,
layers::ImageContainer** _retval) MOZ_OVERRIDE;
NS_IMETHOD_(already_AddRefed<layers::ImageContainer>)
GetImageContainer(layers::LayerManager* aManager,
uint32_t aFlags) MOZ_OVERRIDE;
NS_IMETHOD_(DrawResult) Draw(gfxContext* aContext,
const nsIntSize& aSize,
const ImageRegion& aRegion,

Просмотреть файл

@ -256,6 +256,7 @@ RasterImage::RasterImage(ProgressTracker* aProgressTracker,
mLockCount(0),
mDecodeCount(0),
mRequestedSampleSize(0),
mLastImageContainerDrawResult(DrawResult::NOT_READY),
#ifdef DEBUG
mFramesNotified(0),
#endif
@ -727,19 +728,21 @@ NS_IMETHODIMP_(TemporaryRef<SourceSurface>)
RasterImage::GetFrame(uint32_t aWhichFrame,
uint32_t aFlags)
{
return GetFrameInternal(aWhichFrame, aFlags);
return GetFrameInternal(aWhichFrame, aFlags).second().forget();
}
TemporaryRef<SourceSurface>
Pair<DrawResult, RefPtr<SourceSurface>>
RasterImage::GetFrameInternal(uint32_t aWhichFrame, uint32_t aFlags)
{
MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE);
if (aWhichFrame > FRAME_MAX_VALUE)
return nullptr;
if (aWhichFrame > FRAME_MAX_VALUE) {
return MakePair(DrawResult::BAD_ARGS, RefPtr<SourceSurface>());
}
if (mError)
return nullptr;
if (mError) {
return MakePair(DrawResult::BAD_IMAGE, 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
@ -748,7 +751,7 @@ RasterImage::GetFrameInternal(uint32_t aWhichFrame, uint32_t aFlags)
LookupFrame(GetRequestedFrameIndex(aWhichFrame), mSize, aFlags);
if (!frameRef) {
// The OS threw this frame away and we couldn't redecode it.
return nullptr;
return MakePair(DrawResult::TEMPORARY_ERROR, RefPtr<SourceSurface>());
}
// If this frame covers the entire image, we can just reuse its existing
@ -767,50 +770,57 @@ RasterImage::GetFrameInternal(uint32_t aWhichFrame, uint32_t aFlags)
frameSurf = CopyFrame(aWhichFrame, aFlags);
}
return frameSurf;
if (!frameRef->IsImageComplete()) {
return MakePair(DrawResult::INCOMPLETE, Move(frameSurf));
}
return MakePair(DrawResult::SUCCESS, Move(frameSurf));
}
already_AddRefed<layers::Image>
RasterImage::GetCurrentImage(ImageContainer* aContainer)
Pair<DrawResult, nsRefPtr<layers::Image>>
RasterImage::GetCurrentImage(ImageContainer* aContainer, uint32_t aFlags)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aContainer);
RefPtr<SourceSurface> surface =
GetFrameInternal(FRAME_CURRENT, FLAG_ASYNC_NOTIFY);
if (!surface) {
auto result = GetFrameInternal(FRAME_CURRENT, aFlags | FLAG_ASYNC_NOTIFY);
if (!result.second()) {
// 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 nullptr;
return MakePair(result.first(), nsRefPtr<layers::Image>());
}
CairoImage::Data cairoData;
GetWidth(&cairoData.mSize.width);
GetHeight(&cairoData.mSize.height);
cairoData.mSourceSurface = surface;
cairoData.mSourceSurface = result.second();
nsRefPtr<layers::Image> image =
aContainer->CreateImage(ImageFormat::CAIRO_SURFACE);
NS_ASSERTION(image, "Failed to create Image");
MOZ_ASSERT(image);
static_cast<CairoImage*>(image.get())->SetData(cairoData);
return image.forget();
return MakePair(result.first(), Move(image));
}
NS_IMETHODIMP
RasterImage::GetImageContainer(LayerManager* aManager, ImageContainer **_retval)
NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
RasterImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aManager);
MOZ_ASSERT((aFlags & ~(FLAG_SYNC_DECODE |
FLAG_SYNC_DECODE_IF_FAST |
FLAG_ASYNC_NOTIFY))
== FLAG_NONE,
"Unsupported flag passed to GetImageContainer");
int32_t maxTextureSize = aManager->GetMaxTextureSize();
if (!mHasSize ||
mSize.width > maxTextureSize ||
mSize.height > maxTextureSize) {
*_retval = nullptr;
return NS_OK;
return nullptr;
}
if (IsUnlocked() && mProgressTracker) {
@ -818,28 +828,34 @@ RasterImage::GetImageContainer(LayerManager* aManager, ImageContainer **_retval)
}
nsRefPtr<layers::ImageContainer> container = mImageContainer.get();
if (container) {
container.forget(_retval);
return NS_OK;
bool mustRedecode =
(aFlags & (FLAG_SYNC_DECODE | FLAG_SYNC_DECODE_IF_FAST)) &&
mLastImageContainerDrawResult != DrawResult::SUCCESS &&
mLastImageContainerDrawResult != DrawResult::BAD_IMAGE;
if (container && !mustRedecode) {
return container.forget();
}
// We need a new ImageContainer, so create one.
container = LayerManager::CreateImageContainer();
nsRefPtr<layers::Image> image = GetCurrentImage(container);
if (!image) {
return NS_ERROR_NOT_AVAILABLE;
auto result = GetCurrentImage(container, aFlags);
if (!result.second()) {
// We couldn't get an Image.
return nullptr;
}
// |image| holds a reference to a SourceSurface which in turn holds a lock on
// the current frame's VolatileBuffer, ensuring that it doesn't get freed as
// long as the layer system keeps this ImageContainer alive.
container->SetCurrentImageInTransaction(image);
// |result.second()| holds a reference to a SourceSurface which in turn holds
// a lock on the current frame's VolatileBuffer, ensuring that it doesn't get
// freed as long as the layer system keeps this ImageContainer alive.
container->SetCurrentImageInTransaction(result.second());
mLastImageContainerDrawResult = result.first();
mImageContainer = container;
container.forget(_retval);
return NS_OK;
return container.forget();
}
void
@ -852,12 +868,14 @@ RasterImage::UpdateImageContainer()
return;
}
nsRefPtr<layers::Image> image = GetCurrentImage(container);
if (!image) {
auto result = GetCurrentImage(container, FLAG_NONE);
if (!result.second()) {
// We couldn't get an Image.
return;
}
container->SetCurrentImage(image);
mLastImageContainerDrawResult = result.first();
container->SetCurrentImage(result.second());
}
size_t

Просмотреть файл

@ -30,6 +30,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/Maybe.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/Pair.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/WeakPtr.h"
#include "mozilla/UniquePtr.h"
@ -297,8 +298,9 @@ private:
TemporaryRef<gfx::SourceSurface> CopyFrame(uint32_t aWhichFrame,
uint32_t aFlags);
TemporaryRef<gfx::SourceSurface> GetFrameInternal(uint32_t aWhichFrame,
uint32_t aFlags);
Pair<DrawResult, RefPtr<gfx::SourceSurface>>
GetFrameInternal(uint32_t aWhichFrame, uint32_t aFlags);
DrawableFrameRef LookupFrameInternal(uint32_t aFrameNum,
const gfx::IntSize& aSize,
@ -314,8 +316,9 @@ private:
size_t SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation,
MallocSizeOf aMallocSizeOf) const;
already_AddRefed<layers::Image>
GetCurrentImage(layers::ImageContainer* aContainer);
Pair<DrawResult, nsRefPtr<layers::Image>>
GetCurrentImage(layers::ImageContainer* aContainer, uint32_t aFlags);
void UpdateImageContainer();
// We would like to just check if we have a zero lock count, but we can't do
@ -381,6 +384,10 @@ private: // data
// the layer system needs it.
WeakPtr<layers::ImageContainer> mImageContainer;
// If mImageContainer is non-null, this contains the DrawResult we obtained
// the last time we updated it.
DrawResult mLastImageContainerDrawResult;
#ifdef DEBUG
uint32_t mFramesNotified;
#endif

Просмотреть файл

@ -697,12 +697,10 @@ VectorImage::GetFrame(uint32_t aWhichFrame,
//******************************************************************************
/* [noscript] ImageContainer getImageContainer(); */
NS_IMETHODIMP
VectorImage::GetImageContainer(LayerManager* aManager,
layers::ImageContainer** _retval)
NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
VectorImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags)
{
*_retval = nullptr;
return NS_OK;
return nullptr;
}
struct SVGDrawingParameters

Просмотреть файл

@ -5195,13 +5195,11 @@ nsImageRenderer::IsAnimatedImage()
already_AddRefed<mozilla::layers::ImageContainer>
nsImageRenderer::GetContainer(LayerManager* aManager)
{
if (mType != eStyleImageType_Image || !mImageContainer)
if (mType != eStyleImageType_Image || !mImageContainer) {
return nullptr;
}
nsRefPtr<ImageContainer> container;
nsresult rv = mImageContainer->GetImageContainer(aManager, getter_AddRefs(container));
NS_ENSURE_SUCCESS(rv, nullptr);
return container.forget();
return mImageContainer->GetImageContainer(aManager, imgIContainer::FLAG_NONE);
}
#define MAX_BLUR_RADIUS 300

Просмотреть файл

@ -1427,9 +1427,11 @@ already_AddRefed<ImageContainer>
nsDisplayImage::GetContainer(LayerManager* aManager,
nsDisplayListBuilder* aBuilder)
{
nsRefPtr<ImageContainer> container;
mImage->GetImageContainer(aManager, getter_AddRefs(container));
return container.forget();
uint32_t flags = aBuilder->ShouldSyncDecodeImages()
? imgIContainer::FLAG_SYNC_DECODE
: imgIContainer::FLAG_NONE;
return mImage->GetImageContainer(aManager, flags);
}
gfxRect
@ -1489,8 +1491,12 @@ nsDisplayImage::GetLayerState(nsDisplayListBuilder* aBuilder,
}
}
nsRefPtr<ImageContainer> container;
mImage->GetImageContainer(aManager, getter_AddRefs(container));
uint32_t flags = aBuilder->ShouldSyncDecodeImages()
? imgIContainer::FLAG_SYNC_DECODE
: imgIContainer::FLAG_NONE;
nsRefPtr<ImageContainer> container =
mImage->GetImageContainer(aManager, flags);
if (!container) {
return LAYER_NONE;
}
@ -1534,9 +1540,15 @@ nsDisplayImage::BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aParameters)
{
nsRefPtr<ImageContainer> container;
nsresult rv = mImage->GetImageContainer(aManager, getter_AddRefs(container));
NS_ENSURE_SUCCESS(rv, nullptr);
uint32_t flags = aBuilder->ShouldSyncDecodeImages()
? imgIContainer::FLAG_SYNC_DECODE
: imgIContainer::FLAG_NONE;
nsRefPtr<ImageContainer> container =
mImage->GetImageContainer(aManager, flags);
if (!container) {
return nullptr;
}
nsRefPtr<ImageLayer> layer = static_cast<ImageLayer*>
(aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this));

Просмотреть файл

@ -433,13 +433,18 @@ nsDisplayXULImage::ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& aOffset)
}
already_AddRefed<ImageContainer>
nsDisplayXULImage::GetContainer(LayerManager* aManager, nsDisplayListBuilder* aBuilder)
nsDisplayXULImage::GetContainer(LayerManager* aManager,
nsDisplayListBuilder* aBuilder)
{
return static_cast<nsImageBoxFrame*>(mFrame)->GetContainer(aManager);
uint32_t flags = aBuilder->ShouldSyncDecodeImages()
? imgIContainer::FLAG_SYNC_DECODE
: imgIContainer::FLAG_NONE;
return static_cast<nsImageBoxFrame*>(mFrame)->GetContainer(aManager, flags);
}
already_AddRefed<ImageContainer>
nsImageBoxFrame::GetContainer(LayerManager* aManager)
nsImageBoxFrame::GetContainer(LayerManager* aManager, uint32_t aFlags)
{
bool hasSubRect = !mUseSrcAttr && (mSubRect.width > 0 || mSubRect.height > 0);
if (hasSubRect || !mImageRequest) {
@ -452,9 +457,7 @@ nsImageBoxFrame::GetContainer(LayerManager* aManager)
return nullptr;
}
nsRefPtr<ImageContainer> container;
imgCon->GetImageContainer(aManager, getter_AddRefs(container));
return container.forget();
return imgCon->GetImageContainer(aManager, aFlags);
}

Просмотреть файл

@ -41,6 +41,7 @@ class nsImageBoxFrame MOZ_FINAL : public nsLeafBoxFrame
{
public:
typedef mozilla::image::DrawResult DrawResult;
typedef mozilla::layers::ImageContainer ImageContainer;
typedef mozilla::layers::LayerManager LayerManager;
friend class nsDisplayXULImage;
@ -95,7 +96,9 @@ public:
const nsRect& aDirtyRect,
nsPoint aPt, uint32_t aFlags);
already_AddRefed<mozilla::layers::ImageContainer> GetContainer(LayerManager* aManager);
already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager,
uint32_t aFlags);
protected:
explicit nsImageBoxFrame(nsStyleContext* aContext);