зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1117607 - Make decoders responsible for their own frame allocations. r=tn
This commit is contained in:
Родитель
14a91d6f8c
Коммит
d564a3b0a5
|
@ -41,8 +41,6 @@ Decoder::Decoder(RasterImage* aImage)
|
|||
, mImageIsLocked(false)
|
||||
, mFrameCount(0)
|
||||
, mFailCode(NS_OK)
|
||||
, mNeedsNewFrame(false)
|
||||
, mNeedsToFlushData(false)
|
||||
, mInitialized(false)
|
||||
, mSizeDecode(false)
|
||||
, mInFrame(false)
|
||||
|
@ -89,33 +87,6 @@ Decoder::Init()
|
|||
mInitialized = true;
|
||||
}
|
||||
|
||||
// Initializes a decoder whose image and observer is already being used by a
|
||||
// parent decoder
|
||||
void
|
||||
Decoder::InitSharedDecoder(uint8_t* aImageData, uint32_t aImageDataLength,
|
||||
uint32_t* aColormap, uint32_t aColormapSize,
|
||||
RawAccessFrameRef&& aFrameRef)
|
||||
{
|
||||
// No re-initializing
|
||||
MOZ_ASSERT(!mInitialized, "Can't re-initialize a decoder!");
|
||||
|
||||
mImageData = aImageData;
|
||||
mImageDataLength = aImageDataLength;
|
||||
mColormap = aColormap;
|
||||
mColormapSize = aColormapSize;
|
||||
mCurrentFrame = Move(aFrameRef);
|
||||
|
||||
// We have all the frame data, so we've started the frame.
|
||||
if (!IsSizeDecode()) {
|
||||
mFrameCount++;
|
||||
PostFrameStart();
|
||||
}
|
||||
|
||||
// Implementation-specific initialization
|
||||
InitInternal();
|
||||
mInitialized = true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Decoder::Decode()
|
||||
{
|
||||
|
@ -179,6 +150,9 @@ Decoder::Write(const char* aBuffer, uint32_t aCount)
|
|||
PROFILER_LABEL("ImageDecoder", "Write",
|
||||
js::ProfileEntry::Category::GRAPHICS);
|
||||
|
||||
MOZ_ASSERT(aBuffer);
|
||||
MOZ_ASSERT(aCount > 0);
|
||||
|
||||
// We're strict about decoder errors
|
||||
MOZ_ASSERT(!HasDecoderError(),
|
||||
"Not allowed to make more decoder calls after error!");
|
||||
|
@ -190,12 +164,6 @@ Decoder::Write(const char* aBuffer, uint32_t aCount)
|
|||
// Keep track of the total number of bytes written.
|
||||
mBytesDecoded += aCount;
|
||||
|
||||
// If we're flushing data, clear the flag.
|
||||
if (aBuffer == nullptr && aCount == 0) {
|
||||
MOZ_ASSERT(mNeedsToFlushData, "Flushing when we don't need to");
|
||||
mNeedsToFlushData = false;
|
||||
}
|
||||
|
||||
// If a data error occured, just ignore future data.
|
||||
if (HasDataError()) {
|
||||
return;
|
||||
|
@ -206,28 +174,9 @@ Decoder::Write(const char* aBuffer, uint32_t aCount)
|
|||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!NeedsNewFrame() || HasDataError(),
|
||||
"Should not need a new frame before writing anything");
|
||||
MOZ_ASSERT(!NeedsToFlushData() || HasDataError(),
|
||||
"Should not need to flush data before writing anything");
|
||||
|
||||
// Pass the data along to the implementation.
|
||||
WriteInternal(aBuffer, aCount);
|
||||
|
||||
// If we need a new frame to proceed, let's create one and call it again.
|
||||
while (NeedsNewFrame() && !HasDataError()) {
|
||||
MOZ_ASSERT(!IsSizeDecode(), "Shouldn't need new frame for size decode");
|
||||
|
||||
nsresult rv = AllocateFrame();
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// Use the data we saved when we asked for a new frame.
|
||||
WriteInternal(nullptr, 0);
|
||||
}
|
||||
|
||||
mNeedsToFlushData = false;
|
||||
}
|
||||
|
||||
// Finish telemetry.
|
||||
mDecodeTime += (TimeStamp::Now() - start);
|
||||
}
|
||||
|
@ -238,6 +187,8 @@ Decoder::CompleteDecode()
|
|||
// Implementation-specific finalization
|
||||
if (!HasError()) {
|
||||
FinishInternal();
|
||||
} else {
|
||||
FinishWithErrorInternal();
|
||||
}
|
||||
|
||||
// If the implementation left us mid-frame, finish that up.
|
||||
|
@ -328,135 +279,51 @@ Decoder::Finish()
|
|||
mCurrentFrame->SetOptimizable();
|
||||
}
|
||||
|
||||
mImage->OnDecodingComplete();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Decoder::FinishSharedDecoder()
|
||||
{
|
||||
if (!HasError()) {
|
||||
FinishInternal();
|
||||
mImage->OnDecodingComplete(mIsAnimated);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
Decoder::AllocateFrame(const nsIntSize& aTargetSize /* = nsIntSize() */)
|
||||
Decoder::AllocateFrame(uint32_t aFrameNum,
|
||||
const nsIntSize& aTargetSize,
|
||||
const nsIntRect& aFrameRect,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
uint8_t aPaletteDepth)
|
||||
{
|
||||
MOZ_ASSERT(mNeedsNewFrame);
|
||||
|
||||
nsIntSize targetSize = aTargetSize;
|
||||
if (targetSize == nsIntSize()) {
|
||||
MOZ_ASSERT(HasSize());
|
||||
targetSize = mImageMetadata.GetSize();
|
||||
}
|
||||
|
||||
mCurrentFrame = EnsureFrame(mNewFrameData.mFrameNum,
|
||||
targetSize,
|
||||
mNewFrameData.mFrameRect,
|
||||
GetDecodeFlags(),
|
||||
mNewFrameData.mFormat,
|
||||
mNewFrameData.mPaletteDepth,
|
||||
mCurrentFrame.get());
|
||||
mCurrentFrame = AllocateFrameInternal(aFrameNum, aTargetSize, aFrameRect,
|
||||
GetDecodeFlags(), aFormat,
|
||||
aPaletteDepth, mCurrentFrame.get());
|
||||
|
||||
if (mCurrentFrame) {
|
||||
// Gather the raw pointers the decoders will use.
|
||||
mCurrentFrame->GetImageData(&mImageData, &mImageDataLength);
|
||||
mCurrentFrame->GetPaletteData(&mColormap, &mColormapSize);
|
||||
|
||||
if (mNewFrameData.mFrameNum + 1 == mFrameCount) {
|
||||
if (aFrameNum + 1 == mFrameCount) {
|
||||
PostFrameStart();
|
||||
}
|
||||
} else {
|
||||
PostDataError();
|
||||
}
|
||||
|
||||
// Mark ourselves as not needing another frame before talking to anyone else
|
||||
// so they can tell us if they need yet another.
|
||||
mNeedsNewFrame = false;
|
||||
|
||||
// If we've received any data at all, we may have pending data that needs to
|
||||
// be flushed now that we have a frame to decode into.
|
||||
if (mBytesDecoded > 0) {
|
||||
mNeedsToFlushData = true;
|
||||
}
|
||||
|
||||
return mCurrentFrame ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RawAccessFrameRef
|
||||
Decoder::EnsureFrame(uint32_t aFrameNum,
|
||||
const nsIntSize& aTargetSize,
|
||||
const nsIntRect& aFrameRect,
|
||||
uint32_t aDecodeFlags,
|
||||
SurfaceFormat aFormat,
|
||||
uint8_t aPaletteDepth,
|
||||
imgFrame* aPreviousFrame)
|
||||
Decoder::AllocateFrameInternal(uint32_t aFrameNum,
|
||||
const nsIntSize& aTargetSize,
|
||||
const nsIntRect& aFrameRect,
|
||||
uint32_t aDecodeFlags,
|
||||
SurfaceFormat aFormat,
|
||||
uint8_t aPaletteDepth,
|
||||
imgFrame* aPreviousFrame)
|
||||
{
|
||||
if (mDataError || NS_FAILED(mFailCode)) {
|
||||
return RawAccessFrameRef();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aFrameNum <= mFrameCount, "Invalid frame index!");
|
||||
if (aFrameNum > mFrameCount) {
|
||||
return RawAccessFrameRef();
|
||||
}
|
||||
|
||||
// Adding a frame that doesn't already exist. This is the normal case.
|
||||
if (aFrameNum == mFrameCount) {
|
||||
return InternalAddFrame(aFrameNum, aTargetSize, aFrameRect, aDecodeFlags,
|
||||
aFormat, aPaletteDepth, aPreviousFrame);
|
||||
}
|
||||
|
||||
// We're replacing a frame. It must be the first frame; there's no reason to
|
||||
// ever replace any other frame, since the first frame is the only one we
|
||||
// speculatively allocate without knowing what the decoder really needs.
|
||||
// XXX(seth): I'm not convinced there's any reason to support this at all. We
|
||||
// should figure out how to avoid triggering this and rip it out.
|
||||
MOZ_ASSERT(aFrameNum == 0, "Replacing a frame other than the first?");
|
||||
MOZ_ASSERT(mFrameCount == 1, "Should have only one frame");
|
||||
MOZ_ASSERT(aPreviousFrame, "Need the previous frame to replace");
|
||||
if (aFrameNum != 0 || !aPreviousFrame || mFrameCount != 1) {
|
||||
return RawAccessFrameRef();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!aPreviousFrame->GetRect().IsEqualEdges(aFrameRect) ||
|
||||
aPreviousFrame->GetFormat() != aFormat ||
|
||||
aPreviousFrame->GetPaletteDepth() != aPaletteDepth,
|
||||
"Replacing first frame with the same kind of frame?");
|
||||
|
||||
// Reset our state.
|
||||
mInFrame = false;
|
||||
RawAccessFrameRef ref = Move(mCurrentFrame);
|
||||
|
||||
MOZ_ASSERT(ref, "No ref to current frame?");
|
||||
|
||||
// Reinitialize the old frame.
|
||||
nsIntSize oldSize = aPreviousFrame->GetImageSize();
|
||||
bool nonPremult =
|
||||
aDecodeFlags & imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
|
||||
if (NS_FAILED(aPreviousFrame->ReinitForDecoder(oldSize, aFrameRect, aFormat,
|
||||
aPaletteDepth, nonPremult))) {
|
||||
NS_WARNING("imgFrame::ReinitForDecoder should succeed");
|
||||
mFrameCount = 0;
|
||||
aPreviousFrame->Abort();
|
||||
return RawAccessFrameRef();
|
||||
}
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
RawAccessFrameRef
|
||||
Decoder::InternalAddFrame(uint32_t aFrameNum,
|
||||
const nsIntSize& aTargetSize,
|
||||
const nsIntRect& aFrameRect,
|
||||
uint32_t aDecodeFlags,
|
||||
SurfaceFormat aFormat,
|
||||
uint8_t aPaletteDepth,
|
||||
imgFrame* aPreviousFrame)
|
||||
{
|
||||
MOZ_ASSERT(aFrameNum <= mFrameCount, "Invalid frame index!");
|
||||
if (aFrameNum > mFrameCount) {
|
||||
if (aFrameNum != mFrameCount) {
|
||||
MOZ_ASSERT_UNREACHABLE("Allocating frames out of order");
|
||||
return RawAccessFrameRef();
|
||||
}
|
||||
|
||||
|
@ -559,6 +426,7 @@ Decoder::SetSizeOnImage()
|
|||
void Decoder::InitInternal() { }
|
||||
void Decoder::WriteInternal(const char* aBuffer, uint32_t aCount) { }
|
||||
void Decoder::FinishInternal() { }
|
||||
void Decoder::FinishWithErrorInternal() { }
|
||||
|
||||
/*
|
||||
* Progress Notifications
|
||||
|
@ -685,24 +553,6 @@ Decoder::PostDecoderError(nsresult aFailureCode)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Decoder::NeedNewFrame(uint32_t framenum, uint32_t x_offset, uint32_t y_offset,
|
||||
uint32_t width, uint32_t height,
|
||||
gfx::SurfaceFormat format,
|
||||
uint8_t palette_depth /* = 0 */)
|
||||
{
|
||||
// Decoders should never call NeedNewFrame without yielding back to Write().
|
||||
MOZ_ASSERT(!mNeedsNewFrame);
|
||||
|
||||
// We don't want images going back in time or skipping frames.
|
||||
MOZ_ASSERT(framenum == mFrameCount || framenum == (mFrameCount - 1));
|
||||
|
||||
mNewFrameData = NewFrameData(framenum,
|
||||
nsIntRect(x_offset, y_offset, width, height),
|
||||
format, palette_depth);
|
||||
mNeedsNewFrame = true;
|
||||
}
|
||||
|
||||
Telemetry::ID
|
||||
Decoder::SpeedHistogram()
|
||||
{
|
||||
|
|
129
image/Decoder.h
129
image/Decoder.h
|
@ -33,23 +33,8 @@ public:
|
|||
*/
|
||||
void Init();
|
||||
|
||||
/**
|
||||
* Initializes a decoder whose image and observer is already being used by a
|
||||
* parent decoder. Decoders may not be re-initialized.
|
||||
*
|
||||
* Notifications Sent: TODO
|
||||
*/
|
||||
void InitSharedDecoder(uint8_t* aImageData, uint32_t aImageDataLength,
|
||||
uint32_t* aColormap, uint32_t aColormapSize,
|
||||
RawAccessFrameRef&& aFrameRef);
|
||||
|
||||
/**
|
||||
* Decodes, reading all data currently available in the SourceBuffer. If more
|
||||
* If aBuffer is null and aCount is 0, Write() flushes any buffered data to
|
||||
* the decoder. Data is buffered if the decoder wasn't able to completely
|
||||
* decode it because it needed a new frame. If it's necessary to flush data,
|
||||
* NeedsToFlushData() will return true.
|
||||
*
|
||||
* data is needed, Decode() automatically ensures that it will be called again
|
||||
* on a DecodePool thread when the data becomes available.
|
||||
*
|
||||
|
@ -69,14 +54,6 @@ public:
|
|||
*/
|
||||
bool ShouldSyncDecode(size_t aByteLimit);
|
||||
|
||||
/**
|
||||
* Informs the shared decoder that all the data has been written.
|
||||
* Should only be used if InitSharedDecoder was useed
|
||||
*
|
||||
* Notifications Sent: TODO
|
||||
*/
|
||||
void FinishSharedDecoder();
|
||||
|
||||
/**
|
||||
* Gets the invalidation region accumulated by the decoder so far, and clears
|
||||
* the decoder's invalidation region. This means that each call to
|
||||
|
@ -259,11 +236,6 @@ public:
|
|||
bool HasSize() const { return mImageMetadata.HasSize(); }
|
||||
void SetSizeOnImage();
|
||||
|
||||
void SetSize(const nsIntSize& aSize, const Orientation& aOrientation)
|
||||
{
|
||||
PostSize(aSize.width, aSize.height, aOrientation);
|
||||
}
|
||||
|
||||
nsIntSize GetSize() const
|
||||
{
|
||||
MOZ_ASSERT(HasSize());
|
||||
|
@ -279,30 +251,9 @@ public:
|
|||
*/
|
||||
RasterImage* GetImage() const { MOZ_ASSERT(mImage); return mImage.get(); }
|
||||
|
||||
// Tell the decoder infrastructure to allocate a frame. By default, frame 0
|
||||
// is created as an ARGB frame with no offset and with size width * height.
|
||||
// If decoders need something different, they must ask for it.
|
||||
// This is called by decoders when they need a new frame. These decoders
|
||||
// must then save the data they have been sent but not yet processed and
|
||||
// return from WriteInternal. When the new frame is created, WriteInternal
|
||||
// will be called again with nullptr and 0 as arguments.
|
||||
void NeedNewFrame(uint32_t frameNum, uint32_t x_offset, uint32_t y_offset,
|
||||
uint32_t width, uint32_t height,
|
||||
gfx::SurfaceFormat format,
|
||||
uint8_t palette_depth = 0);
|
||||
|
||||
virtual bool NeedsNewFrame() const { return mNeedsNewFrame; }
|
||||
|
||||
// Try to allocate a frame as described in mNewFrameData and return the
|
||||
// status code from that attempt. Clears mNewFrameData.
|
||||
virtual nsresult AllocateFrame(const nsIntSize& aTargetSize = nsIntSize());
|
||||
|
||||
already_AddRefed<imgFrame> GetCurrentFrame()
|
||||
{
|
||||
nsRefPtr<imgFrame> frame = mCurrentFrame.get();
|
||||
return frame.forget();
|
||||
}
|
||||
|
||||
// XXX(seth): This should be removed once we can optimize imgFrame objects
|
||||
// off-main-thread. It only exists to support the code in Finish() for
|
||||
// nsICODecoder.
|
||||
RawAccessFrameRef GetCurrentFrameRef()
|
||||
{
|
||||
return mCurrentFrame ? mCurrentFrame->RawAccessRef()
|
||||
|
@ -322,6 +273,8 @@ public:
|
|||
|
||||
|
||||
protected:
|
||||
friend class nsICODecoder;
|
||||
|
||||
virtual ~Decoder();
|
||||
|
||||
/*
|
||||
|
@ -331,6 +284,7 @@ protected:
|
|||
virtual void InitInternal();
|
||||
virtual void WriteInternal(const char* aBuffer, uint32_t aCount);
|
||||
virtual void FinishInternal();
|
||||
virtual void FinishWithErrorInternal();
|
||||
|
||||
/*
|
||||
* Progress notifications.
|
||||
|
@ -396,11 +350,6 @@ protected:
|
|||
void PostDataError();
|
||||
void PostDecoderError(nsresult aFailCode);
|
||||
|
||||
// Returns true if we may have stored data that we need to flush now that we
|
||||
// have a new frame to decode into. Callers can use Write() to actually
|
||||
// flush the data; see the documentation for that method.
|
||||
bool NeedsToFlushData() const { return mNeedsToFlushData; }
|
||||
|
||||
/**
|
||||
* CompleteDecode() finishes up the decoding process after Decode() determines
|
||||
* that we're finished. It records final progress and does all the cleanup
|
||||
|
@ -409,32 +358,33 @@ protected:
|
|||
void CompleteDecode();
|
||||
|
||||
/**
|
||||
* Ensures that a given frame number exists with the given parameters, and
|
||||
* returns a RawAccessFrameRef for that frame.
|
||||
* It is not possible to create sparse frame arrays; you can only append
|
||||
* frames to the current frame array, or if there is only one frame in the
|
||||
* array, replace that frame.
|
||||
* @aTargetSize specifies the target size we're decoding to. If we're not
|
||||
* downscaling during decode, this will always be the same as the image's
|
||||
* intrinsic size.
|
||||
* Allocates a new frame, making it our current frame if successful.
|
||||
*
|
||||
* The @aFrameNum parameter only exists as a sanity check; it's illegal to
|
||||
* create a new frame anywhere but immediately after the existing frames.
|
||||
*
|
||||
* If a non-paletted frame is desired, pass 0 for aPaletteDepth.
|
||||
*/
|
||||
RawAccessFrameRef EnsureFrame(uint32_t aFrameNum,
|
||||
const nsIntSize& aTargetSize,
|
||||
const nsIntRect& aFrameRect,
|
||||
uint32_t aDecodeFlags,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
uint8_t aPaletteDepth,
|
||||
imgFrame* aPreviousFrame);
|
||||
nsresult AllocateFrame(uint32_t aFrameNum,
|
||||
const nsIntSize& aTargetSize,
|
||||
const nsIntRect& aFrameRect,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
uint8_t aPaletteDepth = 0);
|
||||
|
||||
RawAccessFrameRef InternalAddFrame(uint32_t aFrameNum,
|
||||
const nsIntSize& aTargetSize,
|
||||
const nsIntRect& aFrameRect,
|
||||
uint32_t aDecodeFlags,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
uint8_t aPaletteDepth,
|
||||
imgFrame* aPreviousFrame);
|
||||
/// Helper method for decoders which only have 'basic' frame allocation needs.
|
||||
nsresult AllocateBasicFrame() {
|
||||
nsIntSize size = GetSize();
|
||||
return AllocateFrame(0, size, nsIntRect(nsIntPoint(), size),
|
||||
gfx::SurfaceFormat::B8G8R8A8);
|
||||
}
|
||||
|
||||
RawAccessFrameRef AllocateFrameInternal(uint32_t aFrameNum,
|
||||
const nsIntSize& aTargetSize,
|
||||
const nsIntRect& aFrameRect,
|
||||
uint32_t aDecodeFlags,
|
||||
gfx::SurfaceFormat aFormat,
|
||||
uint8_t aPaletteDepth,
|
||||
imgFrame* aPreviousFrame);
|
||||
|
||||
/*
|
||||
* Member variables.
|
||||
|
@ -472,27 +422,6 @@ private:
|
|||
|
||||
nsresult mFailCode;
|
||||
|
||||
struct NewFrameData
|
||||
{
|
||||
NewFrameData() { }
|
||||
|
||||
NewFrameData(uint32_t aFrameNum, const nsIntRect& aFrameRect,
|
||||
gfx::SurfaceFormat aFormat, uint8_t aPaletteDepth)
|
||||
: mFrameNum(aFrameNum)
|
||||
, mFrameRect(aFrameRect)
|
||||
, mFormat(aFormat)
|
||||
, mPaletteDepth(aPaletteDepth)
|
||||
{ }
|
||||
|
||||
uint32_t mFrameNum;
|
||||
nsIntRect mFrameRect;
|
||||
gfx::SurfaceFormat mFormat;
|
||||
uint8_t mPaletteDepth;
|
||||
};
|
||||
|
||||
NewFrameData mNewFrameData;
|
||||
bool mNeedsNewFrame;
|
||||
bool mNeedsToFlushData;
|
||||
bool mInitialized;
|
||||
bool mSizeDecode;
|
||||
bool mInFrame;
|
||||
|
|
|
@ -963,9 +963,7 @@ RasterImage::OnAddedFrame(uint32_t aNewFrameCount,
|
|||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT((mFrameCount == 1 && aNewFrameCount == 1) ||
|
||||
mFrameCount < aNewFrameCount,
|
||||
"Frame count running backwards");
|
||||
MOZ_ASSERT(aNewFrameCount <= mFrameCount + 1, "Skipped a frame?");
|
||||
|
||||
if (mError) {
|
||||
return; // We're in an error state, possibly due to OOM. Bail.
|
||||
|
@ -1034,7 +1032,7 @@ RasterImage::SetSize(int32_t aWidth, int32_t aHeight, Orientation aOrientation)
|
|||
}
|
||||
|
||||
void
|
||||
RasterImage::OnDecodingComplete()
|
||||
RasterImage::OnDecodingComplete(bool aIsAnimated)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
@ -1045,12 +1043,30 @@ RasterImage::OnDecodingComplete()
|
|||
// Flag that we've been decoded before.
|
||||
mHasBeenDecoded = true;
|
||||
|
||||
// Let our FrameAnimator know not to expect any more frames.
|
||||
if (mAnim) {
|
||||
mAnim->SetDoneDecoding(true);
|
||||
if (aIsAnimated) {
|
||||
if (mAnim) {
|
||||
mAnim->SetDoneDecoding(true);
|
||||
} else {
|
||||
// The OnAddedFrame event that will create mAnim is still in the event
|
||||
// queue. Wait for it.
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableMethod(this, &RasterImage::MarkAnimationDecoded);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RasterImage::MarkAnimationDecoded()
|
||||
{
|
||||
MOZ_ASSERT(mAnim, "Should have an animation now");
|
||||
if (!mAnim) {
|
||||
return;
|
||||
}
|
||||
|
||||
mAnim->SetDoneDecoding(true);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RasterImage::SetAnimationMode(uint16_t aAnimationMode)
|
||||
{
|
||||
|
@ -1452,18 +1468,6 @@ RasterImage::CreateDecoder(const Maybe<IntSize>& aSize, uint32_t aFlags)
|
|||
decoder->SetImageIsLocked();
|
||||
}
|
||||
|
||||
if (aSize) {
|
||||
// We already have the size; tell the decoder so it can preallocate a
|
||||
// frame. By default, we create an ARGB frame with no offset. If decoders
|
||||
// need a different type, they need to ask for it themselves.
|
||||
// XXX(seth): Note that we call SetSize() and NeedNewFrame() with the
|
||||
// image's intrinsic size, but AllocateFrame with our target size.
|
||||
decoder->SetSize(mSize, mOrientation);
|
||||
decoder->NeedNewFrame(0, 0, 0, aSize->width, aSize->height,
|
||||
SurfaceFormat::B8G8R8A8);
|
||||
decoder->AllocateFrame(*aSize);
|
||||
}
|
||||
|
||||
if (aSize && decoder->HasError()) {
|
||||
if (gfxPrefs::ImageDecodeRetryOnAllocFailure() &&
|
||||
mRetryCount < 10) {
|
||||
|
|
|
@ -206,7 +206,10 @@ public:
|
|||
void SetLoopCount(int32_t aLoopCount);
|
||||
|
||||
/// Notification that the entire image has been decoded.
|
||||
void OnDecodingComplete();
|
||||
void OnDecodingComplete(bool aIsAnimated);
|
||||
|
||||
/// Helper method for OnDecodingComplete.
|
||||
void MarkAnimationDecoded();
|
||||
|
||||
/**
|
||||
* Sends the provided progress notifications to ProgressTracker.
|
||||
|
|
|
@ -437,11 +437,15 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (!mImageData) {
|
||||
PostDecoderError(NS_ERROR_FAILURE);
|
||||
return;
|
||||
|
||||
MOZ_ASSERT(!mImageData, "Already have a buffer allocated?");
|
||||
nsresult rv = AllocateBasicFrame();
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mImageData, "Should have a buffer now");
|
||||
|
||||
// Prepare for transparency
|
||||
if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
|
||||
// Clear the image, as the RLE may jump over areas
|
||||
|
|
|
@ -162,7 +162,7 @@ nsGIFDecoder2::BeginGIF()
|
|||
}
|
||||
|
||||
//******************************************************************************
|
||||
void
|
||||
nsresult
|
||||
nsGIFDecoder2::BeginImageFrame(uint16_t aDepth)
|
||||
{
|
||||
MOZ_ASSERT(HasSize());
|
||||
|
@ -175,35 +175,31 @@ nsGIFDecoder2::BeginImageFrame(uint16_t aDepth)
|
|||
format = gfx::SurfaceFormat::B8G8R8X8;
|
||||
}
|
||||
|
||||
nsIntRect frameRect(mGIFStruct.x_offset, mGIFStruct.y_offset,
|
||||
mGIFStruct.width, mGIFStruct.height);
|
||||
|
||||
// Use correct format, RGB for first frame, PAL for following frames
|
||||
// and include transparency to allow for optimization of opaque images
|
||||
nsresult rv = NS_OK;
|
||||
if (mGIFStruct.images_decoded) {
|
||||
// Image data is stored with original depth and palette
|
||||
NeedNewFrame(mGIFStruct.images_decoded, mGIFStruct.x_offset,
|
||||
mGIFStruct.y_offset, mGIFStruct.width, mGIFStruct.height,
|
||||
format, aDepth);
|
||||
// Image data is stored with original depth and palette.
|
||||
rv = AllocateFrame(mGIFStruct.images_decoded, GetSize(),
|
||||
frameRect, format, aDepth);
|
||||
} else {
|
||||
nsRefPtr<imgFrame> currentFrame = GetCurrentFrame();
|
||||
|
||||
// Our first full frame is automatically created by the image decoding
|
||||
// infrastructure. Just use it as long as it matches up.
|
||||
if (!currentFrame->GetRect().IsEqualEdges(nsIntRect(mGIFStruct.x_offset,
|
||||
mGIFStruct.y_offset,
|
||||
mGIFStruct.width,
|
||||
mGIFStruct.height))) {
|
||||
|
||||
if (!nsIntRect(nsIntPoint(), GetSize()).IsEqualEdges(frameRect)) {
|
||||
// We need padding on the first frame, which means that we don't draw into
|
||||
// part of the image at all. Report that as transparency.
|
||||
PostHasTransparency();
|
||||
|
||||
// Regardless of depth of input, image is decoded into 24bit RGB
|
||||
NeedNewFrame(mGIFStruct.images_decoded, mGIFStruct.x_offset,
|
||||
mGIFStruct.y_offset, mGIFStruct.width, mGIFStruct.height,
|
||||
format);
|
||||
}
|
||||
|
||||
// Regardless of depth of input, the first frame is decoded into 24bit RGB.
|
||||
rv = AllocateFrame(mGIFStruct.images_decoded, GetSize(),
|
||||
frameRect, format);
|
||||
}
|
||||
|
||||
mCurrentFrameIndex = mGIFStruct.images_decoded;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
@ -967,27 +963,13 @@ nsGIFDecoder2::WriteInternal(const char* aBuffer, uint32_t aCount)
|
|||
}
|
||||
// Mask to limit the color values within the colormap
|
||||
mColorMask = 0xFF >> (8 - realDepth);
|
||||
BeginImageFrame(realDepth);
|
||||
|
||||
if (NeedsNewFrame()) {
|
||||
// We now need a new frame from the decoder framework. We leave all our
|
||||
// data in the buffer as if it wasn't consumed, copy to our hold and
|
||||
// return to the decoder framework.
|
||||
uint32_t size =
|
||||
len + mGIFStruct.bytes_to_consume + mGIFStruct.bytes_in_hold;
|
||||
if (size) {
|
||||
if (SetHold(q,
|
||||
mGIFStruct.bytes_to_consume + mGIFStruct.bytes_in_hold,
|
||||
buf, len)) {
|
||||
// Back into the decoder infrastructure so we can get called again.
|
||||
GETN(9, gif_image_header_continue);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
// FALL THROUGH
|
||||
if (NS_FAILED(BeginImageFrame(realDepth))) {
|
||||
mGIFStruct.state = gif_error;
|
||||
return;
|
||||
}
|
||||
|
||||
// FALL THROUGH
|
||||
}
|
||||
|
||||
case gif_image_header_continue: {
|
||||
|
|
|
@ -35,7 +35,7 @@ private:
|
|||
// frame size information, etc.
|
||||
|
||||
void BeginGIF();
|
||||
void BeginImageFrame(uint16_t aDepth);
|
||||
nsresult BeginImageFrame(uint16_t aDepth);
|
||||
void EndImageFrame();
|
||||
void FlushImageData();
|
||||
void FlushImageData(uint32_t fromRow, uint32_t rows);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* vim:set tw=80 expandtab softtabstop=4 ts=4 sw=4: */
|
||||
/* vim:set tw=80 expandtab softtabstop=2 ts=2 sw=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/. */
|
||||
|
@ -80,13 +80,35 @@ nsICODecoder::FinishInternal()
|
|||
// We shouldn't be called in error cases
|
||||
MOZ_ASSERT(!HasError(), "Shouldn't call FinishInternal after error!");
|
||||
|
||||
// Finish the internally used decoder as well
|
||||
if (mContainedDecoder) {
|
||||
mContainedDecoder->FinishSharedDecoder();
|
||||
mDecodeDone = mContainedDecoder->GetDecodeDone();
|
||||
mProgress |= mContainedDecoder->TakeProgress();
|
||||
mInvalidRect.UnionRect(mInvalidRect, mContainedDecoder->TakeInvalidRect());
|
||||
// Finish the internally used decoder as well.
|
||||
if (mContainedDecoder && !mContainedDecoder->HasError()) {
|
||||
mContainedDecoder->FinishInternal();
|
||||
}
|
||||
|
||||
GetFinalStateFromContainedDecoder();
|
||||
}
|
||||
|
||||
void
|
||||
nsICODecoder::FinishWithErrorInternal()
|
||||
{
|
||||
GetFinalStateFromContainedDecoder();
|
||||
}
|
||||
|
||||
void
|
||||
nsICODecoder::GetFinalStateFromContainedDecoder()
|
||||
{
|
||||
if (!mContainedDecoder) {
|
||||
return;
|
||||
}
|
||||
|
||||
mDecodeDone = mContainedDecoder->GetDecodeDone();
|
||||
mDataError = mDataError || mContainedDecoder->HasDataError();
|
||||
mFailCode = NS_SUCCEEDED(mFailCode) ? mContainedDecoder->GetDecoderError()
|
||||
: mFailCode;
|
||||
mDecodeAborted = mContainedDecoder->WasAborted();
|
||||
mProgress |= mContainedDecoder->TakeProgress();
|
||||
mInvalidRect.UnionRect(mInvalidRect, mContainedDecoder->TakeInvalidRect());
|
||||
mCurrentFrame = mContainedDecoder->GetCurrentFrameRef();
|
||||
}
|
||||
|
||||
// Returns a buffer filled with the bitmap file header in little endian:
|
||||
|
@ -217,13 +239,8 @@ void
|
|||
nsICODecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
||||
{
|
||||
MOZ_ASSERT(!HasError(), "Shouldn't call WriteInternal after error!");
|
||||
|
||||
if (!aCount) {
|
||||
if (mContainedDecoder) {
|
||||
WriteToContainedDecoder(aBuffer, aCount);
|
||||
}
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(aBuffer);
|
||||
MOZ_ASSERT(aCount > 0);
|
||||
|
||||
while (aCount && (mPos < ICONCOUNTOFFSET)) { // Skip to the # of icons.
|
||||
if (mPos == 2) { // if the third byte is 1: This is an icon, 2: a cursor
|
||||
|
@ -343,9 +360,7 @@ nsICODecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
|||
mContainedDecoder = new nsPNGDecoder(mImage);
|
||||
mContainedDecoder->SetSizeDecode(IsSizeDecode());
|
||||
mContainedDecoder->SetSendPartialInvalidations(mSendPartialInvalidations);
|
||||
mContainedDecoder->InitSharedDecoder(mImageData, mImageDataLength,
|
||||
mColormap, mColormapSize,
|
||||
Move(mRefForContainedDecoder));
|
||||
mContainedDecoder->Init();
|
||||
if (!WriteToContainedDecoder(mSignature, PNGSIGNATURESIZE)) {
|
||||
return;
|
||||
}
|
||||
|
@ -422,9 +437,7 @@ nsICODecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
|||
bmpDecoder->SetUseAlphaData(true);
|
||||
mContainedDecoder->SetSizeDecode(IsSizeDecode());
|
||||
mContainedDecoder->SetSendPartialInvalidations(mSendPartialInvalidations);
|
||||
mContainedDecoder->InitSharedDecoder(mImageData, mImageDataLength,
|
||||
mColormap, mColormapSize,
|
||||
Move(mRefForContainedDecoder));
|
||||
mContainedDecoder->Init();
|
||||
|
||||
// The ICO format when containing a BMP does not include the 14 byte
|
||||
// bitmap file header. To use the code of the BMP decoder we need to
|
||||
|
@ -627,35 +640,5 @@ nsICODecoder::ProcessDirEntry(IconDirEntry& aTarget)
|
|||
aTarget.mImageOffset = LittleEndian::readUint32(&aTarget.mImageOffset);
|
||||
}
|
||||
|
||||
bool
|
||||
nsICODecoder::NeedsNewFrame() const
|
||||
{
|
||||
if (mContainedDecoder) {
|
||||
return mContainedDecoder->NeedsNewFrame();
|
||||
}
|
||||
|
||||
return Decoder::NeedsNewFrame();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsICODecoder::AllocateFrame(const nsIntSize& aTargetSize /* = nsIntSize() */)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (mContainedDecoder) {
|
||||
rv = mContainedDecoder->AllocateFrame(aTargetSize);
|
||||
mCurrentFrame = mContainedDecoder->GetCurrentFrameRef();
|
||||
mProgress |= mContainedDecoder->TakeProgress();
|
||||
mInvalidRect.UnionRect(mInvalidRect, mContainedDecoder->TakeInvalidRect());
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Grab a strong ref that we'll later hand over to the contained decoder. This
|
||||
// lets us avoid creating a RawAccessFrameRef off-main-thread.
|
||||
rv = Decoder::AllocateFrame(aTargetSize);
|
||||
mRefForContainedDecoder = GetCurrentFrameRef();
|
||||
return rv;
|
||||
}
|
||||
|
||||
} // namespace image
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -40,17 +40,16 @@ public:
|
|||
|
||||
virtual void WriteInternal(const char* aBuffer, uint32_t aCount) override;
|
||||
virtual void FinishInternal() override;
|
||||
virtual nsresult AllocateFrame(const nsIntSize& aTargetSize
|
||||
/* = nsIntSize() */) override;
|
||||
|
||||
protected:
|
||||
virtual bool NeedsNewFrame() const override;
|
||||
virtual void FinishWithErrorInternal() override;
|
||||
|
||||
private:
|
||||
// Writes to the contained decoder and sets the appropriate errors
|
||||
// Returns true if there are no errors.
|
||||
bool WriteToContainedDecoder(const char* aBuffer, uint32_t aCount);
|
||||
|
||||
// Gets decoder state from the contained decoder so it's visible externally.
|
||||
void GetFinalStateFromContainedDecoder();
|
||||
|
||||
// Processes a single dir entry of the icon resource
|
||||
void ProcessDirEntry(IconDirEntry& aTarget);
|
||||
// Sets the hotspot property of if we have a cursor
|
||||
|
@ -84,7 +83,6 @@ private:
|
|||
uint32_t mRowBytes; // How many bytes of the row were already received
|
||||
int32_t mOldLine; // Previous index of the line
|
||||
nsRefPtr<Decoder> mContainedDecoder; // Contains either a BMP or PNG resource
|
||||
RawAccessFrameRef mRefForContainedDecoder; // Avoid locking off-main-thread
|
||||
|
||||
char mDirEntryArray[ICODIRENTRYSIZE]; // Holds the current dir entry buffer
|
||||
IconDirEntry mDirEntry; // Holds a decoded dir entry
|
||||
|
|
|
@ -73,11 +73,17 @@ nsIconDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
|||
break;
|
||||
}
|
||||
|
||||
if (!mImageData) {
|
||||
PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
{
|
||||
MOZ_ASSERT(!mImageData, "Already have a buffer allocated?");
|
||||
nsresult rv = AllocateBasicFrame();
|
||||
if (NS_FAILED(rv)) {
|
||||
mState = iconStateFinished;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mImageData, "Should have a buffer now");
|
||||
|
||||
// Book Keeping
|
||||
aBuffer++;
|
||||
aCount--;
|
||||
|
|
|
@ -396,14 +396,20 @@ nsJPEGDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
|
|||
mInfo.buffered_image = mDecodeStyle == PROGRESSIVE &&
|
||||
jpeg_has_multiple_scans(&mInfo);
|
||||
|
||||
if (!mImageData) {
|
||||
MOZ_ASSERT(!mImageData, "Already have a buffer allocated?");
|
||||
nsIntSize targetSize = mDownscaler ? mDownscaler->TargetSize() : GetSize();
|
||||
nsresult rv = AllocateFrame(0, targetSize,
|
||||
nsIntRect(nsIntPoint(), targetSize),
|
||||
gfx::SurfaceFormat::B8G8R8A8);
|
||||
if (NS_FAILED(rv)) {
|
||||
mState = JPEG_ERROR;
|
||||
PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
|
||||
MOZ_LOG(GetJPEGDecoderAccountingLog(), LogLevel::Debug,
|
||||
("} (could not initialize image frame)"));
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mImageData, "Should have a buffer now");
|
||||
|
||||
if (mDownscaler) {
|
||||
nsresult rv = mDownscaler->BeginFrame(GetSize(),
|
||||
mImageData,
|
||||
|
|
|
@ -141,38 +141,43 @@ nsPNGDecoder::~nsPNGDecoder()
|
|||
}
|
||||
|
||||
// CreateFrame() is used for both simple and animated images
|
||||
void nsPNGDecoder::CreateFrame(png_uint_32 x_offset, png_uint_32 y_offset,
|
||||
int32_t width, int32_t height,
|
||||
gfx::SurfaceFormat format)
|
||||
nsresult
|
||||
nsPNGDecoder::CreateFrame(png_uint_32 aXOffset, png_uint_32 aYOffset,
|
||||
int32_t aWidth, int32_t aHeight,
|
||||
gfx::SurfaceFormat aFormat)
|
||||
{
|
||||
MOZ_ASSERT(HasSize());
|
||||
|
||||
if (format == gfx::SurfaceFormat::B8G8R8A8) {
|
||||
if (aFormat == gfx::SurfaceFormat::B8G8R8A8) {
|
||||
PostHasTransparency();
|
||||
}
|
||||
|
||||
// Our first full frame is automatically created by the image decoding
|
||||
// infrastructure. Just use it as long as it matches up.
|
||||
nsIntRect neededRect(x_offset, y_offset, width, height);
|
||||
nsRefPtr<imgFrame> currentFrame = GetCurrentFrame();
|
||||
if (!currentFrame->GetRect().IsEqualEdges(neededRect)) {
|
||||
if (mNumFrames == 0) {
|
||||
// We need padding on the first frame, which means that we don't draw into
|
||||
// part of the image at all. Report that as transparency.
|
||||
PostHasTransparency();
|
||||
}
|
||||
|
||||
NeedNewFrame(mNumFrames, x_offset, y_offset, width, height, format);
|
||||
} else if (mNumFrames != 0) {
|
||||
NeedNewFrame(mNumFrames, x_offset, y_offset, width, height, format);
|
||||
nsIntRect frameRect(aXOffset, aYOffset, aWidth, aHeight);
|
||||
if (mNumFrames == 0 &&
|
||||
!nsIntRect(nsIntPoint(), GetSize()).IsEqualEdges(frameRect)) {
|
||||
// We need padding on the first frame, which means that we don't draw into
|
||||
// part of the image at all. Report that as transparency.
|
||||
PostHasTransparency();
|
||||
}
|
||||
|
||||
mFrameRect = neededRect;
|
||||
// XXX(seth): Some tests depend on the first frame of PNGs being B8G8R8A8.
|
||||
// This is something we should fix.
|
||||
gfx::SurfaceFormat format = aFormat;
|
||||
if (mNumFrames == 0) {
|
||||
format = gfx::SurfaceFormat::B8G8R8A8;
|
||||
}
|
||||
|
||||
nsresult rv = AllocateFrame(mNumFrames, GetSize(), frameRect, format);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mFrameRect = frameRect;
|
||||
|
||||
MOZ_LOG(GetPNGDecoderAccountingLog(), LogLevel::Debug,
|
||||
("PNGDecoderAccounting: nsPNGDecoder::CreateFrame -- created "
|
||||
"image frame with %dx%d pixels in container %p",
|
||||
width, height,
|
||||
aWidth, aHeight,
|
||||
&mImage));
|
||||
|
||||
#ifdef PNG_APNG_SUPPORTED
|
||||
|
@ -186,6 +191,8 @@ void nsPNGDecoder::CreateFrame(png_uint_32 x_offset, png_uint_32 y_offset,
|
|||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// set timeout and frame disposal method for the current frame
|
||||
|
@ -651,7 +658,11 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
|
|||
decoder->mFrameIsHidden = true;
|
||||
} else {
|
||||
#endif
|
||||
decoder->CreateFrame(0, 0, width, height, decoder->format);
|
||||
nsresult rv = decoder->CreateFrame(0, 0, width, height, decoder->format);
|
||||
if (NS_FAILED(rv)) {
|
||||
png_longjmp(decoder->mPNG, 5); // NS_ERROR_OUT_OF_MEMORY
|
||||
}
|
||||
MOZ_ASSERT(decoder->mImageData, "Should have a buffer now");
|
||||
#ifdef PNG_APNG_SUPPORTED
|
||||
}
|
||||
#endif
|
||||
|
@ -674,12 +685,6 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
|
|||
png_longjmp(decoder->mPNG, 5); // NS_ERROR_OUT_OF_MEMORY
|
||||
}
|
||||
}
|
||||
|
||||
if (decoder->NeedsNewFrame()) {
|
||||
// We know that we need a new frame, so pause input so the decoder
|
||||
// infrastructure can give it to us.
|
||||
png_process_data_pause(png_ptr, /* save = */ 1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -831,13 +836,12 @@ nsPNGDecoder::frame_info_callback(png_structp png_ptr, png_uint_32 frame_num)
|
|||
width = png_get_next_frame_width(png_ptr, decoder->mInfo);
|
||||
height = png_get_next_frame_height(png_ptr, decoder->mInfo);
|
||||
|
||||
decoder->CreateFrame(x_offset, y_offset, width, height, decoder->format);
|
||||
|
||||
if (decoder->NeedsNewFrame()) {
|
||||
// We know that we need a new frame, so pause input so the decoder
|
||||
// infrastructure can give it to us.
|
||||
png_process_data_pause(png_ptr, /* save = */ 1);
|
||||
nsresult rv =
|
||||
decoder->CreateFrame(x_offset, y_offset, width, height, decoder->format);
|
||||
if (NS_FAILED(rv)) {
|
||||
png_longjmp(decoder->mPNG, 5); // NS_ERROR_OUT_OF_MEMORY
|
||||
}
|
||||
MOZ_ASSERT(decoder->mImageData, "Should have a buffer now");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -31,9 +31,9 @@ public:
|
|||
virtual void WriteInternal(const char* aBuffer, uint32_t aCount) override;
|
||||
virtual Telemetry::ID SpeedHistogram() override;
|
||||
|
||||
void CreateFrame(png_uint_32 x_offset, png_uint_32 y_offset,
|
||||
int32_t width, int32_t height,
|
||||
gfx::SurfaceFormat format);
|
||||
nsresult CreateFrame(png_uint_32 aXOffset, png_uint_32 aYOffset,
|
||||
int32_t aWidth, int32_t aHeight,
|
||||
gfx::SurfaceFormat aFormat);
|
||||
void EndImageFrame();
|
||||
|
||||
// Check if PNG is valid ICO (32bpp RGBA)
|
||||
|
|
|
@ -167,80 +167,6 @@ imgFrame::~imgFrame()
|
|||
mPalettedImageData = nullptr;
|
||||
}
|
||||
|
||||
nsresult
|
||||
imgFrame::ReinitForDecoder(const nsIntSize& aImageSize,
|
||||
const nsIntRect& aRect,
|
||||
SurfaceFormat aFormat,
|
||||
uint8_t aPaletteDepth /* = 0 */,
|
||||
bool aNonPremult /* = false */)
|
||||
{
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
|
||||
if (mDecoded.x != 0 || mDecoded.y != 0 ||
|
||||
mDecoded.width != 0 || mDecoded.height != 0) {
|
||||
MOZ_ASSERT_UNREACHABLE("Shouldn't reinit after write");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (mAborted) {
|
||||
MOZ_ASSERT_UNREACHABLE("Shouldn't reinit if aborted");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (mLockCount < 1) {
|
||||
MOZ_ASSERT_UNREACHABLE("Shouldn't reinit unless locked");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Restore everything (except mLockCount, which we need to keep) to how it was
|
||||
// when we were first created.
|
||||
// XXX(seth): This is probably a little excessive, but I want to be *really*
|
||||
// sure that nothing got missed.
|
||||
mDecoded = nsIntRect(0, 0, 0, 0);
|
||||
mTimeout = 100;
|
||||
mDisposalMethod = DisposalMethod::NOT_SPECIFIED;
|
||||
mBlendMethod = BlendMethod::OVER;
|
||||
mHasNoAlpha = false;
|
||||
mAborted = false;
|
||||
mPaletteDepth = 0;
|
||||
mNonPremult = false;
|
||||
mSinglePixel = false;
|
||||
mCompositingFailed = false;
|
||||
mOptimizable = false;
|
||||
mImageSize = IntSize();
|
||||
mSize = IntSize();
|
||||
mOffset = nsIntPoint();
|
||||
mSinglePixelColor = Color();
|
||||
|
||||
// Release all surfaces.
|
||||
mImageSurface = nullptr;
|
||||
mOptSurface = nullptr;
|
||||
mVBuf = nullptr;
|
||||
mVBufPtr = nullptr;
|
||||
free(mPalettedImageData);
|
||||
mPalettedImageData = nullptr;
|
||||
|
||||
// Reinitialize.
|
||||
nsresult rv = InitForDecoder(aImageSize, aRect, aFormat,
|
||||
aPaletteDepth, aNonPremult);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// We were locked before; perform the same actions we would've performed when
|
||||
// we originally got locked.
|
||||
if (mImageSurface) {
|
||||
mVBufPtr = mVBuf;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!mPalettedImageData) {
|
||||
MOZ_ASSERT_UNREACHABLE("We got optimized somehow during reinit");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Paletted images don't have surfaces, so there's nothing to do.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
imgFrame::InitForDecoder(const nsIntSize& aImageSize,
|
||||
const nsIntRect& aRect,
|
||||
|
|
|
@ -157,19 +157,6 @@ public:
|
|||
GraphicsFilter aFilter,
|
||||
uint32_t aImageFlags);
|
||||
|
||||
/**
|
||||
* Reinitializes an existing imgFrame with new parameters. You must be holding
|
||||
* a RawAccessFrameRef to the imgFrame, and it must never have been written
|
||||
* to, marked finished, or aborted.
|
||||
*
|
||||
* XXX(seth): We will remove this in bug 1117607.
|
||||
*/
|
||||
nsresult ReinitForDecoder(const nsIntSize& aImageSize,
|
||||
const nsIntRect& aRect,
|
||||
SurfaceFormat aFormat,
|
||||
uint8_t aPaletteDepth = 0,
|
||||
bool aNonPremult = false);
|
||||
|
||||
DrawableFrameRef DrawableRef();
|
||||
RawAccessFrameRef RawAccessRef();
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче