Bug 1185800 - Add DecoderFlags and SurfaceFlags enum classes and use them instead of imgIContainer flags in all decoder-related code. r=tn

This commit is contained in:
Seth Fowler 2015-08-14 17:56:44 -07:00
parent 34ac6552ef
commit f89ca1d90f
19 changed files with 278 additions and 171 deletions

View File

@ -47,35 +47,37 @@ public:
static void Dispatch(RasterImage* aImage,
Progress aProgress,
const nsIntRect& aInvalidRect,
uint32_t aFlags)
SurfaceFlags aSurfaceFlags)
{
MOZ_ASSERT(aImage);
nsCOMPtr<nsIRunnable> worker =
new NotifyProgressWorker(aImage, aProgress, aInvalidRect, aFlags);
new NotifyProgressWorker(aImage, aProgress, aInvalidRect, aSurfaceFlags);
NS_DispatchToMainThread(worker);
}
NS_IMETHOD Run() override
{
MOZ_ASSERT(NS_IsMainThread());
mImage->NotifyProgress(mProgress, mInvalidRect, mFlags);
mImage->NotifyProgress(mProgress, mInvalidRect, mSurfaceFlags);
return NS_OK;
}
private:
NotifyProgressWorker(RasterImage* aImage, Progress aProgress,
const nsIntRect& aInvalidRect, uint32_t aFlags)
NotifyProgressWorker(RasterImage* aImage,
Progress aProgress,
const nsIntRect& aInvalidRect,
SurfaceFlags aSurfaceFlags)
: mImage(aImage)
, mProgress(aProgress)
, mInvalidRect(aInvalidRect)
, mFlags(aFlags)
, mSurfaceFlags(aSurfaceFlags)
{ }
nsRefPtr<RasterImage> mImage;
const Progress mProgress;
const nsIntRect mInvalidRect;
const uint32_t mFlags;
const SurfaceFlags mSurfaceFlags;
};
class NotifyDecodeCompleteWorker : public nsRunnable
@ -470,17 +472,17 @@ DecodePool::NotifyProgress(Decoder* aDecoder)
MOZ_ASSERT(aDecoder);
if (!NS_IsMainThread() ||
(aDecoder->GetFlags() & imgIContainer::FLAG_ASYNC_NOTIFY)) {
(aDecoder->GetDecoderFlags() & DecoderFlags::ASYNC_NOTIFY)) {
NotifyProgressWorker::Dispatch(aDecoder->GetImage(),
aDecoder->TakeProgress(),
aDecoder->TakeInvalidRect(),
aDecoder->GetDecodeFlags());
aDecoder->GetSurfaceFlags());
return;
}
aDecoder->GetImage()->NotifyProgress(aDecoder->TakeProgress(),
aDecoder->TakeInvalidRect(),
aDecoder->GetDecodeFlags());
aDecoder->GetSurfaceFlags());
}
void
@ -489,7 +491,7 @@ DecodePool::NotifyDecodeComplete(Decoder* aDecoder)
MOZ_ASSERT(aDecoder);
if (!NS_IsMainThread() ||
(aDecoder->GetFlags() & imgIContainer::FLAG_ASYNC_NOTIFY)) {
(aDecoder->GetDecoderFlags() & DecoderFlags::ASYNC_NOTIFY)) {
NotifyDecodeCompleteWorker::Dispatch(aDecoder);
return;
}

View File

@ -31,13 +31,11 @@ Decoder::Decoder(RasterImage* aImage)
, mFrameCount(0)
, mFailCode(NS_OK)
, mChunkCount(0)
, mFlags(0)
, mDecoderFlags(DefaultDecoderFlags())
, mSurfaceFlags(DefaultSurfaceFlags())
, mBytesDecoded(0)
, mInitialized(false)
, mMetadataDecode(false)
, mSendPartialInvalidations(false)
, mImageIsTransient(false)
, mFirstFrameDecode(false)
, mInFrame(false)
, mDataDone(false)
, mDecodeDone(false)
@ -235,7 +233,9 @@ Decoder::CompleteDecode()
// If this image wasn't animated and isn't a transient image, mark its frame
// as optimizable. We don't support optimizing animated images and
// optimizing transient images isn't worth it.
if (!HasAnimation() && !mImageIsTransient && mCurrentFrame) {
if (!HasAnimation() &&
!(mDecoderFlags & DecoderFlags::IMAGE_IS_TRANSIENT) &&
mCurrentFrame) {
mCurrentFrame->SetOptimizable();
}
}
@ -249,8 +249,8 @@ Decoder::AllocateFrame(uint32_t aFrameNum,
uint8_t aPaletteDepth)
{
mCurrentFrame = AllocateFrameInternal(aFrameNum, aTargetSize, aFrameRect,
GetDecodeFlags(), aFormat,
aPaletteDepth, mCurrentFrame.get());
aFormat, aPaletteDepth,
mCurrentFrame.get());
if (mCurrentFrame) {
// Gather the raw pointers the decoders will use.
@ -276,7 +276,6 @@ RawAccessFrameRef
Decoder::AllocateFrameInternal(uint32_t aFrameNum,
const nsIntSize& aTargetSize,
const nsIntRect& aFrameRect,
uint32_t aDecodeFlags,
SurfaceFormat aFormat,
uint8_t aPaletteDepth,
imgFrame* aPreviousFrame)
@ -304,8 +303,7 @@ Decoder::AllocateFrameInternal(uint32_t aFrameNum,
}
nsRefPtr<imgFrame> frame = new imgFrame();
bool nonPremult =
aDecodeFlags & imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
bool nonPremult = bool(mSurfaceFlags & SurfaceFlags::NO_PREMULTIPLY_ALPHA);
if (NS_FAILED(frame->InitForDecoder(aTargetSize, aFrameRect, aFormat,
aPaletteDepth, nonPremult))) {
NS_WARNING("imgFrame::Init should succeed");
@ -322,7 +320,7 @@ Decoder::AllocateFrameInternal(uint32_t aFrameNum,
InsertOutcome outcome =
SurfaceCache::Insert(frame, ImageKey(mImage.get()),
RasterSurfaceKey(aTargetSize,
aDecodeFlags,
mSurfaceFlags,
aFrameNum),
Lifetime::Persistent);
if (outcome == InsertOutcome::FAILURE) {
@ -437,7 +435,7 @@ Decoder::PostFrameStop(Opacity aFrameOpacity /* = Opacity::TRANSPARENT */,
// If we're not sending partial invalidations, then we send an invalidation
// here when the first frame is complete.
if (!mSendPartialInvalidations && !HasAnimation()) {
if (!ShouldSendPartialInvalidations() && !HasAnimation()) {
mInvalidRect.UnionRect(mInvalidRect,
gfx::IntRect(gfx::IntPoint(0, 0), GetSize()));
}
@ -454,7 +452,7 @@ Decoder::PostInvalidation(const nsIntRect& aRect,
// Record this invalidation, unless we're not sending partial invalidations
// or we're past the first frame.
if (mSendPartialInvalidations && !HasAnimation()) {
if (ShouldSendPartialInvalidations() && !HasAnimation()) {
mInvalidRect.UnionRect(mInvalidRect, aRect);
mCurrentFrame->ImageUpdated(aRectAtTargetSize.valueOr(aRect));
}

View File

@ -10,9 +10,11 @@
#include "RasterImage.h"
#include "mozilla/RefPtr.h"
#include "DecodePool.h"
#include "DecoderFlags.h"
#include "ImageMetadata.h"
#include "Orientation.h"
#include "SourceBuffer.h"
#include "SurfaceFlags.h"
namespace mozilla {
@ -137,24 +139,6 @@ public:
*/
virtual void SetResolution(const gfx::IntSize& aResolution) { }
/**
* Set whether should send partial invalidations.
*
* If @aSend is true, we'll send partial invalidations when decoding the first
* frame of the image, so image notifications observers will be able to
* gradually draw in the image as it downloads.
*
* If @aSend is false (the default), we'll only send an invalidation when we
* complete the first frame.
*
* This must be called before Init() is called.
*/
void SetSendPartialInvalidations(bool aSend)
{
MOZ_ASSERT(!mInitialized, "Shouldn't be initialized yet");
mSendPartialInvalidations = aSend;
}
/**
* Set an iterator to the SourceBuffer which will feed data to this decoder.
*
@ -171,27 +155,21 @@ public:
}
/**
* Set whether this decoder is associated with a transient image. The decoder
* may choose to avoid certain optimizations that don't pay off for
* short-lived images in this case.
* Should this decoder send partial invalidations?
*/
void SetImageIsTransient(bool aIsTransient)
bool ShouldSendPartialInvalidations() const
{
MOZ_ASSERT(!mInitialized, "Shouldn't be initialized yet");
mImageIsTransient = aIsTransient;
return !(mDecoderFlags & DecoderFlags::IS_REDECODE);
}
/**
* Set whether we should stop decoding after the first frame.
* Should we stop decoding after the first frame?
*/
void SetIsFirstFrameDecode()
bool IsFirstFrameDecode() const
{
MOZ_ASSERT(!mInitialized, "Shouldn't be initialized yet");
mFirstFrameDecode = true;
return bool(mDecoderFlags & DecoderFlags::FIRST_FRAME_ONLY);
}
bool IsFirstFrameDecode() const { return mFirstFrameDecode; }
size_t BytesDecoded() const { return mBytesDecoded; }
// The amount of time we've spent inside Write() so far for this decoder.
@ -255,9 +233,26 @@ public:
SEQUENTIAL // decode to final image immediately
};
void SetFlags(uint32_t aFlags) { mFlags = aFlags; }
uint32_t GetFlags() const { return mFlags; }
uint32_t GetDecodeFlags() const { return DecodeFlags(mFlags); }
/**
* Get or set the DecoderFlags that influence the behavior of this decoder.
*/
void SetDecoderFlags(DecoderFlags aDecoderFlags)
{
MOZ_ASSERT(!mInitialized);
mDecoderFlags = aDecoderFlags;
}
DecoderFlags GetDecoderFlags() const { return mDecoderFlags; }
/**
* Get or set the SurfaceFlags that select the kind of output this decoder
* will produce.
*/
void SetSurfaceFlags(SurfaceFlags aSurfaceFlags)
{
MOZ_ASSERT(!mInitialized);
mSurfaceFlags = aSurfaceFlags;
}
SurfaceFlags GetSurfaceFlags() const { return mSurfaceFlags; }
bool HasSize() const { return mImageMetadata.HasSize(); }
@ -405,7 +400,6 @@ protected:
RawAccessFrameRef AllocateFrameInternal(uint32_t aFrameNum,
const nsIntSize& aTargetSize,
const nsIntRect& aFrameRect,
uint32_t aDecodeFlags,
gfx::SurfaceFormat aFormat,
uint8_t aPaletteDepth,
imgFrame* aPreviousFrame);
@ -432,14 +426,12 @@ private:
TimeDuration mDecodeTime;
uint32_t mChunkCount;
uint32_t mFlags;
DecoderFlags mDecoderFlags;
SurfaceFlags mSurfaceFlags;
size_t mBytesDecoded;
bool mInitialized : 1;
bool mMetadataDecode : 1;
bool mSendPartialInvalidations : 1;
bool mImageIsTransient : 1;
bool mFirstFrameDecode : 1;
bool mInFrame : 1;
bool mDataDone : 1;
bool mDecodeDone : 1;

View File

@ -109,28 +109,26 @@ DecoderFactory::CreateDecoder(DecoderType aType,
RasterImage* aImage,
SourceBuffer* aSourceBuffer,
const Maybe<IntSize>& aTargetSize,
uint32_t aFlags,
DecoderFlags aDecoderFlags,
SurfaceFlags aSurfaceFlags,
int aSampleSize,
const IntSize& aResolution,
bool aIsRedecode,
bool aImageIsTransient)
const IntSize& aResolution)
{
if (aType == DecoderType::UNKNOWN) {
return nullptr;
}
nsRefPtr<Decoder> decoder = GetDecoder(aType, aImage, aIsRedecode);
nsRefPtr<Decoder> decoder =
GetDecoder(aType, aImage, bool(aDecoderFlags & DecoderFlags::IS_REDECODE));
MOZ_ASSERT(decoder, "Should have a decoder now");
// Initialize the decoder.
decoder->SetMetadataDecode(false);
decoder->SetIterator(aSourceBuffer->Iterator());
decoder->SetFlags(aFlags);
decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::FIRST_FRAME_ONLY);
decoder->SetSurfaceFlags(aSurfaceFlags);
decoder->SetSampleSize(aSampleSize);
decoder->SetResolution(aResolution);
decoder->SetSendPartialInvalidations(!aIsRedecode);
decoder->SetImageIsTransient(aImageIsTransient);
decoder->SetIsFirstFrameDecode();
// Set a target size for downscale-during-decode if applicable.
if (aTargetSize) {
@ -152,7 +150,8 @@ DecoderFactory::CreateDecoder(DecoderType aType,
DecoderFactory::CreateAnimationDecoder(DecoderType aType,
RasterImage* aImage,
SourceBuffer* aSourceBuffer,
uint32_t aFlags,
DecoderFlags aDecoderFlags,
SurfaceFlags aSurfaceFlags,
const IntSize& aResolution)
{
if (aType == DecoderType::UNKNOWN) {
@ -169,9 +168,9 @@ DecoderFactory::CreateAnimationDecoder(DecoderType aType,
// Initialize the decoder.
decoder->SetMetadataDecode(false);
decoder->SetIterator(aSourceBuffer->Iterator());
decoder->SetFlags(aFlags);
decoder->SetDecoderFlags(aDecoderFlags | DecoderFlags::IS_REDECODE);
decoder->SetSurfaceFlags(aSurfaceFlags);
decoder->SetResolution(aResolution);
decoder->SetSendPartialInvalidations(false);
decoder->Init();
if (NS_FAILED(decoder->GetDecoderError())) {
@ -213,7 +212,7 @@ DecoderFactory::CreateMetadataDecoder(DecoderType aType,
/* static */ already_AddRefed<Decoder>
DecoderFactory::CreateAnonymousDecoder(DecoderType aType,
SourceBuffer* aSourceBuffer,
uint32_t aFlags)
SurfaceFlags aSurfaceFlags)
{
if (aType == DecoderType::UNKNOWN) {
return nullptr;
@ -226,15 +225,20 @@ DecoderFactory::CreateAnonymousDecoder(DecoderType aType,
// Initialize the decoder.
decoder->SetMetadataDecode(false);
decoder->SetIterator(aSourceBuffer->Iterator());
decoder->SetFlags(aFlags);
decoder->SetImageIsTransient(true);
// Anonymous decoders are always transient; we don't want to optimize surfaces
// or do any other expensive work that might be wasted.
DecoderFlags decoderFlags = DecoderFlags::IMAGE_IS_TRANSIENT;
// Without an image, the decoder can't store anything in the SurfaceCache, so
// callers will only be able to retrieve the most recent frame via
// Decoder::GetCurrentFrame(). That means that anonymous decoders should
// always be first-frame-only decoders, because nobody ever wants the *last*
// frame.
decoder->SetIsFirstFrameDecode();
decoderFlags |= DecoderFlags::FIRST_FRAME_ONLY;
decoder->SetDecoderFlags(decoderFlags);
decoder->SetSurfaceFlags(aSurfaceFlags);
decoder->Init();
if (NS_FAILED(decoder->GetDecoderError())) {
@ -259,7 +263,7 @@ DecoderFactory::CreateAnonymousMetadataDecoder(DecoderType aType,
// Initialize the decoder.
decoder->SetMetadataDecode(true);
decoder->SetIterator(aSourceBuffer->Iterator());
decoder->SetIsFirstFrameDecode();
decoder->SetDecoderFlags(DecoderFlags::FIRST_FRAME_ONLY);
decoder->Init();
if (NS_FAILED(decoder->GetDecoderError())) {

View File

@ -7,9 +7,12 @@
#ifndef mozilla_image_DecoderFactory_h
#define mozilla_image_DecoderFactory_h
#include "DecoderFlags.h"
#include "mozilla/Attributes.h"
#include "mozilla/Maybe.h"
#include "mozilla/gfx/2D.h"
#include "nsCOMPtr.h"
#include "SurfaceFlags.h"
class nsACString;
@ -20,6 +23,10 @@ class Decoder;
class RasterImage;
class SourceBuffer;
/**
* The type of decoder; this is usually determined from a MIME type using
* DecoderFactory::GetDecoderType().
*/
enum class DecoderType
{
PNG,
@ -42,10 +49,6 @@ public:
* (If the image *is* animated, only the first frame will be decoded.) The
* decoder will send notifications to @aImage.
*
* XXX(seth): @aIsRedecode and @aImageIsTransient should really be part of
* @aFlags. This requires changes to the way that decoder flags work, though.
* See bug 1185800.
*
* @param aType Which type of decoder to create - JPEG, PNG, etc.
* @param aImage The image will own the decoder and which should receive
* notifications as decoding progresses.
@ -55,25 +58,23 @@ public:
* be scaled to during decoding. It's an error to specify
* a target size for a decoder type which doesn't support
* downscale-during-decode.
* @param aFlags Flags specifying what type of output the decoder should
* produce; see GetDecodeFlags() in RasterImage.h.
* @param aDecoderFlags Flags specifying the behavior of this decoder.
* @param aSurfaceFlags Flags specifying the type of output this decoder
* should produce.
* @param aSampleSize The sample size requested using #-moz-samplesize (or 0
* if none).
* @param aResolution The resolution requested using #-moz-resolution (or an
* empty rect if none).
* @param aIsRedecode Specify 'true' if this image has been decoded before.
* @param aImageIsTransient Specify 'true' if this image is transient.
*/
static already_AddRefed<Decoder>
CreateDecoder(DecoderType aType,
RasterImage* aImage,
SourceBuffer* aSourceBuffer,
const Maybe<gfx::IntSize>& aTargetSize,
uint32_t aFlags,
DecoderFlags aDecoderFlags,
SurfaceFlags aSurfaceFlags,
int aSampleSize,
const gfx::IntSize& aResolution,
bool aIsRedecode,
bool aImageIsTransient);
const gfx::IntSize& aResolution);
/**
* Creates and initializes a decoder for animated images of type @aType.
@ -84,8 +85,9 @@ public:
* notifications as decoding progresses.
* @param aSourceBuffer The SourceBuffer which the decoder will read its data
* from.
* @param aFlags Flags specifying what type of output the decoder should
* produce; see GetDecodeFlags() in RasterImage.h.
* @param aDecoderFlags Flags specifying the behavior of this decoder.
* @param aSurfaceFlags Flags specifying the type of output this decoder
* should produce.
* @param aResolution The resolution requested using #-moz-resolution (or an
* empty rect if none).
*/
@ -93,7 +95,8 @@ public:
CreateAnimationDecoder(DecoderType aType,
RasterImage* aImage,
SourceBuffer* aSourceBuffer,
uint32_t aFlags,
DecoderFlags aDecoderFlags,
SurfaceFlags aSurfaceFlags,
const gfx::IntSize& aResolution);
/**
@ -126,13 +129,13 @@ public:
* @param aType Which type of decoder to create - JPEG, PNG, etc.
* @param aSourceBuffer The SourceBuffer which the decoder will read its data
* from.
* @param aFlags Flags specifying what type of output the decoder should
* produce; see GetDecodeFlags() in RasterImage.h.
* @param aSurfaceFlags Flags specifying the type of output this decoder
* should produce.
*/
static already_AddRefed<Decoder>
CreateAnonymousDecoder(DecoderType aType,
SourceBuffer* aSourceBuffer,
uint32_t aFlags);
SurfaceFlags aSurfaceFlags);
/**
* Creates and initializes an anonymous metadata decoder (one which isn't
@ -143,8 +146,6 @@ public:
* @param aType Which type of decoder to create - JPEG, PNG, etc.
* @param aSourceBuffer The SourceBuffer which the decoder will read its data
* from.
* @param aFlags Flags specifying what type of output the decoder should
* produce; see GetDecodeFlags() in RasterImage.h.
*/
static already_AddRefed<Decoder>
CreateAnonymousMetadataDecoder(DecoderType aType,

42
image/DecoderFlags.h Normal file
View File

@ -0,0 +1,42 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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_DecoderFlags_h
#define mozilla_image_DecoderFlags_h
#include "mozilla/TypedEnumBits.h"
namespace mozilla {
namespace image {
/**
* Flags that influence decoder behavior. Note that these flags *don't*
* influence the logical content of the surfaces that the decoder generates, so
* they're not in a factor in SurfaceCache lookups and the like. These flags
* instead either influence which surfaces are generated at all or the tune the
* decoder's behavior for a particular scenario.
*/
enum class DecoderFlags : uint8_t
{
FIRST_FRAME_ONLY = 1 << 0,
IS_REDECODE = 1 << 1,
IMAGE_IS_TRANSIENT = 1 << 2,
ASYNC_NOTIFY = 1 << 3
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(DecoderFlags)
/**
* @return the default set of decode flags.
*/
inline DecoderFlags
DefaultDecoderFlags()
{
return DecoderFlags();
}
} // namespace image
} // namespace mozilla
#endif // mozilla_image_DecoderFlags_h

View File

@ -281,7 +281,7 @@ FrameAnimator::GetCompositedFrame(uint32_t aFrameNum)
LookupResult result =
SurfaceCache::Lookup(ImageKey(mImage),
RasterSurfaceKey(mSize,
0, // Default decode flags.
DefaultSurfaceFlags(),
aFrameNum));
MOZ_ASSERT(!result || !result.DrawableRef()->GetIsPaletted(),
"About to return a paletted frame");
@ -332,7 +332,7 @@ DoCollectSizeOfCompositingSurfaces(const RawAccessFrameRef& aSurface,
{
// Concoct a SurfaceKey for this surface.
SurfaceKey key = RasterSurfaceKey(aSurface->GetImageSize(),
imgIContainer::DECODE_FLAGS_DEFAULT,
DefaultSurfaceFlags(),
/* aFrameNum = */ 0);
// Create a counter for this surface.
@ -374,7 +374,7 @@ FrameAnimator::GetRawFrame(uint32_t aFrameNum) const
LookupResult result =
SurfaceCache::Lookup(ImageKey(mImage),
RasterSurfaceKey(mSize,
0, // Default decode flags.
DefaultSurfaceFlags(),
aFrameNum));
return result ? result.DrawableRef()->RawAccessRef()
: RawAccessFrameRef();

View File

@ -116,7 +116,9 @@ ImageOps::DecodeToSurface(nsIInputStream* aInputStream,
DecoderType decoderType =
DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType).get());
nsRefPtr<Decoder> decoder =
DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer, aFlags);
DecoderFactory::CreateAnonymousDecoder(decoderType,
sourceBuffer,
ToSurfaceFlags(aFlags));
if (!decoder) {
return nullptr;
}

View File

@ -118,7 +118,9 @@ public:
// Insert the new surface into the cache immediately. We need to do this so
// that we won't start multiple scaling jobs for the same size.
SurfaceCache::Insert(mDstRef.get(), ImageKey(mImage.get()),
RasterSurfaceKey(mDstSize, mImageFlags, 0),
RasterSurfaceKey(mDstSize,
ToSurfaceFlags(mImageFlags),
/* aFrameNum = */ 0),
Lifetime::Transient);
return true;
@ -168,7 +170,8 @@ public:
// Remove the frame from the cache since we know we don't need it.
SurfaceCache::RemoveSurface(ImageKey(mImage.get()),
RasterSurfaceKey(mDstSize,
mImageFlags, 0));
ToSurfaceFlags(mImageFlags),
/* aFrameNum = */ 0));
// Release everything we're holding, too.
mSrcRef.reset();
@ -425,17 +428,18 @@ RasterImage::LookupFrameInternal(uint32_t aFrameNum,
}
if (mAnim && aFrameNum > 0) {
MOZ_ASSERT(DecodeFlags(aFlags) == DECODE_FLAGS_DEFAULT,
"Can't composite frames with non-default decode flags");
MOZ_ASSERT(ToSurfaceFlags(aFlags) == DefaultSurfaceFlags(),
"Can't composite frames with non-default surface flags");
return mAnim->GetCompositedFrame(aFrameNum);
}
Maybe<uint32_t> alternateFlags;
Maybe<SurfaceFlags> alternateFlags;
if (IsOpaque()) {
// If we're opaque, we can always substitute a frame that was decoded with a
// different decode flag for premultiplied alpha, because that can only
// matter for frames with transparency.
alternateFlags = Some(aFlags ^ FLAG_DECODE_NO_PREMULTIPLY_ALPHA);
alternateFlags.emplace(ToSurfaceFlags(aFlags) ^
SurfaceFlags::NO_PREMULTIPLY_ALPHA);
}
// We don't want any substitution for sync decodes (except the premultiplied
@ -443,7 +447,7 @@ RasterImage::LookupFrameInternal(uint32_t aFrameNum,
if (aFlags & FLAG_SYNC_DECODE) {
return SurfaceCache::Lookup(ImageKey(this),
RasterSurfaceKey(aSize,
DecodeFlags(aFlags),
ToSurfaceFlags(aFlags),
aFrameNum),
alternateFlags);
}
@ -451,7 +455,7 @@ RasterImage::LookupFrameInternal(uint32_t aFrameNum,
// We'll return the best match we can find to the requested frame.
return SurfaceCache::LookupBestMatch(ImageKey(this),
RasterSurfaceKey(aSize,
DecodeFlags(aFlags),
ToSurfaceFlags(aFlags),
aFrameNum),
alternateFlags);
}
@ -1408,18 +1412,31 @@ RasterImage::Decode(const IntSize& aSize, uint32_t aFlags)
Maybe<IntSize> targetSize = mSize != aSize ? Some(aSize) : Nothing();
// Determine which flags we need to decode this image with.
DecoderFlags decoderFlags = DefaultDecoderFlags();
if (aFlags & FLAG_ASYNC_NOTIFY) {
decoderFlags |= DecoderFlags::ASYNC_NOTIFY;
}
if (mTransient) {
decoderFlags |= DecoderFlags::IMAGE_IS_TRANSIENT;
}
if (mHasBeenDecoded) {
decoderFlags |= DecoderFlags::IS_REDECODE;
}
// Create a decoder.
nsRefPtr<Decoder> decoder;
if (mAnim) {
decoder = DecoderFactory::CreateAnimationDecoder(mDecoderType, this,
mSourceBuffer, aFlags,
mSourceBuffer, decoderFlags,
ToSurfaceFlags(aFlags),
mRequestedResolution);
} else {
decoder = DecoderFactory::CreateDecoder(mDecoderType, this, mSourceBuffer,
targetSize, aFlags,
targetSize, decoderFlags,
ToSurfaceFlags(aFlags),
mRequestedSampleSize,
mRequestedResolution,
mHasBeenDecoded, mTransient);
mRequestedResolution);
}
// Make sure DecoderFactory was able to create a decoder successfully.
@ -1432,7 +1449,7 @@ RasterImage::Decode(const IntSize& aSize, uint32_t aFlags)
InsertOutcome outcome =
SurfaceCache::InsertPlaceholder(ImageKey(this),
RasterSurfaceKey(aSize,
decoder->GetDecodeFlags(),
decoder->GetSurfaceFlags(),
/* aFrameNum = */ 0));
if (outcome != InsertOutcome::SUCCESS) {
return NS_ERROR_FAILURE;
@ -1641,7 +1658,7 @@ RasterImage::RequestScale(imgFrame* aFrame,
}
nsRefPtr<ScaleRunner> runner =
new ScaleRunner(this, DecodeFlags(aFlags), aSize, Move(frameRef));
new ScaleRunner(this, aFlags, aSize, Move(frameRef));
if (runner->Init()) {
if (!sScaleWorkerThread) {
NS_NewNamedThread("Image Scaler", getter_AddRefs(sScaleWorkerThread));
@ -1666,8 +1683,8 @@ RasterImage::DrawWithPreDownscaleIfNeeded(DrawableFrameRef&& aFrameRef,
LookupResult result =
SurfaceCache::Lookup(ImageKey(this),
RasterSurfaceKey(aSize,
DecodeFlags(aFlags),
0));
ToSurfaceFlags(aFlags),
/* aFrameNum = */ 0));
if (!result) {
// We either didn't have a matching scaled frame or the OS threw it away.
// Request a new one so we'll be ready next time. For now, we'll fall back
@ -1746,7 +1763,7 @@ RasterImage::Draw(gfxContext* aContext,
// Illegal -- you can't draw with non-default decode flags.
// (Disabling colorspace conversion might make sense to allow, but
// we don't currently.)
if (DecodeFlags(aFlags) != DECODE_FLAGS_DEFAULT) {
if (ToSurfaceFlags(aFlags) != DefaultSurfaceFlags()) {
return DrawResult::BAD_ARGS;
}
@ -1937,14 +1954,15 @@ RasterImage::GetFramesNotified(uint32_t* aFramesNotified)
void
RasterImage::NotifyProgress(Progress aProgress,
const IntRect& aInvalidRect /* = IntRect() */,
uint32_t aFlags /* = DECODE_FLAGS_DEFAULT */)
SurfaceFlags aSurfaceFlags
/* = DefaultSurfaceFlags() */)
{
MOZ_ASSERT(NS_IsMainThread());
// Ensure that we stay alive long enough to finish notifying.
nsRefPtr<RasterImage> image(this);
bool wasDefaultFlags = aFlags == DECODE_FLAGS_DEFAULT;
bool wasDefaultFlags = aSurfaceFlags == DefaultSurfaceFlags();
if (!aInvalidRect.IsEmpty() && wasDefaultFlags) {
// Update our image container since we're invalidating.
@ -1989,7 +2007,7 @@ RasterImage::FinalizeDecoder(Decoder* aDecoder)
// Send out any final notifications.
NotifyProgress(aDecoder->TakeProgress(),
aDecoder->TakeInvalidRect(),
aDecoder->GetDecodeFlags());
aDecoder->GetSurfaceFlags());
bool wasMetadata = aDecoder->IsMetadataDecode();
bool done = aDecoder->GetDecodeDone();
@ -2094,8 +2112,8 @@ RasterImage::OptimalImageSizeForDest(const gfxSize& aDest, uint32_t aWhichFrame,
LookupResult result =
SurfaceCache::Lookup(ImageKey(this),
RasterSurfaceKey(destSize,
DecodeFlags(aFlags),
0));
ToSurfaceFlags(aFlags),
/* aFrameNum = */ 0));
if (result && result.DrawableRef()->IsImageComplete()) {
return destSize; // We have an existing HQ scale for this size.

View File

@ -135,17 +135,6 @@ class FrameAnimator;
class ImageMetadata;
class SourceBuffer;
/**
* Given a set of imgIContainer FLAG_* flags, returns those flags that can
* affect the output of decoders.
*/
inline MOZ_CONSTEXPR uint32_t
DecodeFlags(uint32_t aFlags)
{
return aFlags & (imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA |
imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION);
}
class RasterImage final : public ImageResource
, public nsIProperties
, public SupportsWeakPtr<RasterImage>
@ -196,13 +185,13 @@ public:
*
* @param aProgress The progress notifications to send.
* @param aInvalidRect An invalidation rect to send.
* @param aFlags The decode flags used by the decoder that generated
* these notifications, or DECODE_FLAGS_DEFAULT if the
* @param aFlags The surface flags used by the decoder that generated
* these notifications, or DefaultSurfaceFlags() if the
* notifications don't come from a decoder.
*/
void NotifyProgress(Progress aProgress,
const nsIntRect& aInvalidRect = nsIntRect(),
uint32_t aFlags = DECODE_FLAGS_DEFAULT);
SurfaceFlags aSurfaceFlags = DefaultSurfaceFlags());
/**
* Records telemetry and does final teardown of the provided decoder.

View File

@ -283,7 +283,7 @@ public:
Pair<already_AddRefed<CachedSurface>, MatchType>
LookupBestMatch(const SurfaceKey& aSurfaceKey,
const Maybe<uint32_t>& aAlternateFlags)
const Maybe<SurfaceFlags>& aAlternateFlags)
{
// Try for an exact match first.
nsRefPtr<CachedSurface> exactMatch;
@ -335,13 +335,13 @@ private:
struct MatchContext
{
MatchContext(const SurfaceKey& aIdealKey,
const Maybe<uint32_t>& aAlternateFlags)
const Maybe<SurfaceFlags>& aAlternateFlags)
: mIdealKey(aIdealKey)
, mAlternateFlags(aAlternateFlags)
{ }
const SurfaceKey& mIdealKey;
const Maybe<uint32_t> mAlternateFlags;
const Maybe<SurfaceFlags> mAlternateFlags;
nsRefPtr<CachedSurface> mBestMatch;
};
@ -644,7 +644,7 @@ public:
LookupResult LookupBestMatch(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey,
const Maybe<uint32_t>& aAlternateFlags)
const Maybe<SurfaceFlags>& aAlternateFlags)
{
nsRefPtr<ImageSurfaceCache> cache = GetImageCache(aImageKey);
if (!cache) {
@ -1060,7 +1060,8 @@ SurfaceCache::Shutdown()
/* static */ LookupResult
SurfaceCache::Lookup(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey,
const Maybe<uint32_t>& aAlternateFlags /* = Nothing() */)
const Maybe<SurfaceFlags>& aAlternateFlags
/* = Nothing() */)
{
if (!sInstance) {
return LookupResult(MatchType::NOT_FOUND);
@ -1080,7 +1081,7 @@ SurfaceCache::Lookup(const ImageKey aImageKey,
/* static */ LookupResult
SurfaceCache::LookupBestMatch(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey,
const Maybe<uint32_t>& aAlternateFlags
const Maybe<SurfaceFlags>& aAlternateFlags
/* = Nothing() */)
{
if (!sInstance) {

View File

@ -19,6 +19,7 @@
#include "nsCOMPtr.h" // for already_AddRefed
#include "mozilla/gfx/Point.h" // for mozilla::gfx::IntSize
#include "mozilla/gfx/2D.h" // for SourceSurface
#include "SurfaceFlags.h"
#include "SVGImageContext.h" // for SVGImageContext
namespace mozilla {
@ -59,16 +60,16 @@ public:
{
uint32_t hash = HashGeneric(mSize.width, mSize.height);
hash = AddToHash(hash, mSVGContext.map(HashSIC).valueOr(0));
hash = AddToHash(hash, mAnimationTime, mFlags);
hash = AddToHash(hash, mAnimationTime, uint32_t(mFlags));
return hash;
}
IntSize Size() const { return mSize; }
Maybe<SVGImageContext> SVGContext() const { return mSVGContext; }
float AnimationTime() const { return mAnimationTime; }
uint32_t Flags() const { return mFlags; }
SurfaceFlags Flags() const { return mFlags; }
SurfaceKey WithNewFlags(uint32_t aFlags) const
SurfaceKey WithNewFlags(SurfaceFlags aFlags) const
{
return SurfaceKey(mSize, mSVGContext, mAnimationTime, aFlags);
}
@ -77,7 +78,7 @@ private:
SurfaceKey(const IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
const float aAnimationTime,
const uint32_t aFlags)
const SurfaceFlags aFlags)
: mSize(aSize)
, mSVGContext(aSVGContext)
, mAnimationTime(aAnimationTime)
@ -88,7 +89,9 @@ private:
return aSIC.Hash();
}
friend SurfaceKey RasterSurfaceKey(const IntSize&, uint32_t, uint32_t);
friend SurfaceKey RasterSurfaceKey(const IntSize&,
SurfaceFlags,
uint32_t);
friend SurfaceKey VectorSurfaceKey(const IntSize&,
const Maybe<SVGImageContext>&,
float);
@ -96,12 +99,12 @@ private:
IntSize mSize;
Maybe<SVGImageContext> mSVGContext;
float mAnimationTime;
uint32_t mFlags;
SurfaceFlags mFlags;
};
inline SurfaceKey
RasterSurfaceKey(const gfx::IntSize& aSize,
uint32_t aFlags,
SurfaceFlags aFlags,
uint32_t aFrameNum)
{
return SurfaceKey(aSize, Nothing(), float(aFrameNum), aFlags);
@ -115,7 +118,7 @@ VectorSurfaceKey(const gfx::IntSize& aSize,
// We don't care about aFlags for VectorImage because none of the flags we
// have right now influence VectorImage's rendering. If we add a new flag that
// *does* affect how a VectorImage renders, we'll have to change this.
return SurfaceKey(aSize, aSVGContext, aAnimationTime, 0);
return SurfaceKey(aSize, aSVGContext, aAnimationTime, DefaultSurfaceFlags());
}
enum class Lifetime : uint8_t {
@ -196,7 +199,8 @@ struct SurfaceCache
*/
static LookupResult Lookup(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey,
const Maybe<uint32_t>& aAlternateFlags = Nothing());
const Maybe<SurfaceFlags>& aAlternateFlags
= Nothing());
/**
* Looks up the best matching surface in the cache and returns a drawable
@ -224,7 +228,7 @@ struct SurfaceCache
*/
static LookupResult LookupBestMatch(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey,
const Maybe<uint32_t>& aAlternateFlags
const Maybe<SurfaceFlags>& aAlternateFlags
= Nothing());
/**

56
image/SurfaceFlags.h Normal file
View File

@ -0,0 +1,56 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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_SurfaceFlags_h
#define mozilla_image_SurfaceFlags_h
#include "imgIContainer.h"
#include "mozilla/TypedEnumBits.h"
namespace mozilla {
namespace image {
/**
* Flags that change the output a decoder generates. Because different
* combinations of these flags result in logically different surfaces, these
* flags must be taken into account in SurfaceCache lookups.
*/
enum class SurfaceFlags : uint8_t
{
NO_PREMULTIPLY_ALPHA = 1 << 0,
NO_COLORSPACE_CONVERSION = 1 << 1
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(SurfaceFlags)
/**
* @return the default set of surface flags.
*/
inline SurfaceFlags
DefaultSurfaceFlags()
{
return SurfaceFlags();
}
/**
* Given a set of imgIContainer FLAG_* flags, returns a set of SurfaceFlags with
* the corresponding flags set.
*/
inline SurfaceFlags
ToSurfaceFlags(uint32_t aFlags)
{
SurfaceFlags flags = DefaultSurfaceFlags();
if (aFlags & imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA) {
flags |= SurfaceFlags::NO_PREMULTIPLY_ALPHA;
}
if (aFlags & imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION) {
flags |= SurfaceFlags::NO_COLORSPACE_CONVERSION;
}
return flags;
}
} // namespace image
} // namespace mozilla
#endif // mozilla_image_SurfaceFlags_h

View File

@ -360,10 +360,8 @@ nsICODecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
if (mIsPNG) {
mContainedDecoder = new nsPNGDecoder(mImage);
mContainedDecoder->SetMetadataDecode(IsMetadataDecode());
mContainedDecoder->SetSendPartialInvalidations(mSendPartialInvalidations);
if (mFirstFrameDecode) {
mContainedDecoder->SetIsFirstFrameDecode();
}
mContainedDecoder->SetDecoderFlags(GetDecoderFlags());
mContainedDecoder->SetSurfaceFlags(GetSurfaceFlags());
mContainedDecoder->Init();
if (!WriteToContainedDecoder(mSignature, PNGSIGNATURESIZE)) {
return;
@ -440,10 +438,8 @@ nsICODecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
mContainedDecoder = bmpDecoder;
bmpDecoder->SetUseAlphaData(true);
mContainedDecoder->SetMetadataDecode(IsMetadataDecode());
mContainedDecoder->SetSendPartialInvalidations(mSendPartialInvalidations);
if (mFirstFrameDecode) {
mContainedDecoder->SetIsFirstFrameDecode();
}
mContainedDecoder->SetDecoderFlags(GetDecoderFlags());
mContainedDecoder->SetSurfaceFlags(GetSurfaceFlags());
mContainedDecoder->Init();
// The ICO format when containing a BMP does not include the 14 byte

View File

@ -154,7 +154,7 @@ void
nsJPEGDecoder::InitInternal()
{
mCMSMode = gfxPlatform::GetCMSMode();
if (GetDecodeFlags() & imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION) {
if (GetSurfaceFlags() & SurfaceFlags::NO_COLORSPACE_CONVERSION) {
mCMSMode = eCMSMode_Off;
}

View File

@ -233,11 +233,11 @@ void
nsPNGDecoder::InitInternal()
{
mCMSMode = gfxPlatform::GetCMSMode();
if (GetDecodeFlags() & imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION) {
if (GetSurfaceFlags() & SurfaceFlags::NO_COLORSPACE_CONVERSION) {
mCMSMode = eCMSMode_Off;
}
mDisablePremultipliedAlpha =
GetDecodeFlags() & imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
bool(GetSurfaceFlags() & SurfaceFlags::NO_PREMULTIPLY_ALPHA);
#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
static png_byte color_chunks[]=

View File

@ -276,9 +276,10 @@ private:
surfacePathPrefix.Append("@");
surfacePathPrefix.AppendFloat(counter.Key().AnimationTime());
if (counter.Key().Flags() != imgIContainer::DECODE_FLAGS_DEFAULT) {
if (counter.Key().Flags() != DefaultSurfaceFlags()) {
surfacePathPrefix.Append(", flags:");
surfacePathPrefix.AppendInt(counter.Key().Flags(), /* aRadix = */ 16);
surfacePathPrefix.AppendInt(uint32_t(counter.Key().Flags()),
/* aRadix = */ 16);
}
} else if (counter.Type() == SurfaceMemoryCounterType::COMPOSITING) {
surfacePathPrefix.Append(", compositing frame");

View File

@ -46,6 +46,7 @@ EXPORTS += [
'IProgressObserver.h',
'Orientation.h',
'SurfaceCache.h',
'SurfaceFlags.h',
]
UNIFIED_SOURCES += [

View File

@ -111,7 +111,7 @@ CheckMetadata(const ImageTestCase& aTestCase,
// Create a full decoder, so we can compare the result.
decoder =
DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer,
imgIContainer::DECODE_FLAGS_DEFAULT);
DefaultSurfaceFlags());
ASSERT_TRUE(decoder != nullptr);
if (aBMPAlpha == BMPAlpha::ENABLED) {
@ -241,14 +241,14 @@ TEST(ImageMetadata, NoFrameDelayGIFFullDecode)
LookupResult firstFrameLookupResult =
SurfaceCache::Lookup(ImageKey(image.get()),
RasterSurfaceKey(imageSize,
imgIContainer::DECODE_FLAGS_DEFAULT,
DefaultSurfaceFlags(),
/* aFrameNum = */ 0));
EXPECT_EQ(MatchType::EXACT, firstFrameLookupResult.Type());
LookupResult secondFrameLookupResult =
SurfaceCache::Lookup(ImageKey(image.get()),
RasterSurfaceKey(imageSize,
imgIContainer::DECODE_FLAGS_DEFAULT,
DefaultSurfaceFlags(),
/* aFrameNum = */ 1));
EXPECT_EQ(MatchType::EXACT, secondFrameLookupResult.Type());
}