diff options
Diffstat (limited to 'Source/WebCore/platform/image-decoders/ImageDecoder.h')
-rw-r--r-- | Source/WebCore/platform/image-decoders/ImageDecoder.h | 396 |
1 files changed, 396 insertions, 0 deletions
diff --git a/Source/WebCore/platform/image-decoders/ImageDecoder.h b/Source/WebCore/platform/image-decoders/ImageDecoder.h new file mode 100644 index 0000000..c3d73c0 --- /dev/null +++ b/Source/WebCore/platform/image-decoders/ImageDecoder.h @@ -0,0 +1,396 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2008-2009 Torch Mobile, Inc. + * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ImageDecoder_h +#define ImageDecoder_h + +#include "IntRect.h" +#include "ImageSource.h" +#include "PlatformString.h" +#include "SharedBuffer.h" +#include <wtf/Assertions.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +#if PLATFORM(SKIA) +#include "NativeImageSkia.h" +#include "SkColorPriv.h" +#elif PLATFORM(QT) +#include <QPixmap> +#include <QImage> +#endif + +namespace WebCore { + + // FIXME: Do we want better encapsulation? + typedef Vector<char> ColorProfile; + + // The RGBA32Buffer object represents the decoded image data in RGBA32 + // format. This buffer is what all decoders write a single frame into. + // Frames are then instantiated for drawing by being handed this buffer. + class RGBA32Buffer { + public: + enum FrameStatus { FrameEmpty, FramePartial, FrameComplete }; + enum FrameDisposalMethod { + // If you change the numeric values of these, make sure you audit + // all users, as some users may cast raw values to/from these + // constants. + DisposeNotSpecified, // Leave frame in framebuffer + DisposeKeep, // Leave frame in framebuffer + DisposeOverwriteBgcolor, // Clear frame to transparent + DisposeOverwritePrevious, // Clear frame to previous framebuffer + // contents + }; +#if PLATFORM(SKIA) || PLATFORM(QT) + typedef uint32_t PixelData; +#else + typedef unsigned PixelData; +#endif + + RGBA32Buffer(); + + RGBA32Buffer(const RGBA32Buffer& other) { operator=(other); } + + // For backends which refcount their data, this operator doesn't need to + // create a new copy of the image data, only increase the ref count. + RGBA32Buffer& operator=(const RGBA32Buffer& other); + + // Deletes the pixel data entirely; used by ImageDecoder to save memory + // when we no longer need to display a frame and only need its metadata. + void clear(); + + // Zeroes the pixel data in the buffer, setting it to fully-transparent. + void zeroFill(); + + // Creates a new copy of the image data in |other|, so the two images + // can be modified independently. Returns whether the copy succeeded. + bool copyBitmapData(const RGBA32Buffer&); + + // Creates a new reference to the image data in |other|. The two images + // share a common backing store. + void copyReferenceToBitmapData(const RGBA32Buffer&); + + // Copies the pixel data at [(startX, startY), (endX, startY)) to the + // same X-coordinates on each subsequent row up to but not including + // endY. + void copyRowNTimes(int startX, int endX, int startY, int endY) + { + ASSERT(startX < width()); + ASSERT(endX <= width()); + ASSERT(startY < height()); + ASSERT(endY <= height()); + const int rowBytes = (endX - startX) * sizeof(PixelData); + const PixelData* const startAddr = getAddr(startX, startY); + for (int destY = startY + 1; destY < endY; ++destY) + memcpy(getAddr(startX, destY), startAddr, rowBytes); + } + +#if PLATFORM(ANDROID) + NativeImageSkia& bitmap() { return m_bitmap; } + const NativeImageSkia& bitmap() const { return m_bitmap; } +#endif + + // Allocates space for the pixel data. Must be called before any pixels + // are written. Will return true on success, false if the memory + // allocation fails. Calling this multiple times is undefined and may + // leak memory. + bool setSize(int newWidth, int newHeight); + + // To be used by ImageSource::createFrameAtIndex(). Returns a pointer + // to the underlying native image data. This pointer will be owned by + // the BitmapImage and freed in FrameData::clear(). + NativeImagePtr asNewNativeImage() const; + + bool hasAlpha() const; + const IntRect& rect() const { return m_rect; } + FrameStatus status() const { return m_status; } + unsigned duration() const { return m_duration; } + FrameDisposalMethod disposalMethod() const { return m_disposalMethod; } + bool premultiplyAlpha() const { return m_premultiplyAlpha; } + + void setHasAlpha(bool alpha); + void setColorProfile(const ColorProfile&); + void setRect(const IntRect& r) { m_rect = r; } + void setStatus(FrameStatus status); + void setDuration(unsigned duration) { m_duration = duration; } + void setDisposalMethod(FrameDisposalMethod method) { m_disposalMethod = method; } + void setPremultiplyAlpha(bool premultiplyAlpha) { m_premultiplyAlpha = premultiplyAlpha; } + + inline void setRGBA(int x, int y, unsigned r, unsigned g, unsigned b, unsigned a) + { + setRGBA(getAddr(x, y), r, g, b, a); + } + +#if PLATFORM(QT) + void setPixmap(const QPixmap& pixmap); +#endif + + private: +#if PLATFORM(CG) + typedef RetainPtr<CFMutableDataRef> NativeBackingStore; +#else + typedef Vector<PixelData> NativeBackingStore; +#endif + + int width() const; + int height() const; + + inline PixelData* getAddr(int x, int y) + { +#if PLATFORM(SKIA) + return m_bitmap.getAddr32(x, y); +#elif PLATFORM(QT) + m_image = m_pixmap.toImage(); + m_pixmap = QPixmap(); + return reinterpret_cast_ptr<QRgb*>(m_image.scanLine(y)) + x; +#else + return m_bytes + (y * width()) + x; +#endif + } + + inline void setRGBA(PixelData* dest, unsigned r, unsigned g, unsigned b, unsigned a) + { + if (m_premultiplyAlpha && !a) + *dest = 0; + else { + if (m_premultiplyAlpha && a < 255) { + float alphaPercent = a / 255.0f; + r = static_cast<unsigned>(r * alphaPercent); + g = static_cast<unsigned>(g * alphaPercent); + b = static_cast<unsigned>(b * alphaPercent); + } +#if PLATFORM(ANDROID) + *dest = SkPackARGB32(a, r, g, b); +#else + *dest = (a << 24 | r << 16 | g << 8 | b); +#endif + } + } + +#if PLATFORM(SKIA) + NativeImageSkia m_bitmap; +#elif PLATFORM(QT) + mutable QPixmap m_pixmap; + mutable QImage m_image; + bool m_hasAlpha; + IntSize m_size; +#else + NativeBackingStore m_backingStore; + PixelData* m_bytes; // The memory is backed by m_backingStore. + IntSize m_size; // The size of the buffer. This should be the + // same as ImageDecoder::m_size. + bool m_hasAlpha; // Whether or not any of the pixels in the buffer + // have transparency. + ColorProfile m_colorProfile; +#endif + IntRect m_rect; // The rect of the original specified frame within + // the overall buffer. This will always just be + // the entire buffer except for GIF frames whose + // original rect was smaller than the overall + // image size. + FrameStatus m_status; // Whether or not this frame is completely + // finished decoding. + unsigned m_duration; // The animation delay. + FrameDisposalMethod m_disposalMethod; // What to do with this frame's data when + // initializing the next frame. + bool m_premultiplyAlpha; // Whether to premultiply alpha into R, G, B + // channels; by default it's true. + }; + + // The ImageDecoder class represents a base class for specific image format + // decoders (e.g., GIF, JPG, PNG, ICO) to derive from. All decoders decode + // into RGBA32 format and the base class manages the RGBA32 frame cache. + // + // ENABLE(IMAGE_DECODER_DOWN_SAMPLING) allows image decoders to write + // directly to scaled output buffers by down sampling. Call + // setMaxNumPixels() to specify the biggest size that decoded images can + // have. Image decoders will deflate those images that are bigger than + // m_maxNumPixels. (Not supported by all image decoders yet) + class ImageDecoder : public Noncopyable { + public: + ImageDecoder(ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption) + : m_scaled(false) + , m_premultiplyAlpha(alphaOption == ImageSource::AlphaPremultiplied) + , m_ignoreGammaAndColorProfile(gammaAndColorProfileOption == ImageSource::GammaAndColorProfileIgnored) + , m_sizeAvailable(false) + , m_maxNumPixels(-1) + , m_isAllDataReceived(false) + , m_failed(false) + { + } + + virtual ~ImageDecoder() {} + + // Factory function to create an ImageDecoder. Ports that subclass + // ImageDecoder can provide their own implementation of this to avoid + // needing to write a dedicated setData() implementation. + static ImageDecoder* create(const SharedBuffer& data, ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption); + + // The the filename extension usually associated with an undecoded image + // of this type. + virtual String filenameExtension() const = 0; + + bool isAllDataReceived() const { return m_isAllDataReceived; } + + virtual void setData(SharedBuffer* data, bool allDataReceived) + { + if (m_failed) + return; + m_data = data; + m_isAllDataReceived = allDataReceived; + } + + // Whether or not the size information has been decoded yet. This + // default implementation just returns true if the size has been set and + // we have not seen a failure. Decoders may want to override this to + // lazily decode enough of the image to get the size. + virtual bool isSizeAvailable() + { + return !m_failed && m_sizeAvailable; + } + + // Returns the size of the image. + virtual IntSize size() const + { + return m_size; + } + + IntSize scaledSize() const + { + return m_scaled ? IntSize(m_scaledColumns.size(), m_scaledRows.size()) : size(); + } + + // Returns the size of frame |index|. This will only differ from size() + // for formats where different frames are different sizes (namely ICO, + // where each frame represents a different icon within the master file). + // Notably, this does not return different sizes for different GIF + // frames, since while these may be stored as smaller rectangles, during + // decoding they are composited to create a full-size frame. + virtual IntSize frameSizeAtIndex(size_t) const + { + return size(); + } + + // Called by the image decoders to set their decoded size, this also + // checks the size for validity. It will return true if the size was + // set, or false if there is an error. On error, the m_failed flag will + // be set and the caller should immediately stop decoding. + virtual bool setSize(unsigned width, unsigned height) + { + if (isOverSize(width, height)) + return setFailed(); + m_size = IntSize(width, height); + m_sizeAvailable = true; + return true; + } + + // The total number of frames for the image. Classes that support + // multiple frames will scan the image data for the answer if they need + // to (without necessarily decoding all of the individual frames). + virtual size_t frameCount() { return 1; } + + // The number of repetitions to perform for an animation loop. + virtual int repetitionCount() const { return cAnimationNone; } + + // Called to obtain the RGBA32Buffer full of decoded data for rendering. + // The decoder plugin will decode as much of the frame as it can before + // handing back the buffer. + virtual RGBA32Buffer* frameBufferAtIndex(size_t) = 0; + + // Whether or not the underlying image format even supports alpha + // transparency. + virtual bool supportsAlpha() const { return true; } + + void setIgnoreGammaAndColorProfile(bool flag) { m_ignoreGammaAndColorProfile = flag; } + + // Whether or not the gamma and color profile are applied. + bool ignoresGammaAndColorProfile() const { return m_ignoreGammaAndColorProfile; } + + // Sets the "decode failure" flag. For caller convenience (since so + // many callers want to return false after calling this), returns false + // to enable easy tailcalling. Subclasses may override this to also + // clean up any local data. + virtual bool setFailed() + { + m_failed = true; + return false; + } + + bool failed() const { return m_failed; } + + // Wipe out frames in the frame buffer cache before |clearBeforeFrame|, + // assuming this can be done without breaking decoding. Different + // decoders place different restrictions on what frames are safe to + // destroy, so this is left to them to implement. + // For convenience's sake, we provide a default (empty) implementation, + // since in practice only GIFs will ever use this. + virtual void clearFrameBufferCache(size_t clearBeforeFrame) { } + +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) + void setMaxNumPixels(int m) { m_maxNumPixels = m; } +#endif + + protected: + void prepareScaleDataIfNecessary(); + int upperBoundScaledX(int origX, int searchStart = 0); + int lowerBoundScaledX(int origX, int searchStart = 0); + int upperBoundScaledY(int origY, int searchStart = 0); + int lowerBoundScaledY(int origY, int searchStart = 0); + int scaledY(int origY, int searchStart = 0); + + RefPtr<SharedBuffer> m_data; // The encoded data. + Vector<RGBA32Buffer> m_frameBufferCache; + ColorProfile m_colorProfile; + bool m_scaled; + Vector<int> m_scaledColumns; + Vector<int> m_scaledRows; + bool m_premultiplyAlpha; + bool m_ignoreGammaAndColorProfile; + + private: + // Some code paths compute the size of the image as "width * height * 4" + // and return it as a (signed) int. Avoid overflow. + static bool isOverSize(unsigned width, unsigned height) + { + // width * height must not exceed (2 ^ 29) - 1, so that we don't + // overflow when we multiply by 4. + unsigned long long total_size = static_cast<unsigned long long>(width) + * static_cast<unsigned long long>(height); + return total_size > ((1 << 29) - 1); + } + + IntSize m_size; + bool m_sizeAvailable; + int m_maxNumPixels; + bool m_isAllDataReceived; + bool m_failed; + }; + +} // namespace WebCore + +#endif |