michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef MOZILLA_IMAGELIB_DECODER_H_ michael@0: #define MOZILLA_IMAGELIB_DECODER_H_ michael@0: michael@0: #include "RasterImage.h" michael@0: #include "imgDecoderObserver.h" michael@0: #include "mozilla/RefPtr.h" michael@0: #include "DecodeStrategy.h" michael@0: #include "ImageMetadata.h" michael@0: #include "Orientation.h" michael@0: #include "mozilla/Telemetry.h" michael@0: michael@0: namespace mozilla { michael@0: namespace image { michael@0: michael@0: class Decoder michael@0: { michael@0: public: michael@0: michael@0: Decoder(RasterImage& aImage); michael@0: virtual ~Decoder(); michael@0: michael@0: /** michael@0: * Initialize an image decoder. Decoders may not be re-initialized. michael@0: * michael@0: * Notifications Sent: TODO michael@0: */ michael@0: void Init(); michael@0: michael@0: /** michael@0: * Initializes a decoder whose image and observer is already being used by a michael@0: * parent decoder. Decoders may not be re-initialized. michael@0: * michael@0: * Notifications Sent: TODO michael@0: */ michael@0: void InitSharedDecoder(uint8_t* imageData, uint32_t imageDataLength, michael@0: uint32_t* colormap, uint32_t colormapSize, michael@0: imgFrame* currentFrame); michael@0: michael@0: /** michael@0: * Writes data to the decoder. michael@0: * michael@0: * @param aBuffer buffer containing the data to be written michael@0: * @param aCount the number of bytes to write michael@0: * michael@0: * Any errors are reported by setting the appropriate state on the decoder. michael@0: * michael@0: * Notifications Sent: TODO michael@0: */ michael@0: void Write(const char* aBuffer, uint32_t aCount, DecodeStrategy aStrategy); michael@0: michael@0: /** michael@0: * Informs the decoder that all the data has been written. michael@0: * michael@0: * Notifications Sent: TODO michael@0: */ michael@0: void Finish(RasterImage::eShutdownIntent aShutdownIntent); michael@0: michael@0: /** michael@0: * Informs the shared decoder that all the data has been written. michael@0: * Should only be used if InitSharedDecoder was useed michael@0: * michael@0: * Notifications Sent: TODO michael@0: */ michael@0: void FinishSharedDecoder(); michael@0: michael@0: /** michael@0: * Tells the decoder to flush any pending invalidations. This informs the image michael@0: * frame of its decoded region, and sends the appropriate OnDataAvailable call michael@0: * to consumers. michael@0: * michael@0: * This can be called any time when we're midway through decoding a frame, michael@0: * and must be called after finishing a frame (before starting a new one). michael@0: */ michael@0: void FlushInvalidations(); michael@0: michael@0: // We're not COM-y, so we don't get refcounts by default michael@0: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Decoder) michael@0: michael@0: /* michael@0: * State. michael@0: */ michael@0: michael@0: // If we're doing a "size decode", we more or less pass through the image michael@0: // data, stopping only to scoop out the image dimensions. A size decode michael@0: // must be enabled by SetSizeDecode() _before_calling Init(). michael@0: bool IsSizeDecode() { return mSizeDecode; } michael@0: void SetSizeDecode(bool aSizeDecode) michael@0: { michael@0: NS_ABORT_IF_FALSE(!mInitialized, "Can't set size decode after Init()!"); michael@0: mSizeDecode = aSizeDecode; michael@0: } michael@0: michael@0: void SetObserver(imgDecoderObserver* aObserver) michael@0: { michael@0: MOZ_ASSERT(aObserver); michael@0: mObserver = aObserver; michael@0: } michael@0: michael@0: // The number of frames we have, including anything in-progress. Thus, this michael@0: // is only 0 if we haven't begun any frames. michael@0: uint32_t GetFrameCount() { return mFrameCount; } michael@0: michael@0: // The number of complete frames we have (ie, not including anything in-progress). michael@0: uint32_t GetCompleteFrameCount() { return mInFrame ? mFrameCount - 1 : mFrameCount; } michael@0: michael@0: // Error tracking michael@0: bool HasError() { return HasDataError() || HasDecoderError(); } michael@0: bool HasDataError() { return mDataError; } michael@0: bool HasDecoderError() { return NS_FAILED(mFailCode); } michael@0: nsresult GetDecoderError() { return mFailCode; } michael@0: void PostResizeError() { PostDataError(); } michael@0: bool GetDecodeDone() const { michael@0: return mDecodeDone; michael@0: } michael@0: michael@0: // flags. Keep these in sync with imgIContainer.idl. michael@0: // SetDecodeFlags must be called before Init(), otherwise michael@0: // default flags are assumed. michael@0: enum { michael@0: DECODER_NO_PREMULTIPLY_ALPHA = 0x2, // imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA michael@0: DECODER_NO_COLORSPACE_CONVERSION = 0x4 // imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION michael@0: }; michael@0: michael@0: enum DecodeStyle { michael@0: PROGRESSIVE, // produce intermediate frames representing the partial state of the image michael@0: SEQUENTIAL // decode to final image immediately michael@0: }; michael@0: michael@0: void SetDecodeFlags(uint32_t aFlags) { mDecodeFlags = aFlags; } michael@0: uint32_t GetDecodeFlags() { return mDecodeFlags; } michael@0: michael@0: bool HasSize() const { return mImageMetadata.HasSize(); } michael@0: void SetSizeOnImage(); michael@0: michael@0: // Use HistogramCount as an invalid Histogram ID michael@0: virtual Telemetry::ID SpeedHistogram() { return Telemetry::HistogramCount; } michael@0: michael@0: ImageMetadata& GetImageMetadata() { return mImageMetadata; } michael@0: michael@0: // Tell the decoder infrastructure to allocate a frame. By default, frame 0 michael@0: // is created as an ARGB frame with no offset and with size width * height. michael@0: // If decoders need something different, they must ask for it. michael@0: // This is called by decoders when they need a new frame. These decoders michael@0: // must then save the data they have been sent but not yet processed and michael@0: // return from WriteInternal. When the new frame is created, WriteInternal michael@0: // will be called again with nullptr and 0 as arguments. michael@0: void NeedNewFrame(uint32_t frameNum, uint32_t x_offset, uint32_t y_offset, michael@0: uint32_t width, uint32_t height, michael@0: gfxImageFormat format, michael@0: uint8_t palette_depth = 0); michael@0: michael@0: virtual bool NeedsNewFrame() const { return mNeedsNewFrame; } michael@0: michael@0: // Try to allocate a frame as described in mNewFrameData and return the michael@0: // status code from that attempt. Clears mNewFrameData. michael@0: virtual nsresult AllocateFrame(); michael@0: michael@0: // Called when a chunk of decoding has been done and the frame needs to be michael@0: // marked as dirty. Must be called only on the main thread. michael@0: void MarkFrameDirty(); michael@0: michael@0: imgFrame* GetCurrentFrame() const { return mCurrentFrame; } michael@0: michael@0: protected: michael@0: michael@0: /* michael@0: * Internal hooks. Decoder implementations may override these and michael@0: * only these methods. michael@0: */ michael@0: virtual void InitInternal(); michael@0: virtual void WriteInternal(const char* aBuffer, uint32_t aCount, DecodeStrategy aStrategy); michael@0: virtual void FinishInternal(); michael@0: michael@0: /* michael@0: * Progress notifications. michael@0: */ michael@0: michael@0: // Called by decoders when they determine the size of the image. Informs michael@0: // the image of its size and sends notifications. michael@0: void PostSize(int32_t aWidth, michael@0: int32_t aHeight, michael@0: Orientation aOrientation = Orientation()); michael@0: michael@0: // Called by decoders when they begin a frame. Informs the image, sends michael@0: // notifications, and does internal book-keeping. michael@0: void PostFrameStart(); michael@0: michael@0: // Called by decoders when they end a frame. Informs the image, sends michael@0: // notifications, and does internal book-keeping. michael@0: // Specify whether this frame is opaque as an optimization. michael@0: // For animated images, specify the disposal, blend method and timeout for michael@0: // this frame. michael@0: void PostFrameStop(FrameBlender::FrameAlpha aFrameAlpha = FrameBlender::kFrameHasAlpha, michael@0: FrameBlender::FrameDisposalMethod aDisposalMethod = FrameBlender::kDisposeKeep, michael@0: int32_t aTimeout = 0, michael@0: FrameBlender::FrameBlendMethod aBlendMethod = FrameBlender::kBlendOver); michael@0: michael@0: // Called by the decoders when they have a region to invalidate. We may not michael@0: // actually pass these invalidations on right away. michael@0: void PostInvalidation(nsIntRect& aRect); michael@0: michael@0: // Called by the decoders when they have successfully decoded the image. This michael@0: // may occur as the result of the decoder getting to the appropriate point in michael@0: // the stream, or by us calling FinishInternal(). michael@0: // michael@0: // May not be called mid-frame. michael@0: // michael@0: // For animated images, specify the loop count. -1 means loop forever, 0 michael@0: // means a single iteration, stopping on the last frame. michael@0: void PostDecodeDone(int32_t aLoopCount = 0); michael@0: michael@0: // Data errors are the fault of the source data, decoder errors are our fault michael@0: void PostDataError(); michael@0: void PostDecoderError(nsresult aFailCode); michael@0: michael@0: /* michael@0: * Member variables. michael@0: * michael@0: */ michael@0: RasterImage &mImage; michael@0: imgFrame* mCurrentFrame; michael@0: RefPtr mObserver; michael@0: ImageMetadata mImageMetadata; michael@0: michael@0: uint8_t* mImageData; // Pointer to image data in either Cairo or 8bit format michael@0: uint32_t mImageDataLength; michael@0: uint32_t* mColormap; // Current colormap to be used in Cairo format michael@0: uint32_t mColormapSize; michael@0: michael@0: uint32_t mDecodeFlags; michael@0: bool mDecodeDone; michael@0: bool mDataError; michael@0: michael@0: private: michael@0: uint32_t mFrameCount; // Number of frames, including anything in-progress michael@0: michael@0: nsIntRect mInvalidRect; // Tracks an invalidation region in the current frame. michael@0: michael@0: nsresult mFailCode; michael@0: michael@0: struct NewFrameData michael@0: { michael@0: NewFrameData() michael@0: {} michael@0: michael@0: NewFrameData(uint32_t num, uint32_t offsetx, uint32_t offsety, michael@0: uint32_t width, uint32_t height, michael@0: gfxImageFormat format, uint8_t paletteDepth) michael@0: : mFrameNum(num) michael@0: , mOffsetX(offsetx) michael@0: , mOffsetY(offsety) michael@0: , mWidth(width) michael@0: , mHeight(height) michael@0: , mFormat(format) michael@0: , mPaletteDepth(paletteDepth) michael@0: {} michael@0: uint32_t mFrameNum; michael@0: uint32_t mOffsetX; michael@0: uint32_t mOffsetY; michael@0: uint32_t mWidth; michael@0: uint32_t mHeight; michael@0: gfxImageFormat mFormat; michael@0: uint8_t mPaletteDepth; michael@0: }; michael@0: NewFrameData mNewFrameData; michael@0: bool mNeedsNewFrame; michael@0: bool mInitialized; michael@0: bool mSizeDecode; michael@0: bool mInFrame; michael@0: bool mIsAnimated; michael@0: }; michael@0: michael@0: } // namespace image michael@0: } // namespace mozilla michael@0: michael@0: #endif // MOZILLA_IMAGELIB_DECODER_H_