summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/image-decoders
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/image-decoders')
-rw-r--r--WebCore/platform/image-decoders/ImageDecoder.h210
-rw-r--r--WebCore/platform/image-decoders/bmp/BMPImageDecoder.cpp158
-rw-r--r--WebCore/platform/image-decoders/bmp/BMPImageDecoder.h91
-rw-r--r--WebCore/platform/image-decoders/bmp/BMPImageReader.cpp (renamed from WebCore/platform/image-decoders/skia/BMPImageReader.cpp)363
-rw-r--r--WebCore/platform/image-decoders/bmp/BMPImageReader.h (renamed from WebCore/platform/image-decoders/skia/BMPImageReader.h)259
-rw-r--r--WebCore/platform/image-decoders/cairo/ImageDecoderCairo.cpp124
-rw-r--r--WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp146
-rw-r--r--WebCore/platform/image-decoders/gif/GIFImageDecoder.h19
-rw-r--r--WebCore/platform/image-decoders/gif/GIFImageReader.cpp21
-rw-r--r--WebCore/platform/image-decoders/haiku/ImageDecoderHaiku.cpp131
-rw-r--r--WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp355
-rw-r--r--WebCore/platform/image-decoders/ico/ICOImageDecoder.h151
-rw-r--r--WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp124
-rw-r--r--WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h13
-rw-r--r--WebCore/platform/image-decoders/png/PNGImageDecoder.cpp66
-rw-r--r--WebCore/platform/image-decoders/png/PNGImageDecoder.h6
-rw-r--r--WebCore/platform/image-decoders/skia/BMPImageDecoder.cpp82
-rw-r--r--WebCore/platform/image-decoders/skia/BMPImageDecoder.h54
-rw-r--r--WebCore/platform/image-decoders/skia/GIFImageDecoder.cpp493
-rw-r--r--WebCore/platform/image-decoders/skia/GIFImageDecoder.h93
-rw-r--r--WebCore/platform/image-decoders/skia/GIFImageReader.cpp951
-rw-r--r--WebCore/platform/image-decoders/skia/GIFImageReader.h215
-rw-r--r--WebCore/platform/image-decoders/skia/ICOImageDecoder.cpp230
-rw-r--r--WebCore/platform/image-decoders/skia/ICOImageDecoder.h118
-rw-r--r--WebCore/platform/image-decoders/skia/ImageDecoder.h307
-rw-r--r--WebCore/platform/image-decoders/skia/ImageDecoderSkia.cpp130
-rw-r--r--WebCore/platform/image-decoders/skia/JPEGImageDecoder.cpp512
-rw-r--r--WebCore/platform/image-decoders/skia/JPEGImageDecoder.h68
-rw-r--r--WebCore/platform/image-decoders/skia/PNGImageDecoder.cpp415
-rw-r--r--WebCore/platform/image-decoders/skia/PNGImageDecoder.h68
-rw-r--r--WebCore/platform/image-decoders/skia/XBMImageDecoder.cpp280
-rw-r--r--WebCore/platform/image-decoders/skia/XBMImageDecoder.h81
-rw-r--r--WebCore/platform/image-decoders/wx/ImageDecoderWx.cpp172
-rw-r--r--WebCore/platform/image-decoders/xbm/XBMImageDecoder.cpp290
-rw-r--r--WebCore/platform/image-decoders/xbm/XBMImageDecoder.h83
35 files changed, 2203 insertions, 4676 deletions
diff --git a/WebCore/platform/image-decoders/ImageDecoder.h b/WebCore/platform/image-decoders/ImageDecoder.h
index ca27b37..ffc7d9e 100644
--- a/WebCore/platform/image-decoders/ImageDecoder.h
+++ b/WebCore/platform/image-decoders/ImageDecoder.h
@@ -30,18 +30,22 @@
#include "ImageSource.h"
#include "PlatformString.h"
#include "SharedBuffer.h"
+#include <wtf/Assertions.h>
+#include <wtf/RefPtr.h>
#include <wtf/Vector.h>
-namespace WebCore {
+#if PLATFORM(SKIA)
+#include "NativeImageSkia.h"
+#include "SkBitmap.h"
+#endif
- typedef Vector<unsigned> RGBA32Array;
+namespace WebCore {
// 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.
@@ -50,46 +54,101 @@ namespace WebCore {
DisposeOverwriteBgcolor, // Clear frame to transparent
DisposeOverwritePrevious, // Clear frame to previous framebuffer contents
};
+#if PLATFORM(SKIA)
+ typedef uint32_t PixelData;
+#else
+ typedef unsigned PixelData;
+#endif
+
+ RGBA32Buffer();
+
+ // For backends which refcount their data, this constructor doesn't need
+ // to create a new copy of the image data, only increase the ref count.
+ //
+ // This exists because ImageDecoder keeps a Vector<RGBA32Buffer>, and
+ // Vector requires this constructor.
+ RGBA32Buffer(const RGBA32Buffer& other)
+ {
+ operator=(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.
+ void copyBitmapData(const RGBA32Buffer& other);
- RGBA32Buffer()
- : m_height(0)
- , m_status(FrameEmpty)
- , m_duration(0)
- , m_disposalMethod(DisposeNotSpecified)
- , m_hasAlpha(false)
+ // 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)
{
- }
-
- void clear() {
- m_bytes.clear();
- m_status = FrameEmpty;
- // NOTE: Do not reset other members here; clearFrameBufferCache() calls
- // this to free the bitmap data, but other functions like
- // initFrameBuffer() and frameComplete() may still need to read other
- // metadata out of this frame later.
+ 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);
}
- const RGBA32Array& bytes() const { return m_bytes; }
- RGBA32Array& bytes() { return m_bytes; }
+ // 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; }
- unsigned height() const { return m_height; }
FrameStatus status() const { return m_status; }
unsigned duration() const { return m_duration; }
FrameDisposalMethod disposalMethod() const { return m_disposalMethod; }
- bool hasAlpha() const { return m_hasAlpha; }
+ void setHasAlpha(bool alpha);
void setRect(const IntRect& r) { m_rect = r; }
- void ensureHeight(unsigned rowIndex) { if (rowIndex > m_height) m_height = rowIndex; }
- void setStatus(FrameStatus s) { m_status = s; }
+ void setStatus(FrameStatus status);
void setDuration(unsigned duration) { m_duration = duration; }
void setDisposalMethod(FrameDisposalMethod method) { m_disposalMethod = method; }
- void setHasAlpha(bool alpha) { m_hasAlpha = alpha; }
- static void setRGBA(unsigned& pos, unsigned r, unsigned g, unsigned b, unsigned a)
+ inline void setRGBA(int x, int y, unsigned r, unsigned g, unsigned b, unsigned a)
+ {
+ setRGBA(getAddr(x, y), r, g, b, a);
+ }
+
+ private:
+ RGBA32Buffer& operator=(const RGBA32Buffer& other);
+
+ int width() const;
+ int height() const;
+
+ inline PixelData* getAddr(int x, int y)
+ {
+#if PLATFORM(CAIRO) || PLATFORM(WX)
+ return m_bytes.data() + (y * width()) + x;
+#elif PLATFORM(SKIA)
+ return m_bitmap.getAddr32(x, y);
+#else
+ ASSERT_NOT_REACHED();
+ return 0;
+#endif
+ }
+
+ inline void setRGBA(PixelData* dest, unsigned r, unsigned g, unsigned b, unsigned a)
{
// We store this data pre-multiplied.
if (a == 0)
- pos = 0;
+ *dest = 0;
else {
if (a < 255) {
float alphaPercent = a / 255.0f;
@@ -97,20 +156,25 @@ namespace WebCore {
g = static_cast<unsigned>(g * alphaPercent);
b = static_cast<unsigned>(b * alphaPercent);
}
- pos = (a << 24 | r << 16 | g << 8 | b);
+ *dest = (a << 24 | r << 16 | g << 8 | b);
}
}
- private:
- RGBA32Array m_bytes;
- 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.
- unsigned m_height; // The height (the number of rows we've fully decoded).
+#if PLATFORM(CAIRO) || PLATFORM(WX)
+ Vector<PixelData> m_bytes;
+ 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.
+#elif PLATFORM(SKIA)
+ NativeImageSkia m_bitmap;
+#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_hasAlpha; // Whether or not any of the pixels in the buffer have transparency.
+ unsigned m_duration; // The animation delay.
+ FrameDisposalMethod m_disposalMethod;
+ // What to do with this frame's data when initializing the next frame.
};
// The ImageDecoder class represents a base class for specific image format decoders
@@ -119,11 +183,11 @@ namespace WebCore {
class ImageDecoder {
public:
ImageDecoder()
- : m_sizeAvailable(false)
- , m_failed(false)
+ : m_failed(false)
+ , m_sizeAvailable(false)
{
}
-
+
virtual ~ImageDecoder() {}
// The the filename extension usually associated with an undecoded image of this type.
@@ -132,16 +196,53 @@ namespace WebCore {
// All specific decoder plugins must do something with the data they are given.
virtual void setData(SharedBuffer* data, bool allDataReceived) { m_data = data; }
- // Whether or not the size information has been decoded yet.
- virtual bool isSizeAvailable() const = 0;
+ // 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
+ {
+ // Requesting the size of an invalid bitmap is meaningless.
+ ASSERT(!m_failed);
+ return m_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();
+ }
- // Requests the size.
- virtual IntSize size() const { return m_size; }
+ // Called by the image decoders to set their decoded size, this also check
+ // 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)) {
+ m_failed = true;
+ return false;
+ }
+ 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 int frameCount() { return 1; }
+ virtual size_t frameCount() { return 1; }
// The number of repetitions to perform for an animation loop.
virtual int repetitionCount() const { return cAnimationNone; }
@@ -149,7 +250,7 @@ namespace WebCore {
// 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 index) = 0;
+ virtual RGBA32Buffer* frameBufferAtIndex(size_t) = 0;
// Whether or not the underlying image format even supports alpha transparency.
virtual bool supportsAlpha() const { return true; }
@@ -168,9 +269,22 @@ namespace WebCore {
protected:
RefPtr<SharedBuffer> m_data; // The encoded data.
Vector<RGBA32Buffer> m_frameBufferCache;
- bool m_sizeAvailable;
- mutable bool m_failed;
+ bool m_failed;
+
+ 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;
};
} // namespace WebCore
diff --git a/WebCore/platform/image-decoders/bmp/BMPImageDecoder.cpp b/WebCore/platform/image-decoders/bmp/BMPImageDecoder.cpp
index 3b90bdc..de0690f 100644
--- a/WebCore/platform/image-decoders/bmp/BMPImageDecoder.cpp
+++ b/WebCore/platform/image-decoders/bmp/BMPImageDecoder.cpp
@@ -1,42 +1,148 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- *
+ * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
+ *
* 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
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
+
#include "config.h"
#include "BMPImageDecoder.h"
-namespace WebCore
+#include "BMPImageReader.h"
+
+namespace WebCore {
+
+// Number of bits in .BMP used to store the file header (doesn't match
+// "sizeof(BMPImageDecoder::BitmapFileHeader)" since we omit some fields and
+// don't pack).
+static const size_t sizeOfFileHeader = 14;
+
+BMPImageDecoder::BMPImageDecoder()
+ : ImageDecoder()
+ , m_allDataReceived(false)
+ , m_decodedOffset(0)
{
+}
-bool BMPImageDecoder::isSizeAvailable() const
+void BMPImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
{
- return false;
+ if (failed())
+ return;
+
+ ImageDecoder::setData(data, allDataReceived);
+ m_allDataReceived = allDataReceived;
+ if (m_reader)
+ m_reader->setData(data);
}
-
+
+bool BMPImageDecoder::isSizeAvailable()
+{
+ if (!ImageDecoder::isSizeAvailable() && !failed())
+ decodeWithCheckForDataEnded(true);
+
+ return ImageDecoder::isSizeAvailable();
+}
+
RGBA32Buffer* BMPImageDecoder::frameBufferAtIndex(size_t index)
{
- return 0;
+ if (index)
+ return 0;
+
+ if (m_frameBufferCache.isEmpty())
+ m_frameBufferCache.resize(1);
+
+ RGBA32Buffer* buffer = &m_frameBufferCache.first();
+ if (buffer->status() != RGBA32Buffer::FrameComplete && !failed())
+ decodeWithCheckForDataEnded(false);
+ return buffer;
+}
+
+void BMPImageDecoder::decodeWithCheckForDataEnded(bool onlySize)
+{
+ if (failed())
+ return;
+
+ // If we couldn't decode the image but we've received all the data, decoding
+ // has failed.
+ if (!decode(onlySize) && m_allDataReceived)
+ setFailed();
+}
+
+bool BMPImageDecoder::decode(bool onlySize)
+{
+ size_t imgDataOffset = 0;
+ if ((m_decodedOffset < sizeOfFileHeader)
+ && !processFileHeader(&imgDataOffset))
+ return false;
+
+ if (!m_reader) {
+ m_reader.set(new BMPImageReader(this, m_decodedOffset, imgDataOffset,
+ false));
+ m_reader->setData(m_data.get());
+ }
+
+ if (!m_frameBufferCache.isEmpty())
+ m_reader->setBuffer(&m_frameBufferCache.first());
+
+ return m_reader->decodeBMP(onlySize);
+}
+
+bool BMPImageDecoder::processFileHeader(size_t* imgDataOffset)
+{
+ ASSERT(imgDataOffset);
+
+ // Read file header.
+ ASSERT(!m_decodedOffset);
+ if (m_data->size() < sizeOfFileHeader)
+ return false;
+ const uint16_t fileType =
+ (m_data->data()[0] << 8) | static_cast<uint8_t>(m_data->data()[1]);
+ *imgDataOffset = readUint32(10);
+ m_decodedOffset = sizeOfFileHeader;
+
+ // See if this is a bitmap filetype we understand.
+ enum {
+ BMAP = 0x424D, // "BM"
+ // The following additional OS/2 2.x header values (see
+ // http://www.fileformat.info/format/os2bmp/egff.htm ) aren't widely
+ // decoded, and are unlikely to be in much use.
+ /*
+ ICON = 0x4943, // "IC"
+ POINTER = 0x5054, // "PT"
+ COLORICON = 0x4349, // "CI"
+ COLORPOINTER = 0x4350, // "CP"
+ BITMAPARRAY = 0x4241, // "BA"
+ */
+ };
+ if (fileType != BMAP) {
+ setFailed();
+ return false;
+ }
+
+ return true;
}
} // namespace WebCore
diff --git a/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h b/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h
index a2d4b25..c793585 100644
--- a/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h
+++ b/WebCore/platform/image-decoders/bmp/BMPImageDecoder.h
@@ -1,46 +1,85 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- *
+ * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
+ *
* 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
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef BMPImageDecoder_h
#define BMPImageDecoder_h
-#include "ImageDecoder.h"
+#include "BMPImageReader.h"
+#include <wtf/OwnPtr.h>
namespace WebCore {
- class BMPImageReader;
-
// This class decodes the BMP image format.
class BMPImageDecoder : public ImageDecoder {
public:
+ BMPImageDecoder();
+
+ // ImageDecoder
virtual String filenameExtension() const { return "bmp"; }
+ virtual void setData(SharedBuffer*, bool allDataReceived);
+ virtual bool isSizeAvailable();
+ virtual RGBA32Buffer* frameBufferAtIndex(size_t index);
- // Whether or not the size information has been decoded yet.
- virtual bool isSizeAvailable() const;
+ private:
+ inline uint32_t readUint32(int offset) const
+ {
+ return BMPImageReader::readUint32(m_data.get(),
+ m_decodedOffset + offset);
+ }
- virtual RGBA32Buffer* frameBufferAtIndex(size_t index);
+ // Decodes the image. If |onlySize| is true, stops decoding after
+ // calculating the image size. If decoding fails but there is no more
+ // data coming, sets the "decode failure" flag.
+ void decodeWithCheckForDataEnded(bool onlySize);
+
+ // Decodes the image. If |onlySize| is true, stops decoding after
+ // calculating the image size. Returns whether decoding succeeded.
+ // NOTE: Used internally by decodeWithCheckForDataEnded(). Other people
+ // should not call this.
+ bool decode(bool onlySize);
+
+ // Processes the file header at the beginning of the data. Sets
+ // |*imgDataOffset| based on the header contents. Returns true if the
+ // file header could be decoded.
+ bool processFileHeader(size_t* imgDataOffset);
+
+ // True if we've seen all the data.
+ bool m_allDataReceived;
+
+ // An index into |m_data| representing how much we've already decoded.
+ // Note that this only tracks data _this_ class decodes; once the
+ // BMPImageReader takes over this will not be updated further.
+ size_t m_decodedOffset;
+
+ // The reader used to do most of the BMP decoding.
+ OwnPtr<BMPImageReader> m_reader;
};
} // namespace WebCore
diff --git a/WebCore/platform/image-decoders/skia/BMPImageReader.cpp b/WebCore/platform/image-decoders/bmp/BMPImageReader.cpp
index 829b107..1936d81 100644
--- a/WebCore/platform/image-decoders/skia/BMPImageReader.cpp
+++ b/WebCore/platform/image-decoders/bmp/BMPImageReader.cpp
@@ -33,11 +33,15 @@
namespace WebCore {
-BMPImageReader::BMPImageReader()
- : m_decodedOffset(0)
- , m_headerOffset(0)
- , m_imgDataOffset(0)
- , m_andMaskState(None)
+BMPImageReader::BMPImageReader(ImageDecoder* parent,
+ size_t decodedAndHeaderOffset,
+ size_t imgDataOffset,
+ bool usesAndMask)
+ : m_parent(parent)
+ , m_buffer(0)
+ , m_decodedOffset(decodedAndHeaderOffset)
+ , m_headerOffset(decodedAndHeaderOffset)
+ , m_imgDataOffset(imgDataOffset)
, m_isOS21x(false)
, m_isOS22x(false)
, m_isTopDown(false)
@@ -46,88 +50,52 @@ BMPImageReader::BMPImageReader()
, m_tableSizeInBytes(0)
, m_seenNonZeroAlphaPixel(false)
, m_seenZeroAlphaPixel(false)
+ , m_andMaskState(usesAndMask ? NotYetDecoded : None)
{
- m_frameBufferCache.resize(1);
-
// Clue-in decodeBMP() that we need to detect the correct info header size.
memset(&m_infoHeader, 0, sizeof(m_infoHeader));
}
-void BMPImageReader::setData(SharedBuffer* data, bool allDataReceived)
-{
- ImageDecoder::setData(data, allDataReceived);
-
- // NOTE: This function intentionally uses frameBufferAtIndex() instead of
- // checking m_frameBufferCache.first() directly, so that it will do the
- // right thing for ICOImageDecoder, which needs to override this accessor
- // to support ICOs which contain PNGs.
-
- // Return quickly when we can't do any more work.
- if (m_failed || data->isEmpty()
- || (frameBufferAtIndex(0)->status() == RGBA32Buffer::FrameComplete))
- return;
-
- // Decode as much as we can. This assumes |data| starts at the beginning
- // of the image data, rather than containing just the latest chunk.
- decodeImage(data);
- if (m_failed) {
- // Handle failure before getting the framebuffer below.
- m_colorTable.clear();
- return;
- }
-
- // If we got all the data but couldn't finish decoding, fail.
- const bool finished =
- (frameBufferAtIndex(0)->status() == RGBA32Buffer::FrameComplete);
- if (allDataReceived && !finished)
- m_failed = true;
-
- // Release the color table when we no longer need it.
- if (finished || m_failed)
- m_colorTable.clear();
-}
-
-RGBA32Buffer* BMPImageReader::frameBufferAtIndex(size_t index)
-{
- return index ? 0 : &m_frameBufferCache.first();
-}
-
-void BMPImageReader::decodeBMP(SharedBuffer* data)
+bool BMPImageReader::decodeBMP(bool onlySize)
{
// Calculate size of info header.
- if (!m_infoHeader.biSize && !getInfoHeaderSize(data))
- return;
+ if (!m_infoHeader.biSize && !readInfoHeaderSize())
+ return false;
// Read and process info header.
if ((m_decodedOffset < (m_headerOffset + m_infoHeader.biSize))
- && !processInfoHeader(data))
- return;
+ && !processInfoHeader())
+ return false;
+
+ // processInfoHeader() set the size, so if that's all we needed, we're done.
+ if (onlySize)
+ return true;
// Read and process the bitmasks, if needed.
- if (m_needToProcessBitmasks && !processBitmasks(data))
- return;
+ if (m_needToProcessBitmasks && !processBitmasks())
+ return false;
// Read and process the color table, if needed.
- if (m_needToProcessColorTable && !processColorTable(data))
- return;
-
- // Initialize frame buffer state, if needed.
- if (m_frameBufferCache.first().status() == RGBA32Buffer::FrameEmpty) {
- m_frameBufferCache.first().setRect(IntRect(IntPoint(), size()));
- m_frameBufferCache.first().setStatus(RGBA32Buffer::FramePartial);
- if (!m_frameBufferCache.first().setSize(m_infoHeader.biWidth,
- m_infoHeader.biHeight)) {
- // Unable to allocate.
- m_failed = true;
- return;
- }
+ if (m_needToProcessColorTable && !processColorTable())
+ return false;
+ // Initialize the framebuffer if needed.
+ ASSERT(m_buffer); // Parent should set this before asking us to decode!
+ if (m_buffer->status() == RGBA32Buffer::FrameEmpty) {
+ if (!m_buffer->setSize(m_parent->size().width(),
+ m_parent->size().height()))
+ return setFailed(); // Unable to allocate.
+ m_buffer->setStatus(RGBA32Buffer::FramePartial);
// setSize() calls eraseARGB(), which resets the alpha flag, so we force
// it back to false here. We'll set it true below in all cases where
// these 0s could actually show through.
- m_frameBufferCache.first().setHasAlpha(false);
+ m_buffer->setHasAlpha(false);
+
+ // For BMPs, the frame always fills the entire image.
+ m_buffer->setRect(IntRect(IntPoint(), m_parent->size()));
+
if (!m_isTopDown)
- m_coord.setY(size().height() - 1);
+ m_coord.setY(m_parent->size().height() - 1);
}
// Decode the data.
@@ -135,40 +103,40 @@ void BMPImageReader::decodeBMP(SharedBuffer* data)
if ((m_infoHeader.biCompression == RLE4)
|| (m_infoHeader.biCompression == RLE8)
|| (m_infoHeader.biCompression == RLE24)) {
- if (!processRLEData(data))
- return;
- } else if (!processNonRLEData(data, false, 0))
- return;
+ if (!processRLEData())
+ return false;
+ } else if (!processNonRLEData(false, 0))
+ return false;
}
// If the image has an AND mask and there was no alpha data, process the
// mask.
- if ((m_andMaskState == NotYetDecoded)
- && !m_frameBufferCache.first().hasAlpha()) {
+ if ((m_andMaskState == NotYetDecoded) && !m_buffer->hasAlpha()) {
// Reset decoding coordinates to start of image.
m_coord.setX(0);
- m_coord.setY(m_isTopDown ? 0 : (size().height() - 1));
+ m_coord.setY(m_isTopDown ? 0 : (m_parent->size().height() - 1));
// The AND mask is stored as 1-bit data.
m_infoHeader.biBitCount = 1;
m_andMaskState = Decoding;
}
- if ((m_andMaskState == Decoding) && !processNonRLEData(data, false, 0))
- return;
+ if ((m_andMaskState == Decoding) && !processNonRLEData(false, 0))
+ return false;
// Done!
- m_frameBufferCache.first().setStatus(RGBA32Buffer::FrameComplete);
+ m_buffer->setStatus(RGBA32Buffer::FrameComplete);
+ return true;
}
-bool BMPImageReader::getInfoHeaderSize(SharedBuffer* data)
+bool BMPImageReader::readInfoHeaderSize()
{
// Get size of info header.
ASSERT(m_decodedOffset == m_headerOffset);
- if ((m_decodedOffset > data->size())
- || ((data->size() - m_decodedOffset) < 4))
+ if ((m_decodedOffset > m_data->size())
+ || ((m_data->size() - m_decodedOffset) < 4))
return false;
- m_infoHeader.biSize = readUint32(data, 0);
+ m_infoHeader.biSize = readUint32(0);
// Don't increment m_decodedOffset here, it just makes the code in
// processInfoHeader() more confusing.
@@ -177,10 +145,8 @@ bool BMPImageReader::getInfoHeaderSize(SharedBuffer* data)
// image data.
if (((m_headerOffset + m_infoHeader.biSize) < m_headerOffset)
|| (m_imgDataOffset
- && (m_imgDataOffset < (m_headerOffset + m_infoHeader.biSize)))) {
- m_failed = true;
- return false;
- }
+ && (m_imgDataOffset < (m_headerOffset + m_infoHeader.biSize))))
+ return setFailed();
// See if this is a header size we understand:
// OS/2 1.x: 12
@@ -195,32 +161,28 @@ bool BMPImageReader::getInfoHeaderSize(SharedBuffer* data)
|| (m_infoHeader.biSize == 46)))
m_isOS22x = true;
else
- m_failed = true;
+ return setFailed();
- return !m_failed;
+ return true;
}
-bool BMPImageReader::processInfoHeader(SharedBuffer* data)
+bool BMPImageReader::processInfoHeader()
{
// Read info header.
ASSERT(m_decodedOffset == m_headerOffset);
- if ((m_decodedOffset > data->size())
- || ((data->size() - m_decodedOffset) < m_infoHeader.biSize)
- || !readInfoHeader(data))
+ if ((m_decodedOffset > m_data->size())
+ || ((m_data->size() - m_decodedOffset) < m_infoHeader.biSize)
+ || !readInfoHeader())
return false;
m_decodedOffset += m_infoHeader.biSize;
// Sanity-check header values.
- if (!isInfoHeaderValid()) {
- m_failed = true;
- return false;
- }
+ if (!isInfoHeaderValid())
+ return setFailed();
- // Make our size available to the caller.
- if (!setSize(m_infoHeader.biWidth, m_infoHeader.biHeight)) {
- m_failed = true;
- return false;
- }
+ // Set our size.
+ if (!m_parent->setSize(m_infoHeader.biWidth, m_infoHeader.biHeight))
+ return setFailed();
// For paletted images, bitmaps can set biClrUsed to 0 to mean "all
// colors", so set it to the maximum number of colors for this bit depth.
@@ -250,29 +212,29 @@ bool BMPImageReader::processInfoHeader(SharedBuffer* data)
return true;
}
-bool BMPImageReader::readInfoHeader(SharedBuffer* data)
+bool BMPImageReader::readInfoHeader()
{
// Pre-initialize some fields that not all headers set.
m_infoHeader.biCompression = RGB;
m_infoHeader.biClrUsed = 0;
if (m_isOS21x) {
- m_infoHeader.biWidth = readUint16(data, 4);
- m_infoHeader.biHeight = readUint16(data, 6);
+ m_infoHeader.biWidth = readUint16(4);
+ m_infoHeader.biHeight = readUint16(6);
ASSERT(m_andMaskState == None); // ICO is a Windows format, not OS/2!
- m_infoHeader.biBitCount = readUint16(data, 10);
+ m_infoHeader.biBitCount = readUint16(10);
return true;
}
- m_infoHeader.biWidth = readUint32(data, 4);
- m_infoHeader.biHeight = readUint32(data, 8);
+ m_infoHeader.biWidth = readUint32(4);
+ m_infoHeader.biHeight = readUint32(8);
if (m_andMaskState != None)
m_infoHeader.biHeight /= 2;
- m_infoHeader.biBitCount = readUint16(data, 14);
+ m_infoHeader.biBitCount = readUint16(14);
// Read compression type, if present.
if (m_infoHeader.biSize >= 20) {
- uint32_t biCompression = readUint32(data, 16);
+ uint32_t biCompression = readUint32(16);
// Detect OS/2 2.x-specific compression types.
if ((biCompression == 3) && (m_infoHeader.biBitCount == 1)) {
@@ -281,17 +243,16 @@ bool BMPImageReader::readInfoHeader(SharedBuffer* data)
} else if ((biCompression == 4) && (m_infoHeader.biBitCount == 24)) {
m_infoHeader.biCompression = RLE24;
m_isOS22x = true;
- } else if (biCompression > 5) {
- // Some type we don't understand.
- m_failed = true;
- return false;
- } else
- m_infoHeader.biCompression = static_cast<CompressionType>(biCompression);
+ } else if (biCompression > 5)
+ return setFailed(); // Some type we don't understand.
+ else
+ m_infoHeader.biCompression =
+ static_cast<CompressionType>(biCompression);
}
// Read colors used, if present.
if (m_infoHeader.biSize >= 36)
- m_infoHeader.biClrUsed = readUint32(data, 32);
+ m_infoHeader.biClrUsed = readUint32(32);
// Windows V4+ can safely read the four bitmasks from 40-56 bytes in, so do
// that here. If the bit depth is less than 16, these values will be
@@ -308,10 +269,10 @@ bool BMPImageReader::readInfoHeader(SharedBuffer* data)
// to pay attention to the alpha mask here, so there's a special case in
// processBitmasks() that doesn't always overwrite that value.
if (isWindowsV4Plus()) {
- m_bitMasks[0] = readUint32(data, 40);
- m_bitMasks[1] = readUint32(data, 44);
- m_bitMasks[2] = readUint32(data, 48);
- m_bitMasks[3] = readUint32(data, 52);
+ m_bitMasks[0] = readUint32(40);
+ m_bitMasks[1] = readUint32(44);
+ m_bitMasks[2] = readUint32(48);
+ m_bitMasks[3] = readUint32(52);
}
// Detect top-down BMPs.
@@ -441,7 +402,7 @@ bool BMPImageReader::isInfoHeaderValid() const
return true;
}
-bool BMPImageReader::processBitmasks(SharedBuffer* data)
+bool BMPImageReader::processBitmasks()
{
// Create m_bitMasks[] values.
if (m_infoHeader.biCompression != BITFIELDS) {
@@ -469,19 +430,19 @@ bool BMPImageReader::processBitmasks(SharedBuffer* data)
// we read the info header.
// Fail if we don't have enough file space for the bitmasks.
- static const int SIZEOF_BITMASKS = 12;
- if (((m_headerOffset + m_infoHeader.biSize + SIZEOF_BITMASKS) < (m_headerOffset + m_infoHeader.biSize))
- || (m_imgDataOffset && (m_imgDataOffset < (m_headerOffset + m_infoHeader.biSize + SIZEOF_BITMASKS)))) {
- m_failed = true;
- return false;
- }
+ static const size_t SIZEOF_BITMASKS = 12;
+ if (((m_headerOffset + m_infoHeader.biSize + SIZEOF_BITMASKS) <
+ (m_headerOffset + m_infoHeader.biSize))
+ || (m_imgDataOffset && (m_imgDataOffset <
+ (m_headerOffset + m_infoHeader.biSize + SIZEOF_BITMASKS))))
+ return setFailed();
// Read bitmasks.
- if ((data->size() - m_decodedOffset) < SIZEOF_BITMASKS)
+ if ((m_data->size() - m_decodedOffset) < SIZEOF_BITMASKS)
return false;
- m_bitMasks[0] = readUint32(data, 0);
- m_bitMasks[1] = readUint32(data, 4);
- m_bitMasks[2] = readUint32(data, 8);
+ m_bitMasks[0] = readUint32(0);
+ m_bitMasks[1] = readUint32(4);
+ m_bitMasks[2] = readUint32(8);
// No alpha in anything other than Windows V4+.
m_bitMasks[3] = 0;
@@ -500,7 +461,8 @@ bool BMPImageReader::processBitmasks(SharedBuffer* data)
// specify a bogus alpha channel in bits that don't exist in the pixel
// data (for example, bits 25-31 in a 24-bit RGB format).
if (m_infoHeader.biBitCount < 32)
- m_bitMasks[i] &= ((static_cast<uint32_t>(1) << m_infoHeader.biBitCount) - 1);
+ m_bitMasks[i] &=
+ ((static_cast<uint32_t>(1) << m_infoHeader.biBitCount) - 1);
// For empty masks (common on the alpha channel, especially after the
// trimming above), quickly clear the shifts and continue, to avoid an
@@ -513,10 +475,8 @@ bool BMPImageReader::processBitmasks(SharedBuffer* data)
// Make sure bitmask does not overlap any other bitmasks.
for (int j = 0; j < i; ++j) {
- if (tempMask & m_bitMasks[j]) {
- m_failed = true;
- return false;
- }
+ if (tempMask & m_bitMasks[j])
+ return setFailed();
}
// Count offset into pixel data.
@@ -528,10 +488,8 @@ bool BMPImageReader::processBitmasks(SharedBuffer* data)
--m_bitShiftsLeft[i];
// Make sure bitmask is contiguous.
- if (tempMask) {
- m_failed = true;
- return false;
- }
+ if (tempMask)
+ return setFailed();
// Since RGBABuffer tops out at 8 bits per channel, adjust the shift
// amounts to use the most significant 8 bits of the channel.
@@ -544,26 +502,26 @@ bool BMPImageReader::processBitmasks(SharedBuffer* data)
return true;
}
-bool BMPImageReader::processColorTable(SharedBuffer* data)
+bool BMPImageReader::processColorTable()
{
m_tableSizeInBytes = m_infoHeader.biClrUsed * (m_isOS21x ? 3 : 4);
// Fail if we don't have enough file space for the color table.
- if (((m_headerOffset + m_infoHeader.biSize + m_tableSizeInBytes) < (m_headerOffset + m_infoHeader.biSize))
- || (m_imgDataOffset && (m_imgDataOffset < (m_headerOffset + m_infoHeader.biSize + m_tableSizeInBytes)))) {
- m_failed = true;
- return false;
- }
+ if (((m_headerOffset + m_infoHeader.biSize + m_tableSizeInBytes) <
+ (m_headerOffset + m_infoHeader.biSize))
+ || (m_imgDataOffset && (m_imgDataOffset <
+ (m_headerOffset + m_infoHeader.biSize + m_tableSizeInBytes))))
+ return setFailed();
// Read color table.
- if ((m_decodedOffset > data->size())
- || ((data->size() - m_decodedOffset) < m_tableSizeInBytes))
+ if ((m_decodedOffset > m_data->size())
+ || ((m_data->size() - m_decodedOffset) < m_tableSizeInBytes))
return false;
m_colorTable.resize(m_infoHeader.biClrUsed);
for (size_t i = 0; i < m_infoHeader.biClrUsed; ++i) {
- m_colorTable[i].rgbBlue = data->data()[m_decodedOffset++];
- m_colorTable[i].rgbGreen = data->data()[m_decodedOffset++];
- m_colorTable[i].rgbRed = data->data()[m_decodedOffset++];
+ m_colorTable[i].rgbBlue = m_data->data()[m_decodedOffset++];
+ m_colorTable[i].rgbGreen = m_data->data()[m_decodedOffset++];
+ m_colorTable[i].rgbRed = m_data->data()[m_decodedOffset++];
// Skip padding byte (not present on OS/2 1.x).
if (!m_isOS21x)
++m_decodedOffset;
@@ -578,9 +536,9 @@ bool BMPImageReader::processColorTable(SharedBuffer* data)
return true;
}
-bool BMPImageReader::processRLEData(SharedBuffer* data)
+bool BMPImageReader::processRLEData()
{
- if (m_decodedOffset > data->size())
+ if (m_decodedOffset > m_data->size())
return false;
// RLE decoding is poorly specified. Two main problems:
@@ -608,25 +566,23 @@ bool BMPImageReader::processRLEData(SharedBuffer* data)
while (true) {
// Every entry takes at least two bytes; bail if there isn't enough
// data.
- if ((data->size() - m_decodedOffset) < 2)
+ if ((m_data->size() - m_decodedOffset) < 2)
return false;
// For every entry except EOF, we'd better not have reached the end of
// the image.
- const uint8_t count = data->data()[m_decodedOffset];
- const uint8_t code = data->data()[m_decodedOffset + 1];
- if (((count != 0) || (code != 1)) && pastEndOfImage(0)) {
- m_failed = true;
- return false;
- }
+ const uint8_t count = m_data->data()[m_decodedOffset];
+ const uint8_t code = m_data->data()[m_decodedOffset + 1];
+ if (((count != 0) || (code != 1)) && pastEndOfImage(0))
+ return setFailed();
// Decode.
if (count == 0) {
switch (code) {
case 0: // Magic token: EOL
// Skip any remaining pixels in this row.
- if (m_coord.x() < size().width())
- m_frameBufferCache.first().setHasAlpha(true);
+ if (m_coord.x() < m_parent->size().width())
+ m_buffer->setHasAlpha(true);
moveBufferToNextRow();
m_decodedOffset += 2;
@@ -634,28 +590,28 @@ bool BMPImageReader::processRLEData(SharedBuffer* data)
case 1: // Magic token: EOF
// Skip any remaining pixels in the image.
- if ((m_coord.x() < size().width())
- || (m_isTopDown ? (m_coord.y() < (size().height() - 1)) : (m_coord.y() > 0)))
- m_frameBufferCache.first().setHasAlpha(true);
+ if ((m_coord.x() < m_parent->size().width())
+ || (m_isTopDown
+ ? (m_coord.y() < (m_parent->size().height() - 1))
+ : (m_coord.y() > 0)))
+ m_buffer->setHasAlpha(true);
return true;
case 2: { // Magic token: Delta
// The next two bytes specify dx and dy. Bail if there isn't
// enough data.
- if ((data->size() - m_decodedOffset) < 4)
+ if ((m_data->size() - m_decodedOffset) < 4)
return false;
// Fail if this takes us past the end of the desired row or
// past the end of the image.
- const uint8_t dx = data->data()[m_decodedOffset + 2];
- const uint8_t dy = data->data()[m_decodedOffset + 3];
+ const uint8_t dx = m_data->data()[m_decodedOffset + 2];
+ const uint8_t dy = m_data->data()[m_decodedOffset + 3];
if ((dx != 0) || (dy != 0))
- m_frameBufferCache.first().setHasAlpha(true);
- if (((m_coord.x() + dx) > size().width()) ||
- pastEndOfImage(dy)) {
- m_failed = true;
- return false;
- }
+ m_buffer->setHasAlpha(true);
+ if (((m_coord.x() + dx) > m_parent->size().width()) ||
+ pastEndOfImage(dy))
+ return setFailed();
// Skip intervening pixels.
m_coord.move(dx, m_isTopDown ? dy : -dy);
@@ -671,7 +627,7 @@ bool BMPImageReader::processRLEData(SharedBuffer* data)
// point to the beginning of the pixel data, bump it past
// the escape bytes and then reset if decoding failed.
m_decodedOffset += 2;
- if (!processNonRLEData(data, true, code)) {
+ if (!processNonRLEData(true, code)) {
m_decodedOffset -= 2;
return false;
}
@@ -681,16 +637,17 @@ bool BMPImageReader::processRLEData(SharedBuffer* data)
// The following color data is repeated for |count| total pixels.
// Strangely, some BMPs seem to specify excessively large counts
// here; ignore pixels past the end of the row.
- const int endX = std::min(m_coord.x() + count, size().width());
+ const int endX =
+ std::min(m_coord.x() + count, m_parent->size().width());
if (m_infoHeader.biCompression == RLE24) {
// Bail if there isn't enough data.
- if ((data->size() - m_decodedOffset) < 4)
+ if ((m_data->size() - m_decodedOffset) < 4)
return false;
// One BGR triple that we copy |count| times.
- fillRGBA(endX, data->data()[m_decodedOffset + 3],
- data->data()[m_decodedOffset + 2], code, 0xff);
+ fillRGBA(endX, m_data->data()[m_decodedOffset + 3],
+ m_data->data()[m_decodedOffset + 2], code, 0xff);
m_decodedOffset += 4;
} else {
// RLE8 has one color index that gets repeated; RLE4 has two
@@ -702,10 +659,8 @@ bool BMPImageReader::processRLEData(SharedBuffer* data)
colorIndexes[1] &= 0xf;
}
if ((colorIndexes[0] >= m_infoHeader.biClrUsed)
- || (colorIndexes[1] >= m_infoHeader.biClrUsed)) {
- m_failed = true;
- return false;
- }
+ || (colorIndexes[1] >= m_infoHeader.biClrUsed))
+ return setFailed();
for (int which = 0; m_coord.x() < endX; ) {
setI(colorIndexes[which]);
which = !which;
@@ -717,20 +672,18 @@ bool BMPImageReader::processRLEData(SharedBuffer* data)
}
}
-bool BMPImageReader::processNonRLEData(SharedBuffer* data, bool inRLE, int numPixels)
+bool BMPImageReader::processNonRLEData(bool inRLE, int numPixels)
{
- if (m_decodedOffset > data->size())
+ if (m_decodedOffset > m_data->size())
return false;
if (!inRLE)
- numPixels = size().width();
+ numPixels = m_parent->size().width();
// Fail if we're being asked to decode more pixels than remain in the row.
const int endX = m_coord.x() + numPixels;
- if (endX > size().width()) {
- m_failed = true;
- return false;
- }
+ if (endX > m_parent->size().width())
+ return setFailed();
// Determine how many bytes of data the requested number of pixels
// requires.
@@ -748,7 +701,7 @@ bool BMPImageReader::processNonRLEData(SharedBuffer* data, bool inRLE, int numPi
// one row, we've already checked that this condition is true.)
while (!pastEndOfImage(0)) {
// Bail if we don't have enough data for the desired number of pixels.
- if ((data->size() - m_decodedOffset) < paddedNumBytes)
+ if ((m_data->size() - m_decodedOffset) < paddedNumBytes)
return false;
if (m_infoHeader.biBitCount < 16) {
@@ -757,8 +710,9 @@ bool BMPImageReader::processNonRLEData(SharedBuffer* data, bool inRLE, int numPi
// the most significant bits in the byte).
const uint8_t mask = (1 << m_infoHeader.biBitCount) - 1;
for (size_t byte = 0; byte < unpaddedNumBytes; ++byte) {
- uint8_t pixelData = data->data()[m_decodedOffset + byte];
- for (size_t pixel = 0; (pixel < pixelsPerByte) && (m_coord.x() < endX); ++pixel) {
+ uint8_t pixelData = m_data->data()[m_decodedOffset + byte];
+ for (size_t pixel = 0;
+ (pixel < pixelsPerByte) && (m_coord.x() < endX); ++pixel) {
const size_t colorIndex =
(pixelData >> (8 - m_infoHeader.biBitCount)) & mask;
if (m_andMaskState == Decoding) {
@@ -769,14 +723,12 @@ bool BMPImageReader::processNonRLEData(SharedBuffer* data, bool inRLE, int numPi
// web will not be doing a lot of inverting.
if (colorIndex) {
setRGBA(0, 0, 0, 0);
- m_frameBufferCache.first().setHasAlpha(true);
+ m_buffer->setHasAlpha(true);
} else
m_coord.move(1, 0);
} else {
- if (colorIndex >= m_infoHeader.biClrUsed) {
- m_failed = true;
- return false;
- }
+ if (colorIndex >= m_infoHeader.biClrUsed)
+ return setFailed();
setI(colorIndex);
}
pixelData <<= m_infoHeader.biBitCount;
@@ -785,7 +737,7 @@ bool BMPImageReader::processNonRLEData(SharedBuffer* data, bool inRLE, int numPi
} else {
// RGB data. Decode pixels one at a time, left to right.
while (m_coord.x() < endX) {
- const uint32_t pixel = readCurrentPixel(data, bytesPerPixel);
+ const uint32_t pixel = readCurrentPixel(bytesPerPixel);
// Some BMPs specify an alpha channel but don't actually use it
// (it contains all 0s). To avoid displaying these images as
@@ -803,12 +755,10 @@ bool BMPImageReader::processNonRLEData(SharedBuffer* data, bool inRLE, int numPi
} else {
m_seenNonZeroAlphaPixel = true;
if (m_seenZeroAlphaPixel) {
- // The eraseARGB() call here also sets "hasAlpha" true.
- m_frameBufferCache.first().bitmap().eraseARGB(0, 0, 0,
- 0);
+ m_buffer->zeroFill();
m_seenZeroAlphaPixel = false;
} else if (alpha != 255)
- m_frameBufferCache.first().setHasAlpha(true);
+ m_buffer->setHasAlpha(true);
}
setRGBA(getComponent(pixel, 0), getComponent(pixel, 1),
@@ -832,4 +782,11 @@ void BMPImageReader::moveBufferToNextRow()
m_coord.move(-m_coord.x(), m_isTopDown ? 1 : -1);
}
+bool BMPImageReader::setFailed()
+{
+ m_parent->setFailed();
+ m_colorTable.clear();
+ return false;
+}
+
} // namespace WebCore
diff --git a/WebCore/platform/image-decoders/skia/BMPImageReader.h b/WebCore/platform/image-decoders/bmp/BMPImageReader.h
index 0edf7b0..1271172 100644
--- a/WebCore/platform/image-decoders/skia/BMPImageReader.h
+++ b/WebCore/platform/image-decoders/bmp/BMPImageReader.h
@@ -36,46 +36,26 @@
namespace WebCore {
- // This class decodes a BMP image. It is used as a base for the BMP and ICO
- // decoders, which wrap it in the appropriate code to read file headers, etc.
- class BMPImageReader : public ImageDecoder {
+ // This class decodes a BMP image. It is used in the BMP and ICO decoders,
+ // which wrap it in the appropriate code to read file headers, etc.
+ class BMPImageReader {
public:
- BMPImageReader();
-
- // Does the actual decoding. |data| starts at the beginning of the file,
- // but may be incomplete.
- virtual void decodeImage(SharedBuffer* data) = 0;
-
- // ImageDecoder
- virtual void setData(SharedBuffer* data, bool allDataReceived);
- virtual RGBA32Buffer* frameBufferAtIndex(size_t index);
-
- protected:
- enum AndMaskState {
- None,
- NotYetDecoded,
- Decoding,
- };
-
- // Decodes a single BMP, starting with an info header.
- void decodeBMP(SharedBuffer* data);
-
- // Read a value from |data[m_decodedOffset + additionalOffset]|, converting
- // from little to native endianness.
- inline uint16_t readUint16(SharedBuffer* data, int additionalOffset) const
+ // Read a value from |data[offset]|, converting from little to native
+ // endianness.
+ static inline uint16_t readUint16(SharedBuffer* data, int offset)
{
uint16_t result;
- memcpy(&result, &data->data()[m_decodedOffset + additionalOffset], 2);
+ memcpy(&result, &data->data()[offset], 2);
#if PLATFORM(BIG_ENDIAN)
result = ((result & 0xff) << 8) | ((result & 0xff00) >> 8);
#endif
return result;
}
- inline uint32_t readUint32(SharedBuffer* data, int additionalOffset) const
+ static inline uint32_t readUint32(SharedBuffer* data, int offset)
{
uint32_t result;
- memcpy(&result, &data->data()[m_decodedOffset + additionalOffset], 4);
+ memcpy(&result, &data->data()[offset], 4);
#if PLATFORM(BIG_ENDIAN)
result = ((result & 0xff) << 24) | ((result & 0xff00) << 8) |
((result & 0xff0000) >> 8) | ((result & 0xff000000) >> 24);
@@ -83,26 +63,26 @@ namespace WebCore {
return result;
}
- // An index into |m_data| representing how much we've already decoded.
- size_t m_decodedOffset;
-
- // The file offset at which the BMP info header starts.
- size_t m_headerOffset;
+ // |parent| is the decoder that owns us.
+ // |startOffset| points to the start of the BMP within the file.
+ // |buffer| points at an empty RGBA32Buffer that we'll initialize and
+ // fill with decoded data.
+ BMPImageReader(ImageDecoder* parent,
+ size_t decodedAndHeaderOffset,
+ size_t imgDataOffset,
+ bool usesAndMask);
- // The file offset at which the actual image bits start. When decoding ICO
- // files, this is set to 0, since it's not stored anywhere in a header; the
- // reader functions expect the image data to start immediately after the
- // header and (if necessary) color table.
- size_t m_imgDataOffset;
+ void setBuffer(RGBA32Buffer* buffer) { m_buffer = buffer; }
+ void setData(SharedBuffer* data) { m_data = data; }
- // ICOs store a 1bpp "mask" immediately after the main bitmap image data
- // (and, confusingly, add its height to the biHeight value in the info
- // header, thus doubling it). This variable tracks whether we have such a
- // mask and if we've started decoding it yet.
- AndMaskState m_andMaskState;
+ // Does the actual decoding. If |onlySize| is true, decoding only
+ // progresses as far as necessary to get the image size. Returns
+ // whether decoding succeeded.
+ bool decodeBMP(bool onlySize);
private:
- // The various BMP compression types. We don't currently decode all these.
+ // The various BMP compression types. We don't currently decode all
+ // these.
enum CompressionType {
// Universal types
RGB = 0,
@@ -116,9 +96,14 @@ namespace WebCore {
HUFFMAN1D, // Stored in file as 3
RLE24, // Stored in file as 4
};
+ enum AndMaskState {
+ None,
+ NotYetDecoded,
+ Decoding,
+ };
- // These are based on the Windows BITMAPINFOHEADER and RGBTRIPLE structs,
- // but with unnecessary entries removed.
+ // These are based on the Windows BITMAPINFOHEADER and RGBTRIPLE
+ // structs, but with unnecessary entries removed.
struct BitmapInfoHeader {
uint32_t biSize;
int32_t biWidth;
@@ -133,17 +118,27 @@ namespace WebCore {
uint8_t rgbRed;
};
- // Determines the size of the BMP info header. Returns true if the size is
- // valid.
- bool getInfoHeaderSize(SharedBuffer* data);
+ inline uint16_t readUint16(int offset) const
+ {
+ return readUint16(m_data.get(), m_decodedOffset + offset);
+ }
- // Processes the BMP info header. Returns true if the info header could be
- // decoded.
- bool processInfoHeader(SharedBuffer* data);
+ inline uint32_t readUint32(int offset) const
+ {
+ return readUint32(m_data.get(), m_decodedOffset + offset);
+ }
+
+ // Determines the size of the BMP info header. Returns true if the size
+ // is valid.
+ bool readInfoHeaderSize();
- // Helper function for processInfoHeader() which does the actual reading of
- // header values from the byte stream. Returns false on error.
- bool readInfoHeader(SharedBuffer* data);
+ // Processes the BMP info header. Returns true if the info header could
+ // be decoded.
+ bool processInfoHeader();
+
+ // Helper function for processInfoHeader() which does the actual reading
+ // of header values from the byte stream. Returns false on error.
+ bool readInfoHeader();
// Returns true if this is a Windows V4+ BMP.
inline bool isWindowsV4Plus() const
@@ -155,57 +150,58 @@ namespace WebCore {
// Returns false if consistency errors are found in the info header.
bool isInfoHeaderValid() const;
- // For BI_BITFIELDS images, initializes the m_bitMasks[] and m_bitOffsets[]
- // arrays. processInfoHeader() will initialize these for other compression
- // types where needed.
- bool processBitmasks(SharedBuffer* data);
+ // For BI_BITFIELDS images, initializes the m_bitMasks[] and
+ // m_bitOffsets[] arrays. processInfoHeader() will initialize these for
+ // other compression types where needed.
+ bool processBitmasks();
- // For paletted images, allocates and initializes the m_colorTable[] array.
- bool processColorTable(SharedBuffer* data);
+ // For paletted images, allocates and initializes the m_colorTable[]
+ // array.
+ bool processColorTable();
// Processes an RLE-encoded image. Returns true if the entire image was
// decoded.
- bool processRLEData(SharedBuffer* data);
+ bool processRLEData();
// Processes a set of non-RLE-compressed pixels. Two cases:
// * inRLE = true: the data is inside an RLE-encoded bitmap. Tries to
// process |numPixels| pixels on the current row; returns true on
// success.
// * inRLE = false: the data is inside a non-RLE-encoded bitmap.
- // |numPixels| is ignored. Expects |m_coord| to point at the beginning
- // of the next row to be decoded. Tries to process as many complete
- // rows as possible. Returns true if the whole image was decoded.
- bool processNonRLEData(SharedBuffer* data, bool inRLE, int numPixels);
+ // |numPixels| is ignored. Expects |m_coord| to point at the
+ // beginning of the next row to be decoded. Tries to process as
+ // many complete rows as possible. Returns true if the whole image
+ // was decoded.
+ bool processNonRLEData(bool inRLE, int numPixels);
// Returns true if the current y-coordinate plus |numRows| would be past
- // the end of the image. Here "plus" means "toward the end of the image",
- // so downwards for m_isTopDown images and upwards otherwise.
+ // the end of the image. Here "plus" means "toward the end of the
+ // image", so downwards for m_isTopDown images and upwards otherwise.
inline bool pastEndOfImage(int numRows)
{
return m_isTopDown
- ? ((m_coord.y() + numRows) >= size().height())
+ ? ((m_coord.y() + numRows) >= m_parent->size().height())
: ((m_coord.y() - numRows) < 0);
}
// Returns the pixel data for the current X coordinate in a uint32_t.
// Assumes m_decodedOffset has been set to the beginning of the current
// row.
- // NOTE: Only as many bytes of the return value as are needed to hold the
- // pixel data will actually be set.
- inline uint32_t readCurrentPixel(SharedBuffer* data, int bytesPerPixel) const
+ // NOTE: Only as many bytes of the return value as are needed to hold
+ // the pixel data will actually be set.
+ inline uint32_t readCurrentPixel(int bytesPerPixel) const
{
- const int additionalOffset = m_coord.x() * bytesPerPixel;
+ const int offset = m_coord.x() * bytesPerPixel;
switch (bytesPerPixel) {
case 2:
- return readUint16(data, additionalOffset);
+ return readUint16(offset);
case 3: {
- // It doesn't matter that we never set the most significant byte of
- // the return value here in little-endian mode, the caller won't
- // read it.
+ // It doesn't matter that we never set the most significant byte
+ // of the return value here in little-endian mode, the caller
+ // won't read it.
uint32_t pixel;
- memcpy(&pixel,
- &data->data()[m_decodedOffset + additionalOffset], 3);
+ memcpy(&pixel, &m_data->data()[m_decodedOffset + offset], 3);
#if PLATFORM(BIG_ENDIAN)
pixel = ((pixel & 0xff00) << 8) | ((pixel & 0xff0000) >> 8) |
((pixel & 0xff000000) >> 24);
@@ -214,7 +210,7 @@ namespace WebCore {
}
case 4:
- return readUint32(data, additionalOffset);
+ return readUint32(offset);
default:
ASSERT_NOT_REACHED();
@@ -222,12 +218,12 @@ namespace WebCore {
}
}
- // Returns the value of the desired component (0, 1, 2, 3 == R, G, B, A) in
- // the given pixel data.
+ // Returns the value of the desired component (0, 1, 2, 3 == R, G, B, A)
+ // in the given pixel data.
inline unsigned getComponent(uint32_t pixel, int component) const
{
- return ((pixel & m_bitMasks[component]) >> m_bitShiftsRight[component])
- << m_bitShiftsLeft[component];
+ return ((pixel & m_bitMasks[component]) >>
+ m_bitShiftsRight[component]) << m_bitShiftsLeft[component];
}
inline unsigned getAlpha(uint32_t pixel) const
@@ -240,51 +236,84 @@ namespace WebCore {
}
// Sets the current pixel to the color given by |colorIndex|. This also
- // increments the relevant local variables to move the current pixel right
- // by one.
+ // increments the relevant local variables to move the current pixel
+ // right by one.
inline void setI(size_t colorIndex)
{
- setRGBA(m_colorTable[colorIndex].rgbRed, m_colorTable[colorIndex].rgbGreen,
+ setRGBA(m_colorTable[colorIndex].rgbRed,
+ m_colorTable[colorIndex].rgbGreen,
m_colorTable[colorIndex].rgbBlue, 0xff);
}
// Like setI(), but with the individual component values specified.
- inline void setRGBA(unsigned red, unsigned green, unsigned blue, unsigned alpha)
+ inline void setRGBA(unsigned red,
+ unsigned green,
+ unsigned blue,
+ unsigned alpha)
{
- RGBA32Buffer::setRGBA(
- m_frameBufferCache.first().bitmap().getAddr32(m_coord.x(), m_coord.y()),
- red, green, blue, alpha);
+ m_buffer->setRGBA(m_coord.x(), m_coord.y(), red, green, blue,
+ alpha);
m_coord.move(1, 0);
}
// Fills pixels from the current X-coordinate up to, but not including,
- // |endCoord| with the color given by the individual components. This also
- // increments the relevant local variables to move the current pixel right
- // to |endCoord|.
- inline void fillRGBA(int endCoord, unsigned red, unsigned green, unsigned blue, unsigned alpha)
+ // |endCoord| with the color given by the individual components. This
+ // also increments the relevant local variables to move the current
+ // pixel right to |endCoord|.
+ inline void fillRGBA(int endCoord,
+ unsigned red,
+ unsigned green,
+ unsigned blue,
+ unsigned alpha)
{
while (m_coord.x() < endCoord)
setRGBA(red, green, blue, alpha);
}
- // Resets the relevant local variables to start drawing at the left edge of
- // the "next" row, where "next" is above or below the current row depending
- // on the value of |m_isTopDown|.
+ // Resets the relevant local variables to start drawing at the left edge
+ // of the "next" row, where "next" is above or below the current row
+ // depending on the value of |m_isTopDown|.
void moveBufferToNextRow();
+ // Sets the "decode failure" flag and clears any local storage. For
+ // caller convenience (since so many callers want to return false after
+ // calling this), returns false to enable easy tailcalling.
+ bool setFailed();
+
+ // The decoder that owns us.
+ ImageDecoder* m_parent;
+
+ // The destination for the pixel data.
+ RGBA32Buffer* m_buffer;
+
+ // The file to decode.
+ RefPtr<SharedBuffer> m_data;
+
+ // An index into |m_data| representing how much we've already decoded.
+ size_t m_decodedOffset;
+
+ // The file offset at which the BMP info header starts.
+ size_t m_headerOffset;
+
+ // The file offset at which the actual image bits start. When decoding
+ // ICO files, this is set to 0, since it's not stored anywhere in a
+ // header; the reader functions expect the image data to start
+ // immediately after the header and (if necessary) color table.
+ size_t m_imgDataOffset;
+
// The BMP info header.
BitmapInfoHeader m_infoHeader;
- // True if this is an OS/2 1.x (aka Windows 2.x) BMP. The struct layouts
- // for this type of BMP are slightly different from the later, more common
- // formats.
+ // True if this is an OS/2 1.x (aka Windows 2.x) BMP. The struct
+ // layouts for this type of BMP are slightly different from the later,
+ // more common formats.
bool m_isOS21x;
// True if this is an OS/2 2.x BMP. The meanings of compression types 3
// and 4 for this type of BMP differ from Windows V3+ BMPs.
//
- // This will be falsely negative in some cases, but only ones where the way
- // we misinterpret the data is irrelevant.
+ // This will be falsely negative in some cases, but only ones where the
+ // way we misinterpret the data is irrelevant.
bool m_isOS22x;
// True if the BMP is not vertically flipped, that is, the first line of
@@ -295,15 +324,17 @@ namespace WebCore {
bool m_needToProcessBitmasks;
bool m_needToProcessColorTable;
- // Masks/offsets for the color values for non-palette formats. These are
- // bitwise, with array entries 0, 1, 2, 3 corresponding to R, G, B, A.
+ // Masks/offsets for the color values for non-palette formats. These
+ // are bitwise, with array entries 0, 1, 2, 3 corresponding to R, G, B,
+ // A.
//
// The right/left shift values are meant to be applied after the masks.
- // We need to right shift to compensate for the bitfields' offsets into the
- // 32 bits of pixel data, and left shift to scale the color values up for
- // fields with less than 8 bits of precision. Sadly, we can't just combine
- // these into one shift value because the net shift amount could go either
- // direction. (If only "<< -x" were equivalent to ">> x"...)
+ // We need to right shift to compensate for the bitfields' offsets into
+ // the 32 bits of pixel data, and left shift to scale the color values
+ // up for fields with less than 8 bits of precision. Sadly, we can't
+ // just combine these into one shift value because the net shift amount
+ // could go either direction. (If only "<< -x" were equivalent to
+ // ">> x"...)
uint32_t m_bitMasks[4];
int m_bitShiftsRight[4];
int m_bitShiftsLeft[4];
@@ -320,6 +351,12 @@ namespace WebCore {
// these are used.
bool m_seenNonZeroAlphaPixel;
bool m_seenZeroAlphaPixel;
+
+ // ICOs store a 1bpp "mask" immediately after the main bitmap image data
+ // (and, confusingly, add its height to the biHeight value in the info
+ // header, thus doubling it). This variable tracks whether we have such
+ // a mask and if we've started decoding it yet.
+ AndMaskState m_andMaskState;
};
} // namespace WebCore
diff --git a/WebCore/platform/image-decoders/cairo/ImageDecoderCairo.cpp b/WebCore/platform/image-decoders/cairo/ImageDecoderCairo.cpp
new file mode 100644
index 0000000..c53eabd
--- /dev/null
+++ b/WebCore/platform/image-decoders/cairo/ImageDecoderCairo.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include "ImageDecoder.h"
+
+#include <cairo.h>
+
+namespace WebCore {
+
+RGBA32Buffer::RGBA32Buffer()
+ : m_hasAlpha(false)
+ , m_status(FrameEmpty)
+ , m_duration(0)
+ , m_disposalMethod(DisposeNotSpecified)
+{
+}
+
+void RGBA32Buffer::clear()
+{
+ m_bytes.clear();
+ m_status = FrameEmpty;
+ // NOTE: Do not reset other members here; clearFrameBufferCache()
+ // calls this to free the bitmap data, but other functions like
+ // initFrameBuffer() and frameComplete() may still need to read
+ // other metadata out of this frame later.
+}
+
+void RGBA32Buffer::zeroFill()
+{
+ m_bytes.fill(0);
+ m_hasAlpha = true;
+}
+
+void RGBA32Buffer::copyBitmapData(const RGBA32Buffer& other)
+{
+ if (this == &other)
+ return;
+
+ m_bytes = other.m_bytes;
+ m_size = other.m_size;
+ setHasAlpha(other.m_hasAlpha);
+}
+
+bool RGBA32Buffer::setSize(int newWidth, int newHeight)
+{
+ // NOTE: This has no way to check for allocation failure if the
+ // requested size was too big...
+ m_bytes.resize(newWidth * newHeight);
+ m_size = IntSize(newWidth, newHeight);
+
+ // Zero the image.
+ zeroFill();
+
+ return true;
+}
+
+NativeImagePtr RGBA32Buffer::asNewNativeImage() const
+{
+ return cairo_image_surface_create_for_data(
+ reinterpret_cast<unsigned char*>(const_cast<PixelData*>(
+ m_bytes.data())), CAIRO_FORMAT_ARGB32, width(), height(),
+ width() * sizeof(PixelData));
+}
+
+bool RGBA32Buffer::hasAlpha() const
+{
+ return m_hasAlpha;
+}
+
+void RGBA32Buffer::setHasAlpha(bool alpha)
+{
+ m_hasAlpha = alpha;
+}
+
+void RGBA32Buffer::setStatus(FrameStatus status)
+{
+ m_status = status;
+}
+
+RGBA32Buffer& RGBA32Buffer::operator=(const RGBA32Buffer& other)
+{
+ if (this == &other)
+ return *this;
+
+ copyBitmapData(other);
+ setRect(other.rect());
+ setStatus(other.status());
+ setDuration(other.duration());
+ setDisposalMethod(other.disposalMethod());
+ return *this;
+}
+
+int RGBA32Buffer::width() const {
+ return m_size.width();
+}
+
+int RGBA32Buffer::height() const {
+ return m_size.height();
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp b/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp
index 62d8b5b..87036c9 100644
--- a/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp
+++ b/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp
@@ -113,24 +113,17 @@ void GIFImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
}
// Whether or not the size information has been decoded yet.
-bool GIFImageDecoder::isSizeAvailable() const
+bool GIFImageDecoder::isSizeAvailable()
{
- // If we have pending data to decode, send it to the GIF reader now.
- if (!m_sizeAvailable && m_reader) {
- if (m_failed)
- return false;
-
- // The decoder will go ahead and aggressively consume everything up until the first
- // size is encountered.
- decode(GIFSizeQuery, 0);
- }
+ if (!ImageDecoder::isSizeAvailable() && !failed() && m_reader)
+ decode(GIFSizeQuery, 0);
- return m_sizeAvailable;
+ return ImageDecoder::isSizeAvailable();
}
// The total number of frames for the image. Will scan the image data for the answer
// (without necessarily decoding all of the individual frames).
-int GIFImageDecoder::frameCount()
+size_t GIFImageDecoder::frameCount()
{
// If the decoder had an earlier error, we will just return what we had decoded
// so far.
@@ -177,7 +170,7 @@ int GIFImageDecoder::repetitionCount() const
RGBA32Buffer* GIFImageDecoder::frameBufferAtIndex(size_t index)
{
- if (index >= static_cast<size_t>(frameCount()))
+ if (index >= frameCount())
return 0;
RGBA32Buffer& frame = m_frameBufferCache[index];
@@ -237,7 +230,7 @@ void GIFImageDecoder::clearFrameBufferCache(size_t clearBeforeFrame)
}
// Feed data to the GIF reader.
-void GIFImageDecoder::decode(GIFQuery query, unsigned haltAtFrame) const
+void GIFImageDecoder::decode(GIFQuery query, unsigned haltAtFrame)
{
if (m_failed)
return;
@@ -251,10 +244,9 @@ void GIFImageDecoder::decode(GIFQuery query, unsigned haltAtFrame) const
}
// Callbacks from the GIF reader.
-void GIFImageDecoder::sizeNowAvailable(unsigned width, unsigned height)
+bool GIFImageDecoder::sizeNowAvailable(unsigned width, unsigned height)
{
- m_size = IntSize(width, height);
- m_sizeAvailable = true;
+ return setSize(width, height);
}
void GIFImageDecoder::decodingHalted(unsigned bytesLeft)
@@ -262,7 +254,7 @@ void GIFImageDecoder::decodingHalted(unsigned bytesLeft)
m_reader->setReadOffset(m_data->size() - bytesLeft);
}
-void GIFImageDecoder::initFrameBuffer(unsigned frameIndex)
+bool GIFImageDecoder::initFrameBuffer(unsigned frameIndex)
{
// Initialize the frame rect in our buffer.
IntRect frameRect(m_reader->frameXOffset(), m_reader->frameYOffset(),
@@ -279,7 +271,10 @@ void GIFImageDecoder::initFrameBuffer(unsigned frameIndex)
if (frameIndex == 0) {
// This is the first frame, so we're not relying on any previous data.
- prepEmptyFrameBuffer(buffer);
+ if (!buffer->setSize(size().width(), size().height())) {
+ m_failed = true;
+ return false;
+ }
} else {
// The starting state for this frame depends on the previous frame's
// disposal method.
@@ -302,26 +297,25 @@ void GIFImageDecoder::initFrameBuffer(unsigned frameIndex)
if ((prevMethod == RGBA32Buffer::DisposeNotSpecified) ||
(prevMethod == RGBA32Buffer::DisposeKeep)) {
// Preserve the last frame as the starting state for this frame.
- buffer->bytes() = prevBuffer->bytes();
- buffer->setHasAlpha(prevBuffer->hasAlpha());
+ buffer->copyBitmapData(*prevBuffer);
} else {
// We want to clear the previous frame to transparent, without
// affecting pixels in the image outside of the frame.
const IntRect& prevRect = prevBuffer->rect();
if ((frameIndex == 0)
- || prevRect.contains(IntRect(IntPoint(0, 0), size()))) {
+ || prevRect.contains(IntRect(IntPoint(), size()))) {
// Clearing the first frame, or a frame the size of the whole
// image, results in a completely empty image.
- prepEmptyFrameBuffer(buffer);
+ if (!buffer->setSize(size().width(), size().height())) {
+ m_failed = true;
+ return false;
+ }
} else {
// Copy the whole previous buffer, then clear just its frame.
- buffer->bytes() = prevBuffer->bytes();
- buffer->setHasAlpha(prevBuffer->hasAlpha());
+ buffer->copyBitmapData(*prevBuffer);
for (int y = prevRect.y(); y < prevRect.bottom(); ++y) {
- unsigned* const currentRow =
- buffer->bytes().data() + (y * m_size.width());
for (int x = prevRect.x(); x < prevRect.right(); ++x)
- buffer->setRGBA(*(currentRow + x), 0, 0, 0, 0);
+ buffer->setRGBA(x, y, 0, 0, 0, 0);
}
if ((prevRect.width() > 0) && (prevRect.height() > 0))
buffer->setHasAlpha(true);
@@ -334,57 +328,47 @@ void GIFImageDecoder::initFrameBuffer(unsigned frameIndex)
// Reset the alpha pixel tracker for this frame.
m_currentBufferSawAlpha = false;
-}
-
-void GIFImageDecoder::prepEmptyFrameBuffer(RGBA32Buffer* buffer) const
-{
- buffer->bytes().resize(size().width() * size().height());
- buffer->bytes().fill(0);
- buffer->setHasAlpha(true);
+ return true;
}
void GIFImageDecoder::haveDecodedRow(unsigned frameIndex,
- unsigned char* rowBuffer, // Pointer to single scanline temporary buffer
+ unsigned char* rowBuffer,
unsigned char* rowEnd,
- unsigned rowNumber, // The row index
- unsigned repeatCount, // How many times to repeat the row
+ unsigned rowNumber,
+ unsigned repeatCount,
bool writeTransparentPixels)
{
- // Initialize the frame if necessary.
- RGBA32Buffer& buffer = m_frameBufferCache[frameIndex];
- if (buffer.status() == RGBA32Buffer::FrameEmpty)
- initFrameBuffer(frameIndex);
-
- // Do nothing for bogus data.
- if (rowBuffer == 0 || static_cast<int>(m_reader->frameYOffset() + rowNumber) >= size().height())
+ // The pixel data and coordinates supplied to us are relative to the frame's
+ // origin within the entire image size, i.e.
+ // (m_reader->frameXOffset(), m_reader->frameYOffset()).
+ int x = m_reader->frameXOffset();
+ const int y = m_reader->frameYOffset() + rowNumber;
+
+ // Sanity-check the arguments.
+ if ((rowBuffer == 0) || (y >= size().height()))
return;
+ // Get the colormap.
unsigned colorMapSize;
unsigned char* colorMap;
m_reader->getColorMap(colorMap, colorMapSize);
if (!colorMap)
return;
- // The buffers that we draw are the entire image's width and height, so a final output frame is
- // width * height RGBA32 values in size.
- //
- // A single GIF frame, however, can be smaller than the entire image, i.e., it can represent some sub-rectangle
- // within the overall image. The rows we are decoding are within this
- // sub-rectangle. This means that if the GIF frame's sub-rectangle is (x,y,w,h) then row 0 is really row
- // y, and each row goes from x to x+w.
- unsigned dstPos = (m_reader->frameYOffset() + rowNumber) * size().width() + m_reader->frameXOffset();
- unsigned* dst = buffer.bytes().data() + dstPos;
- unsigned* dstEnd = dst + size().width() - m_reader->frameXOffset();
- unsigned* currDst = dst;
- unsigned char* currentRowByte = rowBuffer;
-
- while (currentRowByte != rowEnd && currDst < dstEnd) {
- if ((!m_reader->isTransparent() || *currentRowByte != m_reader->transparentPixel()) && *currentRowByte < colorMapSize) {
- unsigned colorIndex = *currentRowByte * 3;
- unsigned red = colorMap[colorIndex];
- unsigned green = colorMap[colorIndex + 1];
- unsigned blue = colorMap[colorIndex + 2];
- RGBA32Buffer::setRGBA(*currDst, red, green, blue, 255);
+ // Initialize the frame if necessary.
+ RGBA32Buffer& buffer = m_frameBufferCache[frameIndex];
+ if ((buffer.status() == RGBA32Buffer::FrameEmpty) && !initFrameBuffer(frameIndex))
+ return;
+
+ // Write one row's worth of data into the frame. There is no guarantee that
+ // (rowEnd - rowBuffer) == (size().width() - m_reader->frameXOffset()), so
+ // we must ensure we don't run off the end of either the source data or the
+ // row's X-coordinates.
+ for (unsigned char* sourceAddr = rowBuffer; (sourceAddr != rowEnd) && (x < size().width()); ++sourceAddr, ++x) {
+ const unsigned char sourceValue = *sourceAddr;
+ if ((!m_reader->isTransparent() || (sourceValue != m_reader->transparentPixel())) && (sourceValue < colorMapSize)) {
+ const size_t colorIndex = static_cast<size_t>(sourceValue) * 3;
+ buffer.setRGBA(x, y, colorMap[colorIndex], colorMap[colorIndex + 1], colorMap[colorIndex + 2], 255);
} else {
m_currentBufferSawAlpha = true;
// We may or may not need to write transparent pixels to the buffer.
@@ -395,30 +379,13 @@ void GIFImageDecoder::haveDecodedRow(unsigned frameIndex,
// beyond the first, or the initial passes will "show through" the
// later ones.
if (writeTransparentPixels)
- RGBA32Buffer::setRGBA(*currDst, 0, 0, 0, 0);
+ buffer.setRGBA(x, y, 0, 0, 0, 0);
}
- currDst++;
- currentRowByte++;
}
- if (repeatCount > 1) {
- // Copy the row |repeatCount|-1 times.
- unsigned num = currDst - dst;
- unsigned data_size = num * sizeof(unsigned);
- unsigned width = size().width();
- unsigned* end = buffer.bytes().data() + width * size().height();
- currDst = dst + width;
- for (unsigned i = 1; i < repeatCount; i++) {
- if (currDst + num > end) // Protect against a buffer overrun from a bogus repeatCount.
- break;
- memcpy(currDst, dst, data_size);
- currDst += width;
- }
- }
-
- // Our partial height is rowNumber + 1, e.g., row 2 is the 3rd row, so that's a height of 3.
- // Adding in repeatCount - 1 to rowNumber + 1 works out to just be rowNumber + repeatCount.
- buffer.ensureHeight(rowNumber + repeatCount);
+ // Tell the frame to copy the row data if need be.
+ if (repeatCount > 1)
+ buffer.copyRowNTimes(m_reader->frameXOffset(), x, y, std::min(y + static_cast<int>(repeatCount), size().height()));
}
void GIFImageDecoder::frameComplete(unsigned frameIndex, unsigned frameDuration, RGBA32Buffer::FrameDisposalMethod disposalMethod)
@@ -426,10 +393,9 @@ void GIFImageDecoder::frameComplete(unsigned frameIndex, unsigned frameDuration,
// Initialize the frame if necessary. Some GIFs insert do-nothing frames,
// in which case we never reach haveDecodedRow() before getting here.
RGBA32Buffer& buffer = m_frameBufferCache[frameIndex];
- if (buffer.status() == RGBA32Buffer::FrameEmpty)
- initFrameBuffer(frameIndex);
+ if ((buffer.status() == RGBA32Buffer::FrameEmpty) && !initFrameBuffer(frameIndex))
+ return;
- buffer.ensureHeight(m_size.height());
buffer.setStatus(RGBA32Buffer::FrameComplete);
buffer.setDuration(frameDuration);
buffer.setDisposalMethod(disposalMethod);
@@ -437,7 +403,7 @@ void GIFImageDecoder::frameComplete(unsigned frameIndex, unsigned frameDuration,
if (!m_currentBufferSawAlpha) {
// The whole frame was non-transparent, so it's possible that the entire
// resulting buffer was non-transparent, and we can setHasAlpha(false).
- if (buffer.rect().contains(IntRect(IntPoint(0, 0), size())))
+ if (buffer.rect().contains(IntRect(IntPoint(), size())))
buffer.setHasAlpha(false);
else if (frameIndex > 0) {
// Tricky case. This frame does not have alpha only if everywhere
diff --git a/WebCore/platform/image-decoders/gif/GIFImageDecoder.h b/WebCore/platform/image-decoders/gif/GIFImageDecoder.h
index abb55a4..5227ea3 100644
--- a/WebCore/platform/image-decoders/gif/GIFImageDecoder.h
+++ b/WebCore/platform/image-decoders/gif/GIFImageDecoder.h
@@ -44,11 +44,11 @@ namespace WebCore {
virtual void setData(SharedBuffer* data, bool allDataReceived);
// Whether or not the size information has been decoded yet.
- virtual bool isSizeAvailable() const;
+ virtual bool isSizeAvailable();
// The total number of frames for the image. Will scan the image data for the answer
// (without necessarily decoding all of the individual frames).
- virtual int frameCount();
+ virtual size_t frameCount();
// The number of repetitions to perform for an animation loop.
virtual int repetitionCount() const;
@@ -61,10 +61,10 @@ namespace WebCore {
enum GIFQuery { GIFFullQuery, GIFSizeQuery, GIFFrameCountQuery };
- void decode(GIFQuery, unsigned haltAtFrame) const;
+ void decode(GIFQuery, unsigned haltAtFrame);
// Callbacks from the GIF reader.
- void sizeNowAvailable(unsigned width, unsigned height);
+ bool sizeNowAvailable(unsigned width, unsigned height);
void decodingHalted(unsigned bytesLeft);
void haveDecodedRow(unsigned frameIndex, unsigned char* rowBuffer, unsigned char* rowEnd, unsigned rowNumber,
unsigned repeatCount, bool writeTransparentPixels);
@@ -73,17 +73,14 @@ namespace WebCore {
private:
// Called to initialize the frame buffer with the given index, based on the
- // previous frame's disposal method.
- void initFrameBuffer(unsigned frameIndex);
-
- // A helper for initFrameBuffer(), this sets the size of the buffer, and
- // fills it with transparent pixels.
- void prepEmptyFrameBuffer(RGBA32Buffer*) const;
+ // previous frame's disposal method. Returns true on success. On failure,
+ // this will mark the image as failed.
+ bool initFrameBuffer(unsigned frameIndex);
bool m_frameCountValid;
bool m_currentBufferSawAlpha;
mutable int m_repetitionCount;
- mutable GIFImageDecoderPrivate* m_reader;
+ GIFImageDecoderPrivate* m_reader;
};
} // namespace WebCore
diff --git a/WebCore/platform/image-decoders/gif/GIFImageReader.cpp b/WebCore/platform/image-decoders/gif/GIFImageReader.cpp
index 95ab40d..002f67a 100644
--- a/WebCore/platform/image-decoders/gif/GIFImageReader.cpp
+++ b/WebCore/platform/image-decoders/gif/GIFImageReader.cpp
@@ -311,9 +311,13 @@ int GIFImageReader::do_lzw(const unsigned char *q)
while (code >= clear_code)
{
- if (code == prefix[code])
+ if (code >= MAX_BITS || code == prefix[code])
return -1;
+ // Even though suffix[] only holds characters through suffix[avail - 1],
+ // allowing code >= avail here lets us be more tolerant of malformed
+ // data. As long as code < MAX_BITS, the only risk is a garbled image,
+ // which is no worse than refusing to display it.
*stackp++ = suffix[code];
code = prefix[code];
@@ -445,7 +449,10 @@ bool GIFImageReader::read(const unsigned char *buf, unsigned len,
{
/* Initialize LZW parser/decoder */
int datasize = *q;
- if (datasize > MAX_LZW_BITS) {
+ // Since we use a codesize of 1 more than the datasize, we need to ensure
+ // that our datasize is strictly less than the MAX_LZW_BITS value (12).
+ // This sets the largest possible codemask correctly at 4095.
+ if (datasize >= MAX_LZW_BITS) {
state = gif_error;
break;
}
@@ -468,6 +475,8 @@ bool GIFImageReader::read(const unsigned char *buf, unsigned len,
/* init the tables */
if (!frame_reader->suffix)
frame_reader->suffix = new unsigned char[MAX_BITS];
+ // Clearing the whole suffix table lets us be more tolerant of bad data.
+ memset(frame_reader->suffix, 0, MAX_BITS);
for (int i = 0; i < frame_reader->clear_code; i++)
frame_reader->suffix[i] = i;
@@ -508,8 +517,8 @@ bool GIFImageReader::read(const unsigned char *buf, unsigned len,
screen_height = GETINT16(q + 2);
// CALLBACK: Inform the decoderplugin of our size.
- if (clientptr)
- clientptr->sizeNowAvailable(screen_width, screen_height);
+ if (clientptr && !clientptr->sizeNowAvailable(screen_width, screen_height))
+ return false;
screen_bgcolor = q[5];
global_colormap_size = 2<<(q[4]&0x07);
@@ -734,8 +743,8 @@ bool GIFImageReader::read(const unsigned char *buf, unsigned len,
y_offset = 0;
// CALLBACK: Inform the decoderplugin of our size.
- if (clientptr)
- clientptr->sizeNowAvailable(screen_width, screen_height);
+ if (clientptr && !clientptr->sizeNowAvailable(screen_width, screen_height))
+ return false;
}
/* Work around more broken GIF files that have zero image
diff --git a/WebCore/platform/image-decoders/haiku/ImageDecoderHaiku.cpp b/WebCore/platform/image-decoders/haiku/ImageDecoderHaiku.cpp
new file mode 100644
index 0000000..3542cc2
--- /dev/null
+++ b/WebCore/platform/image-decoders/haiku/ImageDecoderHaiku.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include "ImageDecoder.h"
+
+#include <Bitmap.h>
+
+
+namespace WebCore {
+
+RGBA32Buffer::RGBA32Buffer()
+ : m_hasAlpha(false)
+ , m_status(FrameEmpty)
+ , m_duration(0)
+ , m_disposalMethod(DisposeNotSpecified)
+{
+}
+
+void RGBA32Buffer::clear()
+{
+ m_bytes.clear();
+ m_status = FrameEmpty;
+ // NOTE: Do not reset other members here; clearFrameBufferCache()
+ // calls this to free the bitmap data, but other functions like
+ // initFrameBuffer() and frameComplete() may still need to read
+ // other metadata out of this frame later.
+}
+
+void RGBA32Buffer::zeroFill()
+{
+ m_bytes.fill(0);
+ m_hasAlpha = true;
+}
+
+void RGBA32Buffer::copyBitmapData(const RGBA32Buffer& other)
+{
+ if (this == &other)
+ return;
+
+ m_bytes = other.m_bytes;
+ setHasAlpha(other.m_hasAlpha);
+}
+
+bool RGBA32Buffer::setSize(int newWidth, int newHeight)
+{
+ // NOTE: This has no way to check for allocation failure if the
+ // requested size was too big...
+ m_bytes.resize(newWidth * newHeight);
+ m_size = IntSize(newWidth, newHeight);
+
+ // Zero the image.
+ zeroFill();
+
+ return true;
+}
+
+NativeImagePtr RGBA32Buffer::asNewNativeImage() const
+{
+ const void* bytes = m_bytes.data();
+
+ BBitmap* bmp = new BBitmap(BRect(0, 0, width(), height()), B_RGB32);
+ bmp->SetBits(bytes, m_size.width() * m_size.height(), 0, B_RGB32);
+
+ return bmp;
+}
+
+bool RGBA32Buffer::hasAlpha() const
+{
+ return m_hasAlpha;
+}
+
+void RGBA32Buffer::setHasAlpha(bool alpha)
+{
+ m_hasAlpha = alpha;
+}
+
+void RGBA32Buffer::setStatus(FrameStatus status)
+{
+ m_status = status;
+}
+
+RGBA32Buffer& RGBA32Buffer::operator=(const RGBA32Buffer& other)
+{
+ if (this == &other)
+ return *this;
+
+ m_bytes = other.m_bytes;
+ m_size = other.m_size;
+ setHasAlpha(other.hasAlpha());
+ setRect(other.rect());
+ setStatus(other.status());
+ setDuration(other.duration());
+ setDisposalMethod(other.disposalMethod());
+ return *this;
+}
+
+int RGBA32Buffer::width() const
+{
+ return m_size.width();
+}
+
+int RGBA32Buffer::height() const
+{
+ return m_size.height();
+}
+
+} // namespace WebCore
+
diff --git a/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp b/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp
index 5b1a88f..e9296ad 100644
--- a/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp
+++ b/WebCore/platform/image-decoders/ico/ICOImageDecoder.cpp
@@ -1,42 +1,343 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- *
+ * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
+ *
* 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
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
+
#include "config.h"
#include "ICOImageDecoder.h"
-namespace WebCore
+#include <algorithm>
+
+#include "BMPImageReader.h"
+#include "PNGImageDecoder.h"
+
+namespace WebCore {
+
+// Number of bits in .ICO/.CUR used to store the directory and its entries,
+// respectively (doesn't match sizeof values for member structs since we omit
+// some fields).
+static const size_t sizeOfDirectory = 6;
+static const size_t sizeOfDirEntry = 16;
+
+ICOImageDecoder::ICOImageDecoder()
+ : ImageDecoder()
+ , m_allDataReceived(false)
+ , m_decodedOffset(0)
{
+}
-bool ICOImageDecoder::isSizeAvailable() const
+ICOImageDecoder::~ICOImageDecoder()
{
- return false;
+ deleteAllValues(m_bmpReaders);
+ deleteAllValues(m_pngDecoders);
}
-
+
+void ICOImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
+{
+ if (failed())
+ return;
+
+ ImageDecoder::setData(data, allDataReceived);
+ m_allDataReceived = allDataReceived;
+
+ for (BMPReaders::iterator i(m_bmpReaders.begin());
+ i != m_bmpReaders.end(); ++i) {
+ if (*i)
+ (*i)->setData(data);
+ }
+ for (size_t i = 0; i < m_pngDecoders.size(); ++i)
+ setDataForPNGDecoderAtIndex(i);
+}
+
+bool ICOImageDecoder::isSizeAvailable()
+{
+ if (!ImageDecoder::isSizeAvailable())
+ decodeWithCheckForDataEnded(0, true);
+
+ return ImageDecoder::isSizeAvailable();
+}
+
+IntSize ICOImageDecoder::size() const
+{
+ return m_frameSize.isEmpty() ? ImageDecoder::size() : m_frameSize;
+}
+
+IntSize ICOImageDecoder::frameSizeAtIndex(size_t index) const
+{
+ return (index && (index < m_dirEntries.size())) ?
+ m_dirEntries[index].m_size : size();
+}
+
+bool ICOImageDecoder::setSize(unsigned width, unsigned height)
+{
+ if (m_frameSize.isEmpty())
+ return ImageDecoder::setSize(width, height);
+
+ // The size calculated inside the BMPImageReader had better match the one in
+ // the icon directory.
+ if (IntSize(width, height) != m_frameSize)
+ setFailed();
+ return !failed();
+}
+
+size_t ICOImageDecoder::frameCount()
+{
+ decodeWithCheckForDataEnded(0, true);
+ if (m_frameBufferCache.isEmpty())
+ m_frameBufferCache.resize(m_dirEntries.size());
+ // CAUTION: We must not resize m_frameBufferCache again after this, as
+ // decodeAtIndex() may give a BMPImageReader a pointer to one of the
+ // entries.
+ return m_frameBufferCache.size();
+}
+
RGBA32Buffer* ICOImageDecoder::frameBufferAtIndex(size_t index)
{
- return 0;
+ // Ensure |index| is valid.
+ if (index >= frameCount())
+ return 0;
+
+ // Determine the image type, and if this is a BMP, decode.
+ decodeWithCheckForDataEnded(index, false);
+
+ // PNGs decode into their own framebuffers, so only use our internal cache
+ // for non-PNGs (BMP or unknown).
+ if (!m_pngDecoders[index])
+ return &m_frameBufferCache[index];
+
+ // Fail if the size the PNGImageDecoder calculated does not match the size
+ // in the directory.
+ if (m_pngDecoders[index]->isSizeAvailable()) {
+ const IntSize pngSize(m_pngDecoders[index]->size());
+ const IconDirectoryEntry& dirEntry = m_dirEntries[index];
+ if (pngSize != dirEntry.m_size) {
+ setFailed();
+ m_pngDecoders[index]->setFailed();
+ }
+ }
+
+ return m_pngDecoders[index]->frameBufferAtIndex(0);
+}
+
+// static
+bool ICOImageDecoder::compareEntries(const IconDirectoryEntry& a,
+ const IconDirectoryEntry& b)
+{
+ // Larger icons are better.
+ const int aEntryArea = a.m_size.width() * a.m_size.height();
+ const int bEntryArea = b.m_size.width() * b.m_size.height();
+ if (aEntryArea != bEntryArea)
+ return (aEntryArea > bEntryArea);
+
+ // Higher bit-depth icons are better.
+ return (a.m_bitCount > b.m_bitCount);
+}
+
+void ICOImageDecoder::setDataForPNGDecoderAtIndex(size_t index)
+{
+ if (!m_pngDecoders[index])
+ return;
+
+ const IconDirectoryEntry& dirEntry = m_dirEntries[index];
+ // Copy out PNG data to a separate vector and send to the PNG decoder.
+ // FIXME: Save this copy by making the PNG decoder able to take an
+ // optional offset.
+ RefPtr<SharedBuffer> pngData(
+ SharedBuffer::create(&m_data->data()[dirEntry.m_imageOffset],
+ m_data->size() - dirEntry.m_imageOffset));
+ m_pngDecoders[index]->setData(pngData.get(), m_allDataReceived);
+}
+
+void ICOImageDecoder::decodeWithCheckForDataEnded(size_t index, bool onlySize)
+{
+ if (failed())
+ return;
+
+ // If we couldn't decode the image but we've received all the data, decoding
+ // has failed.
+ if ((!decodeDirectory() || (!onlySize && !decodeAtIndex(index)))
+ && m_allDataReceived)
+ setFailed();
}
-} // namespace WebCore
+bool ICOImageDecoder::decodeDirectory()
+{
+ // Read and process directory.
+ if ((m_decodedOffset < sizeOfDirectory) && !processDirectory())
+ return false;
+
+ // Read and process directory entries.
+ return (m_decodedOffset >=
+ (sizeOfDirectory + (m_dirEntries.size() * sizeOfDirEntry)))
+ || processDirectoryEntries();
+}
+
+bool ICOImageDecoder::decodeAtIndex(size_t index)
+{
+ ASSERT(index < m_dirEntries.size());
+ const IconDirectoryEntry& dirEntry = m_dirEntries[index];
+ if (!m_bmpReaders[index] && !m_pngDecoders[index]) {
+ // Image type unknown.
+ const ImageType imageType = imageTypeAtIndex(index);
+ if (imageType == BMP) {
+ // We need to have already sized m_frameBufferCache before this, and
+ // we must not resize it again later (see caution in frameCount()).
+ ASSERT(m_frameBufferCache.size() == m_dirEntries.size());
+ m_bmpReaders[index] =
+ new BMPImageReader(this, dirEntry.m_imageOffset, 0, true);
+ m_bmpReaders[index]->setData(m_data.get());
+ m_bmpReaders[index]->setBuffer(&m_frameBufferCache[index]);
+ } else if (imageType == PNG) {
+ m_pngDecoders[index] = new PNGImageDecoder();
+ setDataForPNGDecoderAtIndex(index);
+ } else {
+ // Not enough data to determine image type yet.
+ return false;
+ }
+ }
+
+ if (m_bmpReaders[index]) {
+ m_frameSize = dirEntry.m_size;
+ bool result = m_bmpReaders[index]->decodeBMP(false);
+ m_frameSize = IntSize();
+ return result;
+ }
+
+ // For PNGs, we're now done; further decoding will happen when calling
+ // frameBufferAtIndex() on the PNG decoder.
+ return true;
+}
+
+bool ICOImageDecoder::processDirectory()
+{
+ // Read directory.
+ ASSERT(!m_decodedOffset);
+ if (m_data->size() < sizeOfDirectory)
+ return false;
+ const uint16_t fileType = readUint16(2);
+ const uint16_t idCount = readUint16(4);
+ m_decodedOffset = sizeOfDirectory;
+
+ // See if this is an icon filetype we understand, and make sure we have at
+ // least one entry in the directory.
+ enum {
+ ICON = 1,
+ CURSOR = 2,
+ };
+ if (((fileType != ICON) && (fileType != CURSOR)) || (idCount == 0)) {
+ setFailed();
+ return false;
+ }
+
+ // Enlarge member vectors to hold all the entries. We must initialize the
+ // BMP and PNG decoding vectors to 0 so that all entries can be safely
+ // deleted in our destructor. If we don't do this, they'll contain garbage
+ // values, and deleting those will corrupt memory.
+ m_dirEntries.resize(idCount);
+ m_bmpReaders.fill(0, idCount);
+ m_pngDecoders.fill(0, idCount);
+ return true;
+}
+
+bool ICOImageDecoder::processDirectoryEntries()
+{
+ // Read directory entries.
+ ASSERT(m_decodedOffset == sizeOfDirectory);
+ if ((m_decodedOffset > m_data->size())
+ || ((m_data->size() - m_decodedOffset) <
+ (m_dirEntries.size() * sizeOfDirEntry)))
+ return false;
+ for (IconDirectoryEntries::iterator i(m_dirEntries.begin());
+ i != m_dirEntries.end(); ++i)
+ *i = readDirectoryEntry(); // Updates m_decodedOffset.
+
+ // Make sure the specified image offsets are past the end of the directory
+ // entries.
+ for (IconDirectoryEntries::iterator i(m_dirEntries.begin());
+ i != m_dirEntries.end(); ++i) {
+ if (i->m_imageOffset < m_decodedOffset) {
+ setFailed();
+ return false;
+ }
+ }
+
+ // Arrange frames in decreasing quality order.
+ std::sort(m_dirEntries.begin(), m_dirEntries.end(), compareEntries);
+
+ // The image size is the size of the largest entry.
+ const IconDirectoryEntry& dirEntry = m_dirEntries.first();
+ setSize(dirEntry.m_size.width(), dirEntry.m_size.height());
+ return true;
+}
+
+ICOImageDecoder::IconDirectoryEntry ICOImageDecoder::readDirectoryEntry()
+{
+ // Read icon data.
+ // The casts to uint8_t in the next few lines are because that's the on-disk
+ // type of the width and height values. Storing them in ints (instead of
+ // matching uint8_ts) is so we can record dimensions of size 256 (which is
+ // what a zero byte really means).
+ int width = static_cast<uint8_t>(m_data->data()[m_decodedOffset]);
+ if (width == 0)
+ width = 256;
+ int height = static_cast<uint8_t>(m_data->data()[m_decodedOffset + 1]);
+ if (height == 0)
+ height = 256;
+ IconDirectoryEntry entry;
+ entry.m_size = IntSize(width, height);
+ entry.m_bitCount = readUint16(6);
+ entry.m_imageOffset = readUint32(12);
+
+ // Some icons don't have a bit depth, only a color count. Convert the
+ // color count to the minimum necessary bit depth. It doesn't matter if
+ // this isn't quite what the bitmap info header says later, as we only use
+ // this value to determine which icon entry is best.
+ if (!entry.m_bitCount) {
+ uint8_t colorCount = m_data->data()[m_decodedOffset + 2];
+ if (colorCount) {
+ for (--colorCount; colorCount; colorCount >>= 1)
+ ++entry.m_bitCount;
+ }
+ }
+
+ m_decodedOffset += sizeOfDirEntry;
+ return entry;
+}
+
+ICOImageDecoder::ImageType ICOImageDecoder::imageTypeAtIndex(size_t index)
+{
+ // Check if this entry is a BMP or a PNG; we need 4 bytes to check the magic
+ // number.
+ ASSERT(index < m_dirEntries.size());
+ const uint32_t imageOffset = m_dirEntries[index].m_imageOffset;
+ if ((imageOffset > m_data->size()) || ((m_data->size() - imageOffset) < 4))
+ return Unknown;
+ return strncmp(&m_data->data()[imageOffset], "\x89PNG", 4) ? BMP : PNG;
+}
+
+}
diff --git a/WebCore/platform/image-decoders/ico/ICOImageDecoder.h b/WebCore/platform/image-decoders/ico/ICOImageDecoder.h
index 56a74c3..f8bddf9 100644
--- a/WebCore/platform/image-decoders/ico/ICOImageDecoder.h
+++ b/WebCore/platform/image-decoders/ico/ICOImageDecoder.h
@@ -1,46 +1,147 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- *
+ * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
+ *
* 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
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ICOImageDecoder_h
#define ICOImageDecoder_h
-#include "ImageDecoder.h"
+#include "BMPImageReader.h"
namespace WebCore {
- class ICOImageReader;
+ class PNGImageDecoder;
// This class decodes the ICO and CUR image formats.
class ICOImageDecoder : public ImageDecoder {
public:
+ ICOImageDecoder();
+ virtual ~ICOImageDecoder();
+
+ // ImageDecoder
virtual String filenameExtension() const { return "ico"; }
+ virtual void setData(SharedBuffer*, bool allDataReceived);
+ virtual bool isSizeAvailable();
+ virtual IntSize size() const;
+ virtual IntSize frameSizeAtIndex(size_t) const;
+ virtual bool setSize(unsigned width, unsigned height);
+ virtual size_t frameCount();
+ virtual RGBA32Buffer* frameBufferAtIndex(size_t);
+
+ private:
+ enum ImageType {
+ Unknown,
+ BMP,
+ PNG,
+ };
+
+ struct IconDirectoryEntry {
+ IntSize m_size;
+ uint16_t m_bitCount;
+ uint32_t m_imageOffset;
+ };
+
+ // Returns true if |a| is a preferable icon entry to |b|.
+ // Larger sizes, or greater bitdepths at the same size, are preferable.
+ static bool compareEntries(const IconDirectoryEntry& a,
+ const IconDirectoryEntry& b);
+
+ inline uint16_t readUint16(int offset) const
+ {
+ return BMPImageReader::readUint16(m_data.get(),
+ m_decodedOffset + offset);
+ }
+
+ inline uint32_t readUint32(int offset) const
+ {
+ return BMPImageReader::readUint32(m_data.get(),
+ m_decodedOffset + offset);
+ }
+
+ // If the desired PNGImageDecoder exists, gives it the appropriate data.
+ void setDataForPNGDecoderAtIndex(size_t);
+
+ // Decodes the entry at |index|. If |onlySize| is true, stops decoding
+ // after calculating the image size. If decoding fails but there is no
+ // more data coming, sets the "decode failure" flag.
+ //
+ // NOTE: If the desired entry is a PNG, this doesn't actually trigger
+ // decoding, it merely ensures the decoder is created and ready to
+ // decode. The caller will then call a function on the PNGImageDecoder
+ // that actually triggers decoding.
+ void decodeWithCheckForDataEnded(size_t index, bool onlySize);
+
+ // Decodes the directory and directory entries at the beginning of the
+ // data, and initializes members. Returns true if all decoding
+ // succeeded. Once this returns true, all entries' sizes are known.
+ bool decodeDirectory();
+
+ // Decodes the specified entry.
+ bool decodeAtIndex(size_t);
+
+ // Processes the ICONDIR at the beginning of the data. Returns true if
+ // the directory could be decoded.
+ bool processDirectory();
+
+ // Processes the ICONDIRENTRY records after the directory. Keeps the
+ // "best" entry as the one we'll decode. Returns true if the entries
+ // could be decoded.
+ bool processDirectoryEntries();
+
+ // Reads and returns a directory entry from the current offset into
+ // |data|.
+ IconDirectoryEntry readDirectoryEntry();
+
+ // Determines whether the desired entry is a BMP or PNG. Returns true
+ // if the type could be determined.
+ ImageType imageTypeAtIndex(size_t);
+
+ // True if we've seen all the data.
+ bool m_allDataReceived;
+
+ // An index into |m_data| representing how much we've already decoded.
+ // Note that this only tracks data _this_ class decodes; once the
+ // BMPImageReader takes over this will not be updated further.
+ size_t m_decodedOffset;
+
+ // The headers for the ICO.
+ typedef Vector<IconDirectoryEntry> IconDirectoryEntries;
+ IconDirectoryEntries m_dirEntries;
- // Whether or not the size information has been decoded yet.
- virtual bool isSizeAvailable() const;
+ // The image decoders for the various frames.
+ typedef Vector<BMPImageReader*> BMPReaders;
+ BMPReaders m_bmpReaders;
+ typedef Vector<PNGImageDecoder*> PNGDecoders;
+ PNGDecoders m_pngDecoders;
- virtual RGBA32Buffer* frameBufferAtIndex(size_t index);
+ // Valid only while a BMPImageReader is decoding, this holds the size
+ // for the particular entry being decoded.
+ IntSize m_frameSize;
};
} // namespace WebCore
diff --git a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
index 38d90bd..ae09586 100644
--- a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
+++ b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
@@ -6,6 +6,8 @@
* Other contributors:
* Stuart Parmenter <stuart@mozilla.com>
*
+ * Copyright (C) 2007-2009 Torch Mobile, Inc.
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
@@ -38,17 +40,21 @@
#include "config.h"
#include "JPEGImageDecoder.h"
#include <assert.h>
-#include <stdio.h>
+#include <stdio.h> // Needed by jpeglib.h for FILE.
+
+#if PLATFORM(WINCE)
+// Remove warning: 'FAR' macro redefinition
+#undef FAR
+
+// jmorecfg.h in libjpeg checks for XMD_H with the comment: "X11/xmd.h correctly defines INT32"
+// fix INT32 redefinition error by pretending we are X11/xmd.h
+#define XMD_H
+#endif
extern "C" {
#include "jpeglib.h"
}
-#if COMPILER(MSVC)
-// Remove warnings from warning level 4.
-#pragma warning(disable : 4611) // warning C4611: interaction between '_setjmp' and C++ object destruction is non-portable
-#endif // COMPILER(MSVC)
-
#include <setjmp.h>
namespace WebCore {
@@ -188,6 +194,10 @@ public:
break;
case JCS_CMYK:
case JCS_YCCK:
+ // jpeglib cannot convert these to rgb, but it can
+ // convert ycck to cmyk
+ m_info.out_color_space = JCS_CMYK;
+ break;
default:
m_state = JPEG_ERROR;
return false;
@@ -219,7 +229,10 @@ public:
m_state = JPEG_START_DECOMPRESS;
// We can fill in the size now that the header is available.
- m_decoder->setSize(m_info.image_width, m_info.image_height);
+ if (!m_decoder->setSize(m_info.image_width, m_info.image_height)) {
+ m_state = JPEG_ERROR;
+ return false;
+ }
if (m_decodingSizeOnly) {
// We can stop here.
@@ -411,19 +424,12 @@ void JPEGImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
}
// Whether or not the size information has been decoded yet.
-bool JPEGImageDecoder::isSizeAvailable() const
+bool JPEGImageDecoder::isSizeAvailable()
{
- // If we have pending data to decode, send it to the JPEG reader now.
- if (!m_sizeAvailable && m_reader) {
- if (m_failed)
- return false;
-
- // The decoder will go ahead and aggressively consume everything up until the
- // size is encountered.
- decode(true);
- }
+ if (!ImageDecoder::isSizeAvailable() && !failed() && m_reader)
+ decode(true);
- return m_sizeAvailable;
+ return ImageDecoder::isSizeAvailable();
}
RGBA32Buffer* JPEGImageDecoder::frameBufferAtIndex(size_t index)
@@ -442,7 +448,7 @@ RGBA32Buffer* JPEGImageDecoder::frameBufferAtIndex(size_t index)
}
// Feed data to the JPEG reader.
-void JPEGImageDecoder::decode(bool sizeOnly) const
+void JPEGImageDecoder::decode(bool sizeOnly)
{
if (m_failed)
return;
@@ -455,45 +461,87 @@ void JPEGImageDecoder::decode(bool sizeOnly) const
}
}
+static void convertCMYKToRGBA(RGBA32Buffer& dest, JSAMPROW src, jpeg_decompress_struct* info)
+{
+ ASSERT(info->out_color_space == JCS_CMYK);
+
+ for (unsigned x = 0; x < info->output_width; ++x) {
+ unsigned c = *src++;
+ unsigned m = *src++;
+ unsigned y = *src++;
+ unsigned k = *src++;
+
+ // Source is 'Inverted CMYK', output is RGB.
+ // See: http://www.easyrgb.com/math.php?MATH=M12#text12
+ // Or: http://www.ilkeratalay.com/colorspacesfaq.php#rgb
+
+ // From CMYK to CMY
+ // C = C * ( 1 - K ) + K
+ // M = M * ( 1 - K ) + K
+ // Y = Y * ( 1 - K ) + K
+
+ // From Inverted CMYK to CMY is thus:
+ // C = (1-iC) * (1 - (1-iK)) + (1-iK) => 1 - iC*iK
+ // Same for M and Y
+
+ // Convert from CMY (0..1) to RGB (0..1)
+ // R = 1 - C => 1 - (1 - iC*iK) => iC*iK
+ // G = 1 - M => 1 - (1 - iM*iK) => iM*iK
+ // B = 1 - Y => 1 - (1 - iY*iK) => iY*iK
+
+ // read_scanlines has increased the scanline counter, so we
+ // actually mean the previous one.
+ dest.setRGBA(x, info->output_scanline - 1, c * k / 255, m * k / 255, y * k / 255, 0xFF);
+ }
+}
+
+static void convertRGBToRGBA(RGBA32Buffer& dest, JSAMPROW src, jpeg_decompress_struct* info)
+{
+ ASSERT(info->out_color_space == JCS_RGB);
+
+ for (unsigned x = 0; x < info->output_width; ++x) {
+ unsigned r = *src++;
+ unsigned g = *src++;
+ unsigned b = *src++;
+ // read_scanlines has increased the scanline counter, so we
+ // actually mean the previous one.
+ dest.setRGBA(x, info->output_scanline - 1, r, g, b, 0xFF);
+ }
+}
+
bool JPEGImageDecoder::outputScanlines()
{
if (m_frameBufferCache.isEmpty())
return false;
- // Resize to the width and height of the image.
+ // Initialize the framebuffer if needed.
RGBA32Buffer& buffer = m_frameBufferCache[0];
if (buffer.status() == RGBA32Buffer::FrameEmpty) {
- // Let's resize our buffer now to the correct width/height.
- RGBA32Array& bytes = buffer.bytes();
- bytes.resize(size().width() * size().height());
-
- // Update our status to be partially complete.
+ if (!buffer.setSize(size().width(), size().height())) {
+ m_failed = true;
+ return false;
+ }
buffer.setStatus(RGBA32Buffer::FramePartial);
+ buffer.setHasAlpha(false);
// For JPEGs, the frame always fills the entire image.
- buffer.setRect(IntRect(0, 0, m_size.width(), m_size.height()));
-
- // We don't have alpha (this is the default when the buffer is constructed).
+ buffer.setRect(IntRect(IntPoint(), size()));
}
jpeg_decompress_struct* info = m_reader->info();
JSAMPARRAY samples = m_reader->samples();
- unsigned* dst = buffer.bytes().data() + info->output_scanline * m_size.width();
-
while (info->output_scanline < info->output_height) {
/* Request one scanline. Returns 0 or 1 scanlines. */
if (jpeg_read_scanlines(info, samples, 1) != 1)
return false;
- JSAMPLE *j1 = samples[0];
- for (unsigned x = 0; x < info->output_width; ++x) {
- unsigned r = *j1++;
- unsigned g = *j1++;
- unsigned b = *j1++;
- RGBA32Buffer::setRGBA(*dst++, r, g, b, 0xFF);
- }
- buffer.ensureHeight(info->output_scanline);
+ if (info->out_color_space == JCS_RGB)
+ convertRGBToRGBA(buffer, *samples, info);
+ else if (info->out_color_space == JCS_CMYK)
+ convertCMYKToRGBA(buffer, *samples, info);
+ else
+ return false;
}
return true;
diff --git a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h
index c01bb5e..56e007d 100644
--- a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h
+++ b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h
@@ -44,28 +44,21 @@ namespace WebCore {
virtual void setData(SharedBuffer* data, bool allDataReceived);
// Whether or not the size information has been decoded yet.
- virtual bool isSizeAvailable() const;
+ virtual bool isSizeAvailable();
virtual RGBA32Buffer* frameBufferAtIndex(size_t index);
virtual bool supportsAlpha() const { return false; }
- void decode(bool sizeOnly = false) const;
+ void decode(bool sizeOnly = false);
JPEGImageReader* reader() { return m_reader; }
- void setSize(int width, int height) {
- if (!m_sizeAvailable) {
- m_sizeAvailable = true;
- m_size = IntSize(width, height);
- }
- }
-
bool outputScanlines();
void jpegComplete();
private:
- mutable JPEGImageReader* m_reader;
+ JPEGImageReader* m_reader;
};
} // namespace WebCore
diff --git a/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp b/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp
index dead8ca..d14333f 100644
--- a/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp
+++ b/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp
@@ -40,11 +40,6 @@
#include "png.h"
#include "assert.h"
-#if COMPILER(MSVC)
-// Remove warnings from warning level 4.
-#pragma warning(disable : 4611) // warning C4611: interaction between '_setjmp' and C++ object destruction is non-portable
-#endif // COMPILER(MSVC)
-
namespace WebCore {
// Gamma constants.
@@ -143,7 +138,6 @@ private:
PNGImageDecoder::PNGImageDecoder()
: m_reader(0)
{
- m_frameBufferCache.resize(1);
}
PNGImageDecoder::~PNGImageDecoder()
@@ -166,19 +160,12 @@ void PNGImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
}
// Whether or not the size information has been decoded yet.
-bool PNGImageDecoder::isSizeAvailable() const
+bool PNGImageDecoder::isSizeAvailable()
{
- // If we have pending data to decode, send it to the PNG reader now.
- if (!m_sizeAvailable && m_reader) {
- if (m_failed)
- return false;
-
- // The decoder will go ahead and aggressively consume everything up until the
- // size is encountered.
- decode(true);
- }
+ if (!ImageDecoder::isSizeAvailable() && !failed() && m_reader)
+ decode(true);
- return m_sizeAvailable;
+ return ImageDecoder::isSizeAvailable();
}
RGBA32Buffer* PNGImageDecoder::frameBufferAtIndex(size_t index)
@@ -186,6 +173,9 @@ RGBA32Buffer* PNGImageDecoder::frameBufferAtIndex(size_t index)
if (index)
return 0;
+ if (m_frameBufferCache.isEmpty())
+ m_frameBufferCache.resize(1);
+
RGBA32Buffer& frame = m_frameBufferCache[0];
if (frame.status() != RGBA32Buffer::FrameComplete && m_reader)
// Decode this frame.
@@ -194,14 +184,14 @@ RGBA32Buffer* PNGImageDecoder::frameBufferAtIndex(size_t index)
}
// Feed data to the PNG reader.
-void PNGImageDecoder::decode(bool sizeOnly) const
+void PNGImageDecoder::decode(bool sizeOnly)
{
if (m_failed)
return;
m_reader->decode(m_data->buffer(), sizeOnly);
- if (m_failed || (m_frameBufferCache[0].status() == RGBA32Buffer::FrameComplete)) {
+ if (m_failed || (!m_frameBufferCache.isEmpty() && m_frameBufferCache[0].status() == RGBA32Buffer::FrameComplete)) {
delete m_reader;
m_reader = 0;
}
@@ -226,7 +216,8 @@ void headerAvailable(png_structp png, png_infop info)
static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png))->headerAvailable();
}
-void PNGImageDecoder::decodingFailed() {
+void PNGImageDecoder::decodingFailed()
+{
m_failed = true;
}
@@ -245,9 +236,12 @@ void PNGImageDecoder::headerAvailable()
}
// We can fill in the size now that the header is available.
- if (!m_sizeAvailable) {
- m_sizeAvailable = true;
- m_size = IntSize(width, height);
+ if (!ImageDecoder::isSizeAvailable()) {
+ if (!setSize(width, height)) {
+ // Size unreasonable, bail out.
+ longjmp(png->jmpbuf, 1);
+ return;
+ }
}
int bitDepth, colorType, interlaceType, compressionType, filterType, channels;
@@ -313,18 +307,22 @@ void rowAvailable(png_structp png, png_bytep rowBuffer,
void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex, int interlacePass)
{
- // Resize to the width and height of the image.
+ if (m_frameBufferCache.isEmpty())
+ return;
+
+ // Initialize the framebuffer if needed.
RGBA32Buffer& buffer = m_frameBufferCache[0];
if (buffer.status() == RGBA32Buffer::FrameEmpty) {
- // Let's resize our buffer now to the correct width/height.
- RGBA32Array& bytes = buffer.bytes();
- bytes.resize(size().width() * size().height());
-
- // Update our status to be partially complete.
+ if (!buffer.setSize(size().width(), size().height())) {
+ static_cast<PNGImageDecoder*>(png_get_progressive_ptr(reader()->pngPtr()))->decodingFailed();
+ longjmp(reader()->pngPtr()->jmpbuf, 1);
+ return;
+ }
buffer.setStatus(RGBA32Buffer::FramePartial);
+ buffer.setHasAlpha(false);
// For PNGs, the frame always fills the entire image.
- buffer.setRect(IntRect(0, 0, size().width(), size().height()));
+ buffer.setRect(IntRect(IntPoint(), size()));
if (reader()->pngPtr()->interlaced)
reader()->createInterlaceBuffer((reader()->hasAlpha() ? 4 : 3) * size().width() * size().height());
@@ -375,21 +373,18 @@ void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex,
// Copy the data into our buffer.
int width = size().width();
- unsigned* dst = buffer.bytes().data() + rowIndex * width;
bool sawAlpha = false;
for (int x = 0; x < width; x++) {
unsigned red = *row++;
unsigned green = *row++;
unsigned blue = *row++;
unsigned alpha = (hasAlpha ? *row++ : 255);
- RGBA32Buffer::setRGBA(*dst++, red, green, blue, alpha);
+ buffer.setRGBA(x, rowIndex, red, green, blue, alpha);
if (!sawAlpha && alpha < 255) {
sawAlpha = true;
buffer.setHasAlpha(true);
}
}
-
- buffer.ensureHeight(rowIndex + 1);
}
void pngComplete(png_structp png, png_infop info)
@@ -399,6 +394,9 @@ void pngComplete(png_structp png, png_infop info)
void PNGImageDecoder::pngComplete()
{
+ if (m_frameBufferCache.isEmpty())
+ return;
+
// Hand back an appropriately sized buffer, even if the image ended up being empty.
RGBA32Buffer& buffer = m_frameBufferCache[0];
buffer.setStatus(RGBA32Buffer::FrameComplete);
diff --git a/WebCore/platform/image-decoders/png/PNGImageDecoder.h b/WebCore/platform/image-decoders/png/PNGImageDecoder.h
index c5264fd..3c0535b 100644
--- a/WebCore/platform/image-decoders/png/PNGImageDecoder.h
+++ b/WebCore/platform/image-decoders/png/PNGImageDecoder.h
@@ -44,11 +44,11 @@ namespace WebCore {
virtual void setData(SharedBuffer* data, bool allDataReceived);
// Whether or not the size information has been decoded yet.
- virtual bool isSizeAvailable() const;
+ virtual bool isSizeAvailable();
virtual RGBA32Buffer* frameBufferAtIndex(size_t index);
- void decode(bool sizeOnly = false) const;
+ void decode(bool sizeOnly = false);
PNGImageReader* reader() { return m_reader; }
@@ -59,7 +59,7 @@ namespace WebCore {
void pngComplete();
private:
- mutable PNGImageReader* m_reader;
+ PNGImageReader* m_reader;
};
} // namespace WebCore
diff --git a/WebCore/platform/image-decoders/skia/BMPImageDecoder.cpp b/WebCore/platform/image-decoders/skia/BMPImageDecoder.cpp
deleted file mode 100644
index 08d5df5..0000000
--- a/WebCore/platform/image-decoders/skia/BMPImageDecoder.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * 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.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 THE COPYRIGHT
- * OWNER 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.
- */
-
-#include "config.h"
-#include "BMPImageDecoder.h"
-
-namespace WebCore {
-
-// Number of bits in .BMP used to store the file header (doesn't match
-// "sizeof(BMPImageDecoder::BitmapFileHeader)" since we omit some fields and
-// don't pack).
-static const size_t sizeOfFileHeader = 14;
-
-void BMPImageDecoder::decodeImage(SharedBuffer* data)
-{
- // Read and process file header.
- if ((m_decodedOffset < sizeOfFileHeader) && !processFileHeader(data))
- return;
-
- // Decode BMP.
- decodeBMP(data);
-}
-
-bool BMPImageDecoder::processFileHeader(SharedBuffer* data)
-{
- // Read file header.
- ASSERT(!m_decodedOffset);
- if (data->size() < sizeOfFileHeader)
- return false;
- const uint16_t fileType =
- (data->data()[0] << 8) | static_cast<uint8_t>(data->data()[1]);
- m_imgDataOffset = readUint32(data, 10);
- m_decodedOffset = m_headerOffset = sizeOfFileHeader;
-
- // See if this is a bitmap filetype we understand.
- enum {
- BMAP = 'BM',
- // The following additional OS/2 2.x header values (see
- // http://www.fileformat.info/format/os2bmp/egff.htm ) aren't widely
- // decoded, and are unlikely to be in much use.
- /*
- ICON = 'IC',
- POINTER = 'PT',
- COLORICON = 'CI',
- COLORPOINTER = 'CP',
- BITMAPARRAY = 'BA',
- */
- };
- if (fileType != BMAP)
- m_failed = true;
-
- return !m_failed;
-}
-
-} // namespace WebCore
diff --git a/WebCore/platform/image-decoders/skia/BMPImageDecoder.h b/WebCore/platform/image-decoders/skia/BMPImageDecoder.h
deleted file mode 100644
index 065981f..0000000
--- a/WebCore/platform/image-decoders/skia/BMPImageDecoder.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * 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.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 THE COPYRIGHT
- * OWNER 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 BMPImageDecoder_h
-#define BMPImageDecoder_h
-
-#include "BMPImageReader.h"
-
-namespace WebCore {
-
- // This class decodes the BMP image format.
- class BMPImageDecoder : public BMPImageReader {
- public:
- virtual String filenameExtension() const { return "bmp"; }
-
- // BMPImageReader
- virtual void decodeImage(SharedBuffer*);
-
- private:
- // Processes the file header at the beginning of the data. Returns true if
- // the file header could be decoded.
- bool processFileHeader(SharedBuffer*);
- };
-
-} // namespace WebCore
-
-#endif
diff --git a/WebCore/platform/image-decoders/skia/GIFImageDecoder.cpp b/WebCore/platform/image-decoders/skia/GIFImageDecoder.cpp
deleted file mode 100644
index c03452a..0000000
--- a/WebCore/platform/image-decoders/skia/GIFImageDecoder.cpp
+++ /dev/null
@@ -1,493 +0,0 @@
-/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- * Copyright (C) 2008, 2009 Google, Inc.
- *
- * 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.
- */
-
-#include "config.h"
-#include "GIFImageDecoder.h"
-#include "GIFImageReader.h"
-
-namespace WebCore {
-
-class GIFImageDecoderPrivate {
-public:
- GIFImageDecoderPrivate(GIFImageDecoder* decoder = 0)
- : m_reader(decoder)
- , m_readOffset(0)
- {
- }
-
- ~GIFImageDecoderPrivate()
- {
- m_reader.close();
- }
-
- bool decode(SharedBuffer* data,
- GIFImageDecoder::GIFQuery query = GIFImageDecoder::GIFFullQuery,
- unsigned int haltFrame = -1)
- {
- return m_reader.read((const unsigned char*)data->data() + m_readOffset, data->size() - m_readOffset,
- query,
- haltFrame);
- }
-
- unsigned frameCount() const { return m_reader.images_count; }
- int repetitionCount() const { return m_reader.loop_count; }
-
- void setReadOffset(unsigned o) { m_readOffset = o; }
-
- bool isTransparent() const { return m_reader.frame_reader->is_transparent; }
-
- void getColorMap(unsigned char*& map, unsigned& size) const
- {
- if (m_reader.frame_reader->is_local_colormap_defined) {
- map = m_reader.frame_reader->local_colormap;
- size = (unsigned)m_reader.frame_reader->local_colormap_size;
- } else {
- map = m_reader.global_colormap;
- size = m_reader.global_colormap_size;
- }
- }
-
- unsigned frameXOffset() const { return m_reader.frame_reader->x_offset; }
- unsigned frameYOffset() const { return m_reader.frame_reader->y_offset; }
- unsigned frameWidth() const { return m_reader.frame_reader->width; }
- unsigned frameHeight() const { return m_reader.frame_reader->height; }
-
- int transparentPixel() const { return m_reader.frame_reader->tpixel; }
-
- unsigned duration() const { return m_reader.frame_reader->delay_time; }
-
-private:
- GIFImageReader m_reader;
- unsigned m_readOffset;
-};
-
-GIFImageDecoder::GIFImageDecoder()
- : m_frameCountValid(true)
- , m_repetitionCount(cAnimationLoopOnce)
- , m_reader(0)
-{
-}
-
-GIFImageDecoder::~GIFImageDecoder()
-{
- delete m_reader;
-}
-
-// Take the data and store it.
-void GIFImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
-{
- if (m_failed)
- return;
-
- // Cache our new data.
- ImageDecoder::setData(data, allDataReceived);
-
- // Our frame count is now unknown.
- m_frameCountValid = false;
-
- // Create the GIF reader.
- if (!m_reader && !m_failed)
- m_reader = new GIFImageDecoderPrivate(this);
-}
-
-// Whether or not the size information has been decoded yet.
-bool GIFImageDecoder::isSizeAvailable() const
-{
- // If we have pending data to decode, send it to the GIF reader now.
- if (!ImageDecoder::isSizeAvailable() && m_reader) {
- if (m_failed)
- return false;
-
- // The decoder will go ahead and aggressively consume everything up until the first
- // size is encountered.
- decode(GIFSizeQuery, 0);
- }
-
- return ImageDecoder::isSizeAvailable();
-}
-
-// The total number of frames for the image. Will scan the image data for the answer
-// (without necessarily decoding all of the individual frames).
-int GIFImageDecoder::frameCount()
-{
- // If the decoder had an earlier error, we will just return what we had decoded
- // so far.
- if (!m_frameCountValid) {
- // FIXME: Scanning all the data has O(n^2) behavior if the data were to come in really
- // slowly. Might be interesting to try to clone our existing read session to preserve
- // state, but for now we just crawl all the data. Note that this is no worse than what
- // ImageIO does on Mac right now (it also crawls all the data again).
- GIFImageDecoderPrivate reader;
- // This function may fail, but we want to keep any partial data it may
- // have decoded, so don't mark it is invalid. If there is an overflow
- // or some serious error, m_failed will have gotten set for us.
- reader.decode(m_data.get(), GIFFrameCountQuery);
- m_frameCountValid = true;
- m_frameBufferCache.resize(reader.frameCount());
- }
-
- return m_frameBufferCache.size();
-}
-
-// The number of repetitions to perform for an animation loop.
-int GIFImageDecoder::repetitionCount() const
-{
- // This value can arrive at any point in the image data stream. Most GIFs
- // in the wild declare it near the beginning of the file, so it usually is
- // set by the time we've decoded the size, but (depending on the GIF and the
- // packets sent back by the webserver) not always. Our caller is
- // responsible for waiting until image decoding has finished to ask this if
- // it needs an authoritative answer. In the meantime, we should default to
- // "loop once".
- if (m_reader) {
- // Added wrinkle: ImageSource::clear() may destroy the reader, making
- // the result from the reader _less_ authoritative on future calls. To
- // detect this, the reader returns cLoopCountNotSeen (-2) instead of
- // cAnimationLoopOnce (-1) when its current incarnation hasn't actually
- // seen a loop count yet; in this case we return our previously-cached
- // value.
- const int repetitionCount = m_reader->repetitionCount();
- if (repetitionCount != cLoopCountNotSeen)
- m_repetitionCount = repetitionCount;
- }
- return m_repetitionCount;
-}
-
-RGBA32Buffer* GIFImageDecoder::frameBufferAtIndex(size_t index)
-{
- if (index >= static_cast<size_t>(frameCount()))
- return 0;
-
- RGBA32Buffer& frame = m_frameBufferCache[index];
- if (frame.status() != RGBA32Buffer::FrameComplete && m_reader)
- decode(GIFFullQuery, index + 1); // Decode this frame.
- return &frame;
-}
-
-void GIFImageDecoder::clearFrameBufferCache(size_t clearBeforeFrame)
-{
- // In some cases, like if the decoder was destroyed while animating, we
- // can be asked to clear more frames than we currently have.
- if (m_frameBufferCache.isEmpty())
- return; // Nothing to do.
-
- // The "-1" here is tricky. It does not mean that |clearBeforeFrame| is the
- // last frame we wish to preserve, but rather that we never want to clear
- // the very last frame in the cache: it's empty (so clearing it is
- // pointless), it's partial (so we don't want to clear it anyway), or the
- // cache could be enlarged with a future setData() call and it could be
- // needed to construct the next frame (see comments below). Callers can
- // always use ImageSource::clear(true, ...) to completely free the memory in
- // this case.
- clearBeforeFrame = std::min(clearBeforeFrame, m_frameBufferCache.size() - 1);
- const Vector<RGBA32Buffer>::iterator end(m_frameBufferCache.begin() + clearBeforeFrame);
-
- // We need to preserve frames such that:
- // * We don't clear |end|
- // * We don't clear the frame we're currently decoding
- // * We don't clear any frame from which a future initFrameBuffer() call
- // will copy bitmap data
- // All other frames can be cleared. Because of the constraints on when
- // ImageSource::clear() can be called (see ImageSource.h), we're guaranteed
- // not to have non-empty frames after the frame we're currently decoding.
- // So, scan backwards from |end| as follows:
- // * If the frame is empty, we're still past any frames we care about.
- // * If the frame is complete, but is DisposeOverwritePrevious, we'll
- // skip over it in future initFrameBuffer() calls. We can clear it
- // unless it's |end|, and keep scanning. For any other disposal method,
- // stop scanning, as we've found the frame initFrameBuffer() will need
- // next.
- // * If the frame is partial, we're decoding it, so don't clear it; if it
- // has a disposal method other than DisposeOverwritePrevious, stop
- // scanning, as we'll only need this frame when decoding the next one.
- Vector<RGBA32Buffer>::iterator i(end);
- for (; (i != m_frameBufferCache.begin()) && ((i->status() == RGBA32Buffer::FrameEmpty) || (i->disposalMethod() == RGBA32Buffer::DisposeOverwritePrevious)); --i) {
- if ((i->status() == RGBA32Buffer::FrameComplete) && (i != end))
- i->clear();
- }
-
- // Now |i| holds the last frame we need to preserve; clear prior frames.
- for (Vector<RGBA32Buffer>::iterator j(m_frameBufferCache.begin()); j != i; ++j) {
- ASSERT(j->status() != RGBA32Buffer::FramePartial);
- if (j->status() != RGBA32Buffer::FrameEmpty)
- j->clear();
- }
-}
-
-// Feed data to the GIF reader.
-void GIFImageDecoder::decode(GIFQuery query, unsigned haltAtFrame) const
-{
- if (m_failed)
- return;
-
- m_failed = !m_reader->decode(m_data.get(), query, haltAtFrame);
-
- if (m_failed) {
- delete m_reader;
- m_reader = 0;
- }
-}
-
-// Callbacks from the GIF reader.
-bool GIFImageDecoder::sizeNowAvailable(unsigned width, unsigned height)
-{
- return setSize(width, height);
-}
-
-void GIFImageDecoder::decodingHalted(unsigned bytesLeft)
-{
- m_reader->setReadOffset(m_data->size() - bytesLeft);
-}
-
-bool GIFImageDecoder::initFrameBuffer(unsigned frameIndex)
-{
- // Initialize the frame rect in our buffer.
- IntRect frameRect(m_reader->frameXOffset(), m_reader->frameYOffset(),
- m_reader->frameWidth(), m_reader->frameHeight());
-
- // Make sure the frameRect doesn't extend past the bottom-right of the buffer.
- if (frameRect.right() > size().width())
- frameRect.setWidth(size().width() - m_reader->frameXOffset());
- if (frameRect.bottom() > size().height())
- frameRect.setHeight(size().height() - m_reader->frameYOffset());
-
- RGBA32Buffer* const buffer = &m_frameBufferCache[frameIndex];
- buffer->setRect(frameRect);
-
- if (frameIndex == 0) {
- // This is the first frame, so we're not relying on any previous data.
- if (!prepEmptyFrameBuffer(buffer)) {
- buffer->setStatus(RGBA32Buffer::FrameComplete);
- m_failed = true;
- return false;
- }
- } else {
- // The starting state for this frame depends on the previous frame's
- // disposal method.
- //
- // Frames that use the DisposeOverwritePrevious method are effectively
- // no-ops in terms of changing the starting state of a frame compared to
- // the starting state of the previous frame, so skip over them. (If the
- // first frame specifies this method, it will get treated like
- // DisposeOverwriteBgcolor below and reset to a completely empty image.)
- const RGBA32Buffer* prevBuffer = &m_frameBufferCache[--frameIndex];
- RGBA32Buffer::FrameDisposalMethod prevMethod =
- prevBuffer->disposalMethod();
- while ((frameIndex > 0)
- && (prevMethod == RGBA32Buffer::DisposeOverwritePrevious)) {
- prevBuffer = &m_frameBufferCache[--frameIndex];
- prevMethod = prevBuffer->disposalMethod();
- }
- ASSERT(prevBuffer->status() == RGBA32Buffer::FrameComplete);
-
- if ((prevMethod == RGBA32Buffer::DisposeNotSpecified) ||
- (prevMethod == RGBA32Buffer::DisposeKeep)) {
- // Preserve the last frame as the starting state for this frame.
- buffer->copyBitmapData(*prevBuffer);
- // This next line isn't currently necessary since the alpha state is
- // currently carried along in the Skia bitmap data, but it's safe,
- // future-proof, and parallel to the Cairo code.
- buffer->setHasAlpha(prevBuffer->hasAlpha());
- } else {
- // We want to clear the previous frame to transparent, without
- // affecting pixels in the image outside of the frame.
- const IntRect& prevRect = prevBuffer->rect();
- if ((frameIndex == 0)
- || prevRect.contains(IntRect(IntPoint(0, 0), size()))) {
- // Clearing the first frame, or a frame the size of the whole
- // image, results in a completely empty image.
- prepEmptyFrameBuffer(buffer);
- } else {
- // Copy the whole previous buffer, then clear just its frame.
- buffer->copyBitmapData(*prevBuffer);
- // Unnecessary (but safe); see comments on the similar call above.
- buffer->setHasAlpha(prevBuffer->hasAlpha());
- SkBitmap& bitmap = buffer->bitmap();
-#ifdef ANDROID_ANIMATED_GIF
- SkAutoLockPixels alp(bitmap);
-#endif
- for (int y = prevRect.y(); y < prevRect.bottom(); ++y) {
- for (int x = prevRect.x(); x < prevRect.right(); ++x)
- buffer->setRGBA(bitmap.getAddr32(x, y), 0, 0, 0, 0);
- }
- if ((prevRect.width() > 0) && (prevRect.height() > 0))
- buffer->setHasAlpha(true);
- }
- }
- }
-
- // Update our status to be partially complete.
- buffer->setStatus(RGBA32Buffer::FramePartial);
-
- // Reset the alpha pixel tracker for this frame.
- m_currentBufferSawAlpha = false;
- return true;
-}
-
-bool GIFImageDecoder::prepEmptyFrameBuffer(RGBA32Buffer* buffer) const
-{
- if (!buffer->setSize(size().width(), size().height()))
- return false;
- // This next line isn't currently necessary since Skia's eraseARGB() sets
- // this for us, but we do it for similar reasons to the setHasAlpha() calls
- // in initFrameBuffer() above.
- buffer->setHasAlpha(true);
- return true;
-}
-
-void GIFImageDecoder::haveDecodedRow(unsigned frameIndex,
- unsigned char* rowBuffer, // Pointer to single scanline temporary buffer
- unsigned char* rowEnd,
- unsigned rowNumber, // The row index
- unsigned repeatCount, // How many times to repeat the row
- bool writeTransparentPixels)
-{
- // Initialize the frame if necessary.
- RGBA32Buffer& buffer = m_frameBufferCache[frameIndex];
- if ((buffer.status() == RGBA32Buffer::FrameEmpty) && !initFrameBuffer(frameIndex))
- return;
-
- // Do nothing for bogus data.
- if (rowBuffer == 0 || static_cast<int>(m_reader->frameYOffset() + rowNumber) >= size().height())
- return;
-
- unsigned colorMapSize;
- unsigned char* colorMap;
- m_reader->getColorMap(colorMap, colorMapSize);
- if (!colorMap)
- return;
-
-#ifdef ANDROID_ANIMATED_GIF
- // Lock the pixels properly. Should be submitted back to webkit.
- SkAutoLockPixels alp(buffer.bitmap());
-#endif
- // The buffers that we draw are the entire image's width and height, so a final output frame is
- // width * height RGBA32 values in size.
- //
- // A single GIF frame, however, can be smaller than the entire image, i.e., it can represent some sub-rectangle
- // within the overall image. The rows we are decoding are within this
- // sub-rectangle. This means that if the GIF frame's sub-rectangle is (x,y,w,h) then row 0 is really row
- // y, and each row goes from x to x+w.
- unsigned dstPos = (m_reader->frameYOffset() + rowNumber) * size().width() + m_reader->frameXOffset();
- unsigned* dst = buffer.bitmap().getAddr32(0, 0) + dstPos;
- unsigned* dstEnd = dst + size().width() - m_reader->frameXOffset();
- unsigned* currDst = dst;
- unsigned char* currentRowByte = rowBuffer;
-
- while (currentRowByte != rowEnd && currDst < dstEnd) {
- if ((!m_reader->isTransparent() || *currentRowByte != m_reader->transparentPixel()) && *currentRowByte < colorMapSize) {
- unsigned colorIndex = *currentRowByte * 3;
- unsigned red = colorMap[colorIndex];
- unsigned green = colorMap[colorIndex + 1];
- unsigned blue = colorMap[colorIndex + 2];
- RGBA32Buffer::setRGBA(currDst, red, green, blue, 255);
- } else {
- m_currentBufferSawAlpha = true;
- // We may or may not need to write transparent pixels to the buffer.
- // If we're compositing against a previous image, it's wrong, and if
- // we're writing atop a cleared, fully transparent buffer, it's
- // unnecessary; but if we're decoding an interlaced gif and
- // displaying it "Haeberli"-style, we must write these for passes
- // beyond the first, or the initial passes will "show through" the
- // later ones.
- if (writeTransparentPixels)
- RGBA32Buffer::setRGBA(currDst, 0, 0, 0, 0);
- }
- currDst++;
- currentRowByte++;
- }
-
- if (repeatCount > 1) {
- // Copy the row |repeatCount|-1 times.
- unsigned num = currDst - dst;
- unsigned data_size = num * sizeof(unsigned);
- unsigned width = size().width();
- unsigned* end = buffer.bitmap().getAddr32(0, 0) + width * size().height();
- currDst = dst + width;
- for (unsigned i = 1; i < repeatCount; i++) {
- if (currDst + num > end) // Protect against a buffer overrun from a bogus repeatCount.
- break;
- memcpy(currDst, dst, data_size);
- currDst += width;
- }
- }
-}
-
-void GIFImageDecoder::frameComplete(unsigned frameIndex, unsigned frameDuration, RGBA32Buffer::FrameDisposalMethod disposalMethod)
-{
- // Initialize the frame if necessary. Some GIFs insert do-nothing frames,
- // in which case we never reach haveDecodedRow() before getting here.
- RGBA32Buffer& buffer = m_frameBufferCache[frameIndex];
- if ((buffer.status() == RGBA32Buffer::FrameEmpty) && !initFrameBuffer(frameIndex))
- return;
-
- buffer.setStatus(RGBA32Buffer::FrameComplete);
- buffer.setDuration(frameDuration);
- buffer.setDisposalMethod(disposalMethod);
-
- if (!m_currentBufferSawAlpha) {
- // The whole frame was non-transparent, so it's possible that the entire
- // resulting buffer was non-transparent, and we can setHasAlpha(false).
- if (buffer.rect().contains(IntRect(IntPoint(0, 0), size())))
- buffer.setHasAlpha(false);
- else if (frameIndex > 0) {
- // Tricky case. This frame does not have alpha only if everywhere
- // outside its rect doesn't have alpha. To know whether this is
- // true, we check the start state of the frame -- if it doesn't have
- // alpha, we're safe.
- //
- // First skip over prior DisposeOverwritePrevious frames (since they
- // don't affect the start state of this frame) the same way we do in
- // initFrameBuffer().
- const RGBA32Buffer* prevBuffer = &m_frameBufferCache[--frameIndex];
- while ((frameIndex > 0)
- && (prevBuffer->disposalMethod() == RGBA32Buffer::DisposeOverwritePrevious))
- prevBuffer = &m_frameBufferCache[--frameIndex];
-
- // Now, if we're at a DisposeNotSpecified or DisposeKeep frame, then
- // we can say we have no alpha if that frame had no alpha. But
- // since in initFrameBuffer() we already copied that frame's alpha
- // state into the current frame's, we need do nothing at all here.
- //
- // The only remaining case is a DisposeOverwriteBgcolor frame. If
- // it had no alpha, and its rect is contained in the current frame's
- // rect, we know the current frame has no alpha.
- if ((prevBuffer->disposalMethod() == RGBA32Buffer::DisposeOverwriteBgcolor)
- && !prevBuffer->hasAlpha() && buffer.rect().contains(prevBuffer->rect()))
- buffer.setHasAlpha(false);
- }
- }
-}
-
-void GIFImageDecoder::gifComplete()
-{
- if (m_reader)
- m_repetitionCount = m_reader->repetitionCount();
- delete m_reader;
- m_reader = 0;
-}
-
-} // namespace WebCore
diff --git a/WebCore/platform/image-decoders/skia/GIFImageDecoder.h b/WebCore/platform/image-decoders/skia/GIFImageDecoder.h
deleted file mode 100644
index d234a76..0000000
--- a/WebCore/platform/image-decoders/skia/GIFImageDecoder.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- * Copyright (C) 2008, 2009 Google, Inc.
- *
- * 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 GIFImageDecoder_h
-#define GIFImageDecoder_h
-
-#include "ImageDecoder.h"
-
-namespace WebCore {
-
- class GIFImageDecoderPrivate;
-
- // This class decodes the GIF image format.
- class GIFImageDecoder : public ImageDecoder {
- public:
- GIFImageDecoder();
- ~GIFImageDecoder();
-
- virtual String filenameExtension() const { return "gif"; }
-
- // Take the data and store it.
- virtual void setData(SharedBuffer* data, bool allDataReceived);
-
- // Whether or not the size information has been decoded yet.
- virtual bool isSizeAvailable() const;
-
- // The total number of frames for the image. Will scan the image data for the answer
- // (without necessarily decoding all of the individual frames).
- virtual int frameCount();
-
- // The number of repetitions to perform for an animation loop.
- virtual int repetitionCount() const;
-
- virtual RGBA32Buffer* frameBufferAtIndex(size_t index);
-
- virtual void clearFrameBufferCache(size_t clearBeforeFrame);
-
- virtual unsigned frameDurationAtIndex(size_t index) { return 0; }
-
- enum GIFQuery { GIFFullQuery, GIFSizeQuery, GIFFrameCountQuery };
-
- void decode(GIFQuery, unsigned haltAtFrame) const;
-
- // Callbacks from the GIF reader.
- bool sizeNowAvailable(unsigned width, unsigned height);
- void decodingHalted(unsigned bytesLeft);
- void haveDecodedRow(unsigned frameIndex, unsigned char* rowBuffer, unsigned char* rowEnd, unsigned rowNumber,
- unsigned repeatCount, bool writeTransparentPixels);
- void frameComplete(unsigned frameIndex, unsigned frameDuration, RGBA32Buffer::FrameDisposalMethod disposalMethod);
- void gifComplete();
-
- private:
- // Called to initialize the frame buffer with the given index, based on the
- // previous frame's disposal method. Returns true on success. On failure,
- // this will mark the image as failed.
- bool initFrameBuffer(unsigned frameIndex);
-
- // A helper for initFrameBuffer(), this sets the size of the buffer, and
- // fills it with transparent pixels.
- bool prepEmptyFrameBuffer(RGBA32Buffer*) const;
-
- bool m_frameCountValid;
- bool m_currentBufferSawAlpha;
- mutable int m_repetitionCount;
- mutable GIFImageDecoderPrivate* m_reader;
- };
-
-} // namespace WebCore
-
-#endif
diff --git a/WebCore/platform/image-decoders/skia/GIFImageReader.cpp b/WebCore/platform/image-decoders/skia/GIFImageReader.cpp
deleted file mode 100644
index 48df514..0000000
--- a/WebCore/platform/image-decoders/skia/GIFImageReader.cpp
+++ /dev/null
@@ -1,951 +0,0 @@
-/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Chris Saari <saari@netscape.com>
- * Apple Computer
- * Google, Inc.
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-/*
-The Graphics Interchange Format(c) is the copyright property of CompuServe
-Incorporated. Only CompuServe Incorporated is authorized to define, redefine,
-enhance, alter, modify or change in any way the definition of the format.
-
-CompuServe Incorporated hereby grants a limited, non-exclusive, royalty-free
-license for the use of the Graphics Interchange Format(sm) in computer
-software; computer software utilizing GIF(sm) must acknowledge ownership of the
-Graphics Interchange Format and its Service Mark by CompuServe Incorporated, in
-User and Technical Documentation. Computer software utilizing GIF, which is
-distributed or may be distributed without User or Technical Documentation must
-display to the screen or printer a message acknowledging ownership of the
-Graphics Interchange Format and the Service Mark by CompuServe Incorporated; in
-this case, the acknowledgement may be displayed in an opening screen or leading
-banner, or a closing screen or trailing banner. A message such as the following
-may be used:
-
- "The Graphics Interchange Format(c) is the Copyright property of
- CompuServe Incorporated. GIF(sm) is a Service Mark property of
- CompuServe Incorporated."
-
-For further information, please contact :
-
- CompuServe Incorporated
- Graphics Technology Department
- 5000 Arlington Center Boulevard
- Columbus, Ohio 43220
- U. S. A.
-
-CompuServe Incorporated maintains a mailing list with all those individuals and
-organizations who wish to receive copies of this document when it is corrected
-or revised. This service is offered free of charge; please provide us with your
-mailing address.
-*/
-
-#include "config.h"
-#include "GIFImageReader.h"
-
-#include <string.h>
-#include "GIFImageDecoder.h"
-
-using WebCore::GIFImageDecoder;
-
-// Define the Mozilla macro setup so that we can leave the macros alone.
-#define PR_BEGIN_MACRO do {
-#define PR_END_MACRO } while (0)
-
-/*
- * GETN(n, s) requests at least 'n' bytes available from 'q', at start of state 's'
- *
- * Note, the hold will never need to be bigger than 256 bytes to gather up in the hold,
- * as each GIF block (except colormaps) can never be bigger than 256 bytes.
- * Colormaps are directly copied in the resp. global_colormap or dynamically allocated local_colormap.
- * So a fixed buffer in GIFImageReader is good enough.
- * This buffer is only needed to copy left-over data from one GifWrite call to the next
- */
-#define GETN(n,s) \
- PR_BEGIN_MACRO \
- bytes_to_consume = (n); \
- state = (s); \
- PR_END_MACRO
-
-/* Get a 16-bit value stored in little-endian format */
-#define GETINT16(p) ((p)[1]<<8|(p)[0])
-
-//******************************************************************************
-// Send the data to the display front-end.
-void GIFImageReader::output_row()
-{
- GIFFrameReader* gs = frame_reader;
-
- int drow_start, drow_end;
-
- drow_start = drow_end = gs->irow;
-
- /*
- * Haeberli-inspired hack for interlaced GIFs: Replicate lines while
- * displaying to diminish the "venetian-blind" effect as the image is
- * loaded. Adjust pixel vertical positions to avoid the appearance of the
- * image crawling up the screen as successive passes are drawn.
- */
- if (gs->progressive_display && gs->interlaced && gs->ipass < 4) {
- unsigned row_dup = 0, row_shift = 0;
-
- switch (gs->ipass) {
- case 1:
- row_dup = 7;
- row_shift = 3;
- break;
- case 2:
- row_dup = 3;
- row_shift = 1;
- break;
- case 3:
- row_dup = 1;
- row_shift = 0;
- break;
- default:
- break;
- }
-
- drow_start -= row_shift;
- drow_end = drow_start + row_dup;
-
- /* Extend if bottom edge isn't covered because of the shift upward. */
- if (((gs->height - 1) - drow_end) <= row_shift)
- drow_end = gs->height - 1;
-
- /* Clamp first and last rows to upper and lower edge of image. */
- if (drow_start < 0)
- drow_start = 0;
- if ((unsigned)drow_end >= gs->height)
- drow_end = gs->height - 1;
- }
-
- /* Protect against too much image data */
- if ((unsigned)drow_start >= gs->height)
- return;
-
- // CALLBACK: Let the client know we have decoded a row.
- if (clientptr && frame_reader)
- clientptr->haveDecodedRow(images_count - 1, frame_reader->rowbuf, frame_reader->rowend,
- drow_start, drow_end - drow_start + 1,
- gs->progressive_display && gs->interlaced && gs->ipass > 1);
-
- gs->rowp = gs->rowbuf;
-
- if (!gs->interlaced)
- gs->irow++;
- else {
- do {
- switch (gs->ipass)
- {
- case 1:
- gs->irow += 8;
- if (gs->irow >= gs->height) {
- gs->ipass++;
- gs->irow = 4;
- }
- break;
-
- case 2:
- gs->irow += 8;
- if (gs->irow >= gs->height) {
- gs->ipass++;
- gs->irow = 2;
- }
- break;
-
- case 3:
- gs->irow += 4;
- if (gs->irow >= gs->height) {
- gs->ipass++;
- gs->irow = 1;
- }
- break;
-
- case 4:
- gs->irow += 2;
- if (gs->irow >= gs->height){
- gs->ipass++;
- gs->irow = 0;
- }
- break;
-
- default:
- break;
- }
- } while (gs->irow > (gs->height - 1));
- }
-}
-
-//******************************************************************************
-/* Perform Lempel-Ziv-Welch decoding */
-int GIFImageReader::do_lzw(const unsigned char *q)
-{
- GIFFrameReader* gs = frame_reader;
- if (!gs)
- return 0;
-
- int code;
- int incode;
- const unsigned char *ch;
-
- /* Copy all the decoder state variables into locals so the compiler
- * won't worry about them being aliased. The locals will be homed
- * back into the GIF decoder structure when we exit.
- */
- int avail = gs->avail;
- int bits = gs->bits;
- int cnt = count;
- int codesize = gs->codesize;
- int codemask = gs->codemask;
- int oldcode = gs->oldcode;
- int clear_code = gs->clear_code;
- unsigned char firstchar = gs->firstchar;
- int datum = gs->datum;
-
- if (!gs->prefix) {
- gs->prefix = new unsigned short[MAX_BITS];
- memset(gs->prefix, 0, MAX_BITS * sizeof(short));
- }
-
- unsigned short *prefix = gs->prefix;
- unsigned char *stackp = gs->stackp;
- unsigned char *suffix = gs->suffix;
- unsigned char *stack = gs->stack;
- unsigned char *rowp = gs->rowp;
- unsigned char *rowend = gs->rowend;
- unsigned rows_remaining = gs->rows_remaining;
-
- if (rowp == rowend)
- return 0;
-
-#define OUTPUT_ROW \
- PR_BEGIN_MACRO \
- output_row(); \
- rows_remaining--; \
- rowp = frame_reader->rowp; \
- if (!rows_remaining) \
- goto END; \
- PR_END_MACRO
-
- for (ch = q; cnt-- > 0; ch++)
- {
- /* Feed the next byte into the decoder's 32-bit input buffer. */
- datum += ((int) *ch) << bits;
- bits += 8;
-
- /* Check for underflow of decoder's 32-bit input buffer. */
- while (bits >= codesize)
- {
- /* Get the leading variable-length symbol from the data stream */
- code = datum & codemask;
- datum >>= codesize;
- bits -= codesize;
-
- /* Reset the dictionary to its original state, if requested */
- if (code == clear_code) {
- codesize = gs->datasize + 1;
- codemask = (1 << codesize) - 1;
- avail = clear_code + 2;
- oldcode = -1;
- continue;
- }
-
- /* Check for explicit end-of-stream code */
- if (code == (clear_code + 1)) {
- /* end-of-stream should only appear after all image data */
- if (rows_remaining != 0)
- return -1;
- return 0;
- }
-
- if (oldcode == -1) {
- *rowp++ = suffix[code];
- if (rowp == rowend)
- OUTPUT_ROW;
-
- firstchar = oldcode = code;
- continue;
- }
-
- incode = code;
- if (code >= avail) {
- *stackp++ = firstchar;
- code = oldcode;
-
- if (stackp == stack + MAX_BITS)
- return -1;
- }
-
- while (code >= clear_code)
- {
- if (code >= MAX_BITS || code == prefix[code])
- return -1;
-
- // Even though suffix[] only holds characters through suffix[avail - 1],
- // allowing code >= avail here lets us be more tolerant of malformed
- // data. As long as code < MAX_BITS, the only risk is a garbled image,
- // which is no worse than refusing to display it.
- *stackp++ = suffix[code];
- code = prefix[code];
-
- if (stackp == stack + MAX_BITS)
- return -1;
- }
-
- *stackp++ = firstchar = suffix[code];
-
- /* Define a new codeword in the dictionary. */
- if (avail < 4096) {
- prefix[avail] = oldcode;
- suffix[avail] = firstchar;
- avail++;
-
- /* If we've used up all the codewords of a given length
- * increase the length of codewords by one bit, but don't
- * exceed the specified maximum codeword size of 12 bits.
- */
- if (((avail & codemask) == 0) && (avail < 4096)) {
- codesize++;
- codemask += avail;
- }
- }
- oldcode = incode;
-
- /* Copy the decoded data out to the scanline buffer. */
- do {
- *rowp++ = *--stackp;
- if (rowp == rowend) {
- OUTPUT_ROW;
- }
- } while (stackp > stack);
- }
- }
-
- END:
-
- /* Home the local copies of the GIF decoder state variables */
- gs->avail = avail;
- gs->bits = bits;
- gs->codesize = codesize;
- gs->codemask = codemask;
- count = cnt;
- gs->oldcode = oldcode;
- gs->firstchar = firstchar;
- gs->datum = datum;
- gs->stackp = stackp;
- gs->rowp = rowp;
- gs->rows_remaining = rows_remaining;
-
- return 0;
-}
-
-
-/******************************************************************************/
-/*
- * process data arriving from the stream for the gif decoder
- */
-
-bool GIFImageReader::read(const unsigned char *buf, unsigned len,
- GIFImageDecoder::GIFQuery query, unsigned haltAtFrame)
-{
- if (!len) {
- // No new data has come in since the last call, just ignore this call.
- return true;
- }
-
- const unsigned char *q = buf;
-
- // Add what we have so far to the block
- // If previous call to me left something in the hold first complete current block
- // Or if we are filling the colormaps, first complete the colormap
- unsigned char* p = 0;
- if (state == gif_global_colormap)
- p = global_colormap;
- else if (state == gif_image_colormap)
- p = frame_reader ? frame_reader->local_colormap : 0;
- else if (bytes_in_hold)
- p = hold;
- else
- p = 0;
-
- if (p || (state == gif_global_colormap) || (state == gif_image_colormap)) {
- // Add what we have sofar to the block
- unsigned l = len < bytes_to_consume ? len : bytes_to_consume;
- if (p)
- memcpy(p + bytes_in_hold, buf, l);
-
- if (l < bytes_to_consume) {
- // Not enough in 'buf' to complete current block, get more
- bytes_in_hold += l;
- bytes_to_consume -= l;
- if (clientptr)
- clientptr->decodingHalted(0);
- return true;
- }
- // Reset hold buffer count
- bytes_in_hold = 0;
- // Point 'q' to complete block in hold (or in colormap)
- q = p;
- }
-
- // Invariant:
- // 'q' is start of current to be processed block (hold, colormap or buf)
- // 'bytes_to_consume' is number of bytes to consume from 'buf'
- // 'buf' points to the bytes to be consumed from the input buffer
- // 'len' is number of bytes left in input buffer from position 'buf'.
- // At entrance of the for loop will 'buf' will be moved 'bytes_to_consume'
- // to point to next buffer, 'len' is adjusted accordingly.
- // So that next round in for loop, q gets pointed to the next buffer.
-
- for (;len >= bytes_to_consume; q=buf) {
- // Eat the current block from the buffer, q keeps pointed at current block
- buf += bytes_to_consume;
- len -= bytes_to_consume;
-
- switch (state)
- {
- case gif_lzw:
- if (do_lzw(q) < 0) {
- state = gif_error;
- break;
- }
- GETN(1, gif_sub_block);
- break;
-
- case gif_lzw_start:
- {
- /* Initialize LZW parser/decoder */
- int datasize = *q;
- // Since we use a codesize of 1 more than the datasize, we need to ensure
- // that our datasize is strictly less than the MAX_LZW_BITS value (12).
- // This sets the largest possible codemask correctly at 4095.
- if (datasize >= MAX_LZW_BITS) {
- state = gif_error;
- break;
- }
- int clear_code = 1 << datasize;
- if (clear_code >= MAX_BITS) {
- state = gif_error;
- break;
- }
-
- if (frame_reader) {
- frame_reader->datasize = datasize;
- frame_reader->clear_code = clear_code;
- frame_reader->avail = frame_reader->clear_code + 2;
- frame_reader->oldcode = -1;
- frame_reader->codesize = frame_reader->datasize + 1;
- frame_reader->codemask = (1 << frame_reader->codesize) - 1;
-
- frame_reader->datum = frame_reader->bits = 0;
-
- /* init the tables */
- if (!frame_reader->suffix)
- frame_reader->suffix = new unsigned char[MAX_BITS];
- // Clearing the whole suffix table lets us be more tolerant of bad data.
- memset(frame_reader->suffix, 0, MAX_BITS);
- for (int i = 0; i < frame_reader->clear_code; i++)
- frame_reader->suffix[i] = i;
-
- if (!frame_reader->stack)
- frame_reader->stack = new unsigned char[MAX_BITS];
- frame_reader->stackp = frame_reader->stack;
- }
-
- GETN(1, gif_sub_block);
- }
- break;
-
- /* All GIF files begin with "GIF87a" or "GIF89a" */
- case gif_type:
- {
- if (!strncmp((char*)q, "GIF89a", 6)) {
- version = 89;
- } else if (!strncmp((char*)q, "GIF87a", 6)) {
- version = 87;
- } else {
- state = gif_error;
- break;
- }
- GETN(7, gif_global_header);
- }
- break;
-
- case gif_global_header:
- {
- /* This is the height and width of the "screen" or
- * frame into which images are rendered. The
- * individual images can be smaller than the
- * screen size and located with an origin anywhere
- * within the screen.
- */
-
- screen_width = GETINT16(q);
- screen_height = GETINT16(q + 2);
-
- // CALLBACK: Inform the decoderplugin of our size.
- if (clientptr) {
- if (!clientptr->sizeNowAvailable(screen_width, screen_height))
- return false;
- }
-
- screen_bgcolor = q[5];
- global_colormap_size = 2<<(q[4]&0x07);
-
- if ((q[4] & 0x80) && global_colormap_size > 0) { /* global map */
- // Get the global colormap
- const unsigned size = 3*global_colormap_size;
-
- // Malloc the color map, but only if we're not just counting frames.
- if (query != GIFImageDecoder::GIFFrameCountQuery)
- global_colormap = new unsigned char[size];
-
- if (len < size) {
- // Use 'hold' pattern to get the global colormap
- GETN(size, gif_global_colormap);
- break;
- }
-
- // Copy everything and go directly to gif_image_start.
- if (global_colormap)
- memcpy(global_colormap, buf, size);
- buf += size;
- len -= size;
- }
-
- GETN(1, gif_image_start);
-
- // q[6] = Pixel Aspect Ratio
- // Not used
- // float aspect = (float)((q[6] + 15) / 64.0);
- }
- break;
-
- case gif_global_colormap:
- // Everything is already copied into global_colormap
- GETN(1, gif_image_start);
- break;
-
- case gif_image_start:
- {
- if (*q == ';') { /* terminator */
- state = gif_done;
- break;
- }
-
- if (*q == '!') { /* extension */
- GETN(2, gif_extension);
- break;
- }
-
- /* If we get anything other than ',' (image separator), '!'
- * (extension), or ';' (trailer), there is extraneous data
- * between blocks. The GIF87a spec tells us to keep reading
- * until we find an image separator, but GIF89a says such
- * a file is corrupt. We follow GIF89a and bail out. */
- if (*q != ',') {
- if (images_decoded > 0) {
- /* The file is corrupt, but one or more images have
- * been decoded correctly. In this case, we proceed
- * as if the file were correctly terminated and set
- * the state to gif_done, so the GIF will display.
- */
- state = gif_done;
- } else {
- /* No images decoded, there is nothing to display. */
- state = gif_error;
- }
- break;
- } else
- GETN(9, gif_image_header);
- }
- break;
-
- case gif_extension:
- {
- int len = count = q[1];
- gstate es = gif_skip_block;
-
- switch (*q)
- {
- case 0xf9:
- es = gif_control_extension;
- break;
-
- case 0x01:
- // ignoring plain text extension
- break;
-
- case 0xff:
- es = gif_application_extension;
- break;
-
- case 0xfe:
- es = gif_consume_comment;
- break;
- }
-
- if (len)
- GETN(len, es);
- else
- GETN(1, gif_image_start);
- }
- break;
-
- case gif_consume_block:
- if (!*q)
- GETN(1, gif_image_start);
- else
- GETN(*q, gif_skip_block);
- break;
-
- case gif_skip_block:
- GETN(1, gif_consume_block);
- break;
-
- case gif_control_extension:
- {
- if (query != GIFImageDecoder::GIFFrameCountQuery) {
- if (!frame_reader)
- frame_reader = new GIFFrameReader();
- }
-
- if (frame_reader) {
- if (*q & 0x1) {
- frame_reader->tpixel = q[3];
- frame_reader->is_transparent = true;
- } else {
- frame_reader->is_transparent = false;
- // ignoring gfx control extension
- }
- // NOTE: This relies on the values in the FrameDisposalMethod enum
- // matching those in the GIF spec!
- frame_reader->disposal_method = (WebCore::RGBA32Buffer::FrameDisposalMethod)(((*q) >> 2) & 0x7);
- // Some specs say 3rd bit (value 4), other specs say value 3
- // Let's choose 3 (the more popular)
- if (frame_reader->disposal_method == 4)
- frame_reader->disposal_method = WebCore::RGBA32Buffer::DisposeOverwritePrevious;
- frame_reader->delay_time = GETINT16(q + 1) * 10;
- }
- GETN(1, gif_consume_block);
- }
- break;
-
- case gif_comment_extension:
- {
- if (*q)
- GETN(*q, gif_consume_comment);
- else
- GETN(1, gif_image_start);
- }
- break;
-
- case gif_consume_comment:
- GETN(1, gif_comment_extension);
- break;
-
- case gif_application_extension:
- /* Check for netscape application extension */
- if (!strncmp((char*)q, "NETSCAPE2.0", 11) ||
- !strncmp((char*)q, "ANIMEXTS1.0", 11))
- GETN(1, gif_netscape_extension_block);
- else
- GETN(1, gif_consume_block);
- break;
-
- /* Netscape-specific GIF extension: animation looping */
- case gif_netscape_extension_block:
- if (*q)
- GETN(*q, gif_consume_netscape_extension);
- else
- GETN(1, gif_image_start);
- break;
-
- /* Parse netscape-specific application extensions */
- case gif_consume_netscape_extension:
- {
- int netscape_extension = q[0] & 7;
-
- /* Loop entire animation specified # of times. Only read the
- loop count during the first iteration. */
- if (netscape_extension == 1) {
- loop_count = GETINT16(q + 1);
-
- GETN(1, gif_netscape_extension_block);
- }
- /* Wait for specified # of bytes to enter buffer */
- else if (netscape_extension == 2) {
- // Don't do this, this extension doesn't exist (isn't used at all)
- // and doesn't do anything, as our streaming/buffering takes care of it all...
- // See: http://semmix.pl/color/exgraf/eeg24.htm
- GETN(1, gif_netscape_extension_block);
- } else
- state = gif_error; // 0,3-7 are yet to be defined netscape
- // extension codes
-
- break;
- }
-
- case gif_image_header:
- {
- unsigned height, width, x_offset, y_offset;
-
- /* Get image offsets, with respect to the screen origin */
- x_offset = GETINT16(q);
- y_offset = GETINT16(q + 2);
-
- /* Get image width and height. */
- width = GETINT16(q + 4);
- height = GETINT16(q + 6);
-
- /* Work around broken GIF files where the logical screen
- * size has weird width or height. We assume that GIF87a
- * files don't contain animations.
- */
- if ((images_decoded == 0) &&
- ((screen_height < height) || (screen_width < width) ||
- (version == 87)))
- {
- screen_height = height;
- screen_width = width;
- x_offset = 0;
- y_offset = 0;
-
- // CALLBACK: Inform the decoderplugin of our size.
- if (clientptr)
- clientptr->sizeNowAvailable(screen_width, screen_height);
- }
-
- /* Work around more broken GIF files that have zero image
- width or height */
- if (!height || !width) {
- height = screen_height;
- width = screen_width;
- if (!height || !width) {
- state = gif_error;
- break;
- }
- }
-
- if (query == GIFImageDecoder::GIFSizeQuery || haltAtFrame == images_decoded) {
- // The decoder needs to stop. Hand back the number of bytes we consumed from
- // buffer minus 9 (the amount we consumed to read the header).
- if (clientptr)
- clientptr->decodingHalted(len + 9);
- GETN(9, gif_image_header);
- return true;
- }
-
- images_count = images_decoded + 1;
-
- if (query == GIFImageDecoder::GIFFullQuery && !frame_reader)
- frame_reader = new GIFFrameReader();
-
- if (frame_reader) {
- frame_reader->x_offset = x_offset;
- frame_reader->y_offset = y_offset;
- frame_reader->height = height;
- frame_reader->width = width;
-
- /* This case will never be taken if this is the first image */
- /* being decoded. If any of the later images are larger */
- /* than the screen size, we need to reallocate buffers. */
- if (screen_width < width) {
- /* XXX Deviant! */
-
- delete []frame_reader->rowbuf;
- screen_width = width;
- frame_reader->rowbuf = new unsigned char[screen_width];
- } else if (!frame_reader->rowbuf) {
- frame_reader->rowbuf = new unsigned char[screen_width];
- }
-
- if (!frame_reader->rowbuf) {
- state = gif_oom;
- break;
- }
- if (screen_height < height)
- screen_height = height;
-
- if (q[8] & 0x40) {
- frame_reader->interlaced = true;
- frame_reader->ipass = 1;
- } else {
- frame_reader->interlaced = false;
- frame_reader->ipass = 0;
- }
-
- if (images_decoded == 0) {
- frame_reader->progressive_display = true;
- } else {
- /* Overlaying interlaced, transparent GIFs over
- existing image data using the Haeberli display hack
- requires saving the underlying image in order to
- avoid jaggies at the transparency edges. We are
- unprepared to deal with that, so don't display such
- images progressively */
- frame_reader->progressive_display = false;
- }
-
- /* Clear state from last image */
- frame_reader->irow = 0;
- frame_reader->rows_remaining = frame_reader->height;
- frame_reader->rowend = frame_reader->rowbuf + frame_reader->width;
- frame_reader->rowp = frame_reader->rowbuf;
-
- /* bits per pixel is q[8]&0x07 */
- }
-
- if (q[8] & 0x80) /* has a local colormap? */
- {
- int num_colors = 2 << (q[8] & 0x7);
- const unsigned size = 3*num_colors;
- unsigned char *map = frame_reader ? frame_reader->local_colormap : 0;
- if (frame_reader && (!map || (num_colors > frame_reader->local_colormap_size))) {
- delete []map;
- map = new unsigned char[size];
- if (!map) {
- state = gif_oom;
- break;
- }
- }
-
- /* Switch to the new local palette after it loads */
- if (frame_reader) {
- frame_reader->local_colormap = map;
- frame_reader->local_colormap_size = num_colors;
- frame_reader->is_local_colormap_defined = true;
- }
-
- if (len < size) {
- // Use 'hold' pattern to get the image colormap
- GETN(size, gif_image_colormap);
- break;
- }
- // Copy everything and directly go to gif_lzw_start
- if (frame_reader)
- memcpy(frame_reader->local_colormap, buf, size);
- buf += size;
- len -= size;
- } else if (frame_reader) {
- /* Switch back to the global palette */
- frame_reader->is_local_colormap_defined = false;
- }
- GETN(1, gif_lzw_start);
- }
- break;
-
- case gif_image_colormap:
- // Everything is already copied into local_colormap
- GETN(1, gif_lzw_start);
- break;
-
- case gif_sub_block:
- {
- if ((count = *q) != 0)
- /* Still working on the same image: Process next LZW data block */
- {
- /* Make sure there are still rows left. If the GIF data */
- /* is corrupt, we may not get an explicit terminator. */
- if (frame_reader && frame_reader->rows_remaining == 0) {
- /* This is an illegal GIF, but we remain tolerant. */
- GETN(1, gif_sub_block);
- }
- GETN(count, gif_lzw);
- }
- else
- /* See if there are any more images in this sequence. */
- {
- images_decoded++;
-
- // CALLBACK: The frame is now complete.
- if (clientptr && frame_reader)
- clientptr->frameComplete(images_decoded - 1, frame_reader->delay_time,
- frame_reader->disposal_method);
-
- /* Clear state from this image */
- if (frame_reader) {
- frame_reader->is_local_colormap_defined = false;
- frame_reader->is_transparent = false;
- }
-
- GETN(1, gif_image_start);
- }
- }
- break;
-
- case gif_done:
- // When the GIF is done, we can stop.
- if (clientptr)
- clientptr->gifComplete();
- return true;
-
- // Handle out of memory errors
- case gif_oom:
- return false;
-
- // Handle general errors
- case gif_error:
- // nsGIFDecoder2::EndGIF(gs->clientptr, gs->loop_count);
- return false;
-
- // We shouldn't ever get here.
- default:
- break;
- }
- }
-
- // Copy the leftover into gs->hold
- bytes_in_hold = len;
- if (len) {
- // Add what we have sofar to the block
- unsigned char* p;
- if (state == gif_global_colormap)
- p = global_colormap;
- else if (state == gif_image_colormap)
- p = frame_reader ? frame_reader->local_colormap : 0;
- else
- p = hold;
- if (p)
- memcpy(p, buf, len);
- bytes_to_consume -= len;
- }
-
- if (clientptr)
- clientptr->decodingHalted(0);
- return true;
-}
diff --git a/WebCore/platform/image-decoders/skia/GIFImageReader.h b/WebCore/platform/image-decoders/skia/GIFImageReader.h
deleted file mode 100644
index f0d127f..0000000
--- a/WebCore/platform/image-decoders/skia/GIFImageReader.h
+++ /dev/null
@@ -1,215 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Communicator client code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef GIFImageReader_h
-#define GIFImageReader_h
-
-// Define ourselves as the clientPtr. Mozilla just hacked their C++ callback class into this old C decoder,
-// so we will too.
-#include "GIFImageDecoder.h"
-
-#define MAX_LZW_BITS 12
-#define MAX_BITS 4097 /* 2^MAX_LZW_BITS+1 */
-#define MAX_COLORS 256
-#define MAX_HOLD_SIZE 256
-
-const int cLoopCountNotSeen = -2;
-
-/* gif2.h
- The interface for the GIF87/89a decoder.
-*/
-// List of possible parsing states
-typedef enum {
- gif_type,
- gif_global_header,
- gif_global_colormap,
- gif_image_start,
- gif_image_header,
- gif_image_colormap,
- gif_image_body,
- gif_lzw_start,
- gif_lzw,
- gif_sub_block,
- gif_extension,
- gif_control_extension,
- gif_consume_block,
- gif_skip_block,
- gif_done,
- gif_oom,
- gif_error,
- gif_comment_extension,
- gif_application_extension,
- gif_netscape_extension_block,
- gif_consume_netscape_extension,
- gif_consume_comment
-} gstate;
-
-struct GIFFrameReader {
- /* LZW decoder state machine */
- unsigned char *stackp; /* Current stack pointer */
- int datasize;
- int codesize;
- int codemask;
- int clear_code; /* Codeword used to trigger dictionary reset */
- int avail; /* Index of next available slot in dictionary */
- int oldcode;
- unsigned char firstchar;
- int bits; /* Number of unread bits in "datum" */
- int datum; /* 32-bit input buffer */
-
- /* Output state machine */
- int ipass; /* Interlace pass; Ranges 1-4 if interlaced. */
- unsigned int rows_remaining; /* Rows remaining to be output */
- unsigned int irow; /* Current output row, starting at zero */
- unsigned char *rowbuf; /* Single scanline temporary buffer */
- unsigned char *rowend; /* Pointer to end of rowbuf */
- unsigned char *rowp; /* Current output pointer */
-
- /* Parameters for image frame currently being decoded */
- unsigned int x_offset, y_offset; /* With respect to "screen" origin */
- unsigned int height, width;
- int tpixel; /* Index of transparent pixel */
- WebCore::RGBA32Buffer::FrameDisposalMethod disposal_method; /* Restore to background, leave in place, etc.*/
- unsigned char *local_colormap; /* Per-image colormap */
- int local_colormap_size; /* Size of local colormap array. */
-
- bool is_local_colormap_defined : 1;
- bool progressive_display : 1; /* If TRUE, do Haeberli interlace hack */
- bool interlaced : 1; /* TRUE, if scanlines arrive interlaced order */
- bool is_transparent : 1; /* TRUE, if tpixel is valid */
-
- unsigned delay_time; /* Display time, in milliseconds,
- for this image in a multi-image GIF */
-
-
- unsigned short* prefix; /* LZW decoding tables */
- unsigned char* suffix; /* LZW decoding tables */
- unsigned char* stack; /* Base of LZW decoder stack */
-
-
- GIFFrameReader() {
- stackp = 0;
- datasize = codesize = codemask = clear_code = avail = oldcode = 0;
- firstchar = 0;
- bits = datum = 0;
- ipass = 0;
- rows_remaining = irow = 0;
- rowbuf = rowend = rowp = 0;
-
- x_offset = y_offset = width = height = 0;
- tpixel = 0;
- disposal_method = WebCore::RGBA32Buffer::DisposeNotSpecified;
-
- local_colormap = 0;
- local_colormap_size = 0;
- is_local_colormap_defined = progressive_display = is_transparent = interlaced = false;
-
- delay_time = 0;
-
- prefix = 0;
- suffix = stack = 0;
- }
-
- ~GIFFrameReader() {
- delete []rowbuf;
- delete []local_colormap;
- delete []prefix;
- delete []suffix;
- delete []stack;
- }
-};
-
-struct GIFImageReader {
- WebCore::GIFImageDecoder* clientptr;
- /* Parsing state machine */
- gstate state; /* Current decoder master state */
- unsigned bytes_to_consume; /* Number of bytes to accumulate */
- unsigned bytes_in_hold; /* bytes accumulated so far*/
- unsigned char hold[MAX_HOLD_SIZE]; /* Accumulation buffer */
- unsigned char* global_colormap; /* (3* MAX_COLORS in size) Default colormap if local not supplied, 3 bytes for each color */
-
- /* Global (multi-image) state */
- int screen_bgcolor; /* Logical screen background color */
- int version; /* Either 89 for GIF89 or 87 for GIF87 */
- unsigned screen_width; /* Logical screen width & height */
- unsigned screen_height;
- int global_colormap_size; /* Size of global colormap array. */
- unsigned images_decoded; /* Counts completed frames for animated GIFs */
- int images_count; /* Counted all frames seen so far (including incomplete frames) */
- int loop_count; /* Netscape specific extension block to control
- the number of animation loops a GIF renders. */
-
- // Not really global, but convenient to locate here.
- int count; /* Remaining # bytes in sub-block */
-
- GIFFrameReader* frame_reader;
-
- GIFImageReader(WebCore::GIFImageDecoder* client = 0) {
- clientptr = client;
- state = gif_type;
- bytes_to_consume = 6;
- bytes_in_hold = 0;
- frame_reader = 0;
- global_colormap = 0;
-
- screen_bgcolor = version = 0;
- screen_width = screen_height = 0;
- global_colormap_size = images_decoded = images_count = 0;
- loop_count = cLoopCountNotSeen;
- count = 0;
- }
-
- ~GIFImageReader() {
- close();
- }
-
- void close() {
- delete []global_colormap;
- global_colormap = 0;
- delete frame_reader;
- frame_reader = 0;
- }
-
- bool read(const unsigned char * buf, unsigned int numbytes,
- WebCore::GIFImageDecoder::GIFQuery query = WebCore::GIFImageDecoder::GIFFullQuery, unsigned haltAtFrame = -1);
-
-private:
- void output_row();
- int do_lzw(const unsigned char *q);
-};
-
-#endif
diff --git a/WebCore/platform/image-decoders/skia/ICOImageDecoder.cpp b/WebCore/platform/image-decoders/skia/ICOImageDecoder.cpp
deleted file mode 100644
index c340896..0000000
--- a/WebCore/platform/image-decoders/skia/ICOImageDecoder.cpp
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * 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.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 THE COPYRIGHT
- * OWNER 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.
- */
-
-#include "config.h"
-#include "ICOImageDecoder.h"
-
-namespace WebCore {
-
-// Number of bits in .ICO/.CUR used to store the directory and its entries,
-// respectively (doesn't match sizeof values for member structs since we omit
-// some fields).
-static const size_t sizeOfDirectory = 6;
-static const size_t sizeOfDirEntry = 16;
-
-void ICOImageDecoder::decodeImage(SharedBuffer* data)
-{
- // Read and process directory.
- if ((m_decodedOffset < sizeOfDirectory) && !processDirectory(data))
- return;
-
- // Read and process directory entries.
- if ((m_decodedOffset < (sizeOfDirectory + (m_directory.idCount * sizeOfDirEntry)))
- && !processDirectoryEntries(data))
- return;
-
- // Check if this entry is a PNG; we need 4 bytes to check the magic number.
- if (m_imageType == Unknown) {
- if (data->size() < (m_dirEntry.dwImageOffset + 4))
- return;
- m_imageType =
- strncmp(&data->data()[m_dirEntry.dwImageOffset], "\x89PNG", 4) ?
- BMP : PNG;
- }
-
- // Decode selected entry.
- if (m_imageType == PNG)
- decodePNG(data);
- else {
- // Note that we don't try to limit the bytes we give to the decoder to
- // just the size specified in the icon directory. If the size given in
- // the directory is insufficient to decode the whole image, the image is
- // corrupt anyway, so whatever we do may be wrong. The easiest choice
- // (which we do here) is to simply aggressively consume bytes until we
- // run out of bytes, finish decoding, or hit a sequence that makes the
- // decoder fail.
- decodeBMP(data);
- }
-}
-
-RGBA32Buffer* ICOImageDecoder::frameBufferAtIndex(size_t index)
-{
- return (m_imageType == PNG) ? m_pngDecoder.frameBufferAtIndex(0) :
- BMPImageReader::frameBufferAtIndex(0);
-}
-
-bool ICOImageDecoder::isSizeAvailable() const
-{
- return (m_imageType == PNG) ? m_pngDecoder.isSizeAvailable() :
- BMPImageReader::isSizeAvailable();
-}
-
-IntSize ICOImageDecoder::size() const
-{
- return (m_imageType == PNG) ? m_pngDecoder.size() : BMPImageReader::size();
-}
-
-bool ICOImageDecoder::processDirectory(SharedBuffer* data)
-{
- // Read directory.
- ASSERT(!m_decodedOffset);
- if (data->size() < sizeOfDirectory)
- return false;
- const uint16_t fileType = readUint16(data, 2);
- m_directory.idCount = readUint16(data, 4);
- m_decodedOffset = sizeOfDirectory;
-
- // See if this is an icon filetype we understand, and make sure we have at
- // least one entry in the directory.
- enum {
- ICON = 1,
- CURSOR = 2,
- };
- if (((fileType != ICON) && (fileType != CURSOR)) ||
- (m_directory.idCount == 0))
- m_failed = true;
-
- return !m_failed;
-}
-
-bool ICOImageDecoder::processDirectoryEntries(SharedBuffer* data)
-{
- // Read directory entries.
- ASSERT(m_decodedOffset == sizeOfDirectory);
- if ((m_decodedOffset > data->size()) || (data->size() - m_decodedOffset) <
- (m_directory.idCount * sizeOfDirEntry))
- return false;
- for (int i = 0; i < m_directory.idCount; ++i) {
- const IconDirectoryEntry dirEntry = readDirectoryEntry(data);
- if ((i == 0) || isBetterEntry(dirEntry))
- m_dirEntry = dirEntry;
- }
-
- // Make sure the specified image offset is past the end of the directory
- // entries, and that the offset isn't so large that it overflows when we add
- // 4 bytes to it (which we do in decodeImage() while ensuring it's safe to
- // examine the first 4 bytes of the image data).
- if ((m_dirEntry.dwImageOffset < m_decodedOffset) ||
- ((m_dirEntry.dwImageOffset + 4) < m_dirEntry.dwImageOffset)) {
- m_failed = true;
- return false;
- }
-
- // Ready to decode the image at the specified offset.
- m_decodedOffset = m_headerOffset = m_dirEntry.dwImageOffset;
- return true;
-}
-
-ICOImageDecoder::IconDirectoryEntry ICOImageDecoder::readDirectoryEntry(
- SharedBuffer* data)
-{
- // Read icon data.
- IconDirectoryEntry entry;
- entry.bWidth = static_cast<uint8_t>(data->data()[m_decodedOffset]);
- if (entry.bWidth == 0)
- entry.bWidth = 256;
- entry.bHeight = static_cast<uint8_t>(data->data()[m_decodedOffset + 1]);
- if (entry.bHeight == 0)
- entry.bHeight = 256;
- entry.wBitCount = readUint16(data, 6);
- entry.dwImageOffset = readUint32(data, 12);
-
- // Some icons don't have a bit depth, only a color count. Convert the
- // color count to the minimum necessary bit depth. It doesn't matter if
- // this isn't quite what the bitmap info header says later, as we only use
- // this value to determine which icon entry is best.
- if (!entry.wBitCount) {
- uint8_t colorCount = data->data()[m_decodedOffset + 2];
- if (colorCount) {
- for (--colorCount; colorCount; colorCount >>= 1)
- ++entry.wBitCount;
- }
- }
-
- m_decodedOffset += sizeOfDirEntry;
- return entry;
-}
-
-bool ICOImageDecoder::isBetterEntry(const IconDirectoryEntry& entry) const
-{
- const IntSize entrySize(entry.bWidth, entry.bHeight);
- const IntSize dirEntrySize(m_dirEntry.bWidth, m_dirEntry.bHeight);
- const int entryArea = entry.bWidth * entry.bHeight;
- const int dirEntryArea = m_dirEntry.bWidth * m_dirEntry.bHeight;
-
- if ((entrySize != dirEntrySize) && !m_preferredIconSize.isEmpty()) {
- // An icon of exactly the preferred size is best.
- if (entrySize == m_preferredIconSize)
- return true;
- if (dirEntrySize == m_preferredIconSize)
- return false;
-
- // The icon closest to the preferred area without being smaller is
- // better.
- if (entryArea != dirEntryArea) {
- return (entryArea < dirEntryArea)
- && (entryArea >= (m_preferredIconSize.width() * m_preferredIconSize.height()));
- }
- }
-
- // Larger icons are better.
- if (entryArea != dirEntryArea)
- return (entryArea > dirEntryArea);
-
- // Higher bit-depth icons are better.
- return (entry.wBitCount > m_dirEntry.wBitCount);
-}
-
-void ICOImageDecoder::decodePNG(SharedBuffer* data)
-{
- // Copy out PNG data to a separate vector and instantiate PNG decoder.
- // It would be nice to save this copy, if I could figure out how to just
- // offset the perceived start of |data| by |m_dirEntry.dwImageOffset| when
- // passing it to setData()...
- RefPtr<SharedBuffer> pngData(
- SharedBuffer::create(&data->data()[m_dirEntry.dwImageOffset],
- data->size() - m_dirEntry.dwImageOffset));
- m_pngDecoder.setData(pngData.get(), true);
-
- // Decode PNG as a side effect of asking for the frame. Strangely, it's
- // seemingly unsafe to call decode() or isSizeAvailable() before calling
- // this, as this is the only function that enlarges the framebuffer to
- // nonzero size, and before this happens any decoded image data is silently
- // thrown away and never decoded again (!).
- m_pngDecoder.frameBufferAtIndex(0);
- m_failed = m_pngDecoder.failed();
-
- // Sanity-check that the size is what we expected.
- if (isSizeAvailable() && ((size().width() != m_dirEntry.bWidth) ||
- (size().height() != m_dirEntry.bHeight)))
- m_failed = true;
-}
-
-}
diff --git a/WebCore/platform/image-decoders/skia/ICOImageDecoder.h b/WebCore/platform/image-decoders/skia/ICOImageDecoder.h
deleted file mode 100644
index f0e1acc..0000000
--- a/WebCore/platform/image-decoders/skia/ICOImageDecoder.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * 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.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 THE COPYRIGHT
- * OWNER 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 ICOImageDecoder_h
-#define ICOImageDecoder_h
-
-#include "BMPImageReader.h"
-#include "PNGImageDecoder.h"
-
-namespace WebCore {
-
- // This class decodes the ICO and CUR image formats.
- class ICOImageDecoder : public BMPImageReader {
- public:
- // See comments on |m_preferredIconSize| below.
- ICOImageDecoder(const IntSize& preferredIconSize)
- : m_preferredIconSize(preferredIconSize)
- , m_imageType(Unknown)
- {
- m_andMaskState = NotYetDecoded;
- }
-
- virtual String filenameExtension() const { return "ico"; }
-
- // BMPImageReader
- virtual void decodeImage(SharedBuffer* data);
- virtual RGBA32Buffer* frameBufferAtIndex(size_t index);
-
- // ImageDecoder
- virtual bool isSizeAvailable() const;
- virtual IntSize size() const;
-
- private:
- enum ImageType {
- Unknown,
- BMP,
- PNG,
- };
-
- // These are based on the Windows ICONDIR and ICONDIRENTRY structs, but
- // with unnecessary entries removed.
- struct IconDirectory {
- uint16_t idCount;
- };
- struct IconDirectoryEntry {
- uint16_t bWidth; // 16 bits so we can represent 256 as 256, not 0
- uint16_t bHeight; // "
- uint16_t wBitCount;
- uint32_t dwImageOffset;
- };
-
- // Processes the ICONDIR at the beginning of the data. Returns true if the
- // directory could be decoded.
- bool processDirectory(SharedBuffer*);
-
- // Processes the ICONDIRENTRY records after the directory. Keeps the
- // "best" entry as the one we'll decode. Returns true if the entries could
- // be decoded.
- bool processDirectoryEntries(SharedBuffer*);
-
- // Reads and returns a directory entry from the current offset into |data|.
- IconDirectoryEntry readDirectoryEntry(SharedBuffer*);
-
- // Returns true if |entry| is a preferable icon entry to m_dirEntry.
- // Larger sizes, or greater bitdepths at the same size, are preferable.
- bool isBetterEntry(const IconDirectoryEntry&) const;
-
- // Called when the image to be decoded is a PNG rather than a BMP.
- // Instantiates a PNGImageDecoder, decodes the image, and copies the
- // results locally.
- void decodePNG(SharedBuffer*);
-
- // The entry size we should prefer. If this is empty, we choose the
- // largest available size. If no entries of the desired size are
- // available, we pick the next larger size.
- IntSize m_preferredIconSize;
-
- // The headers for the ICO.
- IconDirectory m_directory;
- IconDirectoryEntry m_dirEntry;
-
- // The PNG decoder, if we need to use one.
- PNGImageDecoder m_pngDecoder;
-
- // What kind of image data is stored at the entry we're decoding.
- ImageType m_imageType;
- };
-
-} // namespace WebCore
-
-#endif
diff --git a/WebCore/platform/image-decoders/skia/ImageDecoder.h b/WebCore/platform/image-decoders/skia/ImageDecoder.h
deleted file mode 100644
index c198420..0000000
--- a/WebCore/platform/image-decoders/skia/ImageDecoder.h
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- * Copyright (C) 2008, 2009 Google, Inc.
- *
- * 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 "NativeImageSkia.h"
-#include "PlatformString.h"
-#include "SharedBuffer.h"
-#include <wtf/Assertions.h>
-#include <wtf/RefPtr.h>
-#include <wtf/Vector.h>
-
-#include "SkBitmap.h"
-#ifdef ANDROID_ANIMATED_GIF
-#include "SkColor.h"
-#endif
-
-namespace WebCore {
-
- // 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
- };
-
- RGBA32Buffer()
- : m_status(FrameEmpty)
- , m_duration(0)
- , m_disposalMethod(DisposeNotSpecified)
- {
- }
-
- // This constructor doesn't create a new copy of the image data, it only
- // increases the ref count of the existing bitmap.
- RGBA32Buffer(const RGBA32Buffer& other)
- {
- operator=(other);
- }
-
- ~RGBA32Buffer()
- {
- }
-
- // Initialize with another buffer. This function doesn't create a new copy
- // of the image data, it only increases the refcount of the existing bitmap.
- //
- // Normal callers should not generally be using this function. If you want
- // to create a copy on which you can modify the image data independently,
- // use copyBitmapData() instead.
- RGBA32Buffer& operator=(const RGBA32Buffer& other)
- {
- if (this == &other)
- return *this;
-
- m_bitmap = other.m_bitmap;
- // Keep the pixels locked since we will be writing directly into the
- // bitmap throughout this object's lifetime.
- m_bitmap.lockPixels();
- setRect(other.rect());
- setStatus(other.status());
- setDuration(other.duration());
- setDisposalMethod(other.disposalMethod());
- return *this;
- }
-
- void clear()
- {
- m_bitmap.reset();
- m_status = FrameEmpty;
- // NOTE: Do not reset other members here; clearFrameBufferCache()
- // calls this to free the bitmap data, but other functions like
- // initFrameBuffer() and frameComplete() may still need to read
- // other metadata out of this frame later.
- }
-
- // This function creates a new copy of the image data in |other|, so the
- // two images can be modified independently.
- void copyBitmapData(const RGBA32Buffer& other)
- {
- if (this == &other)
- return;
-
- m_bitmap.reset();
- const NativeImageSkia& otherBitmap = other.bitmap();
- otherBitmap.copyTo(&m_bitmap, otherBitmap.config());
- }
-
- NativeImageSkia& bitmap() { return m_bitmap; }
- const NativeImageSkia& bitmap() const { return m_bitmap; }
-
- // Must be called before any pixels are written. Will return true on
- // success, false if the memory allocation fails.
- bool setSize(int width, int height)
- {
- // This function should only be called once, it will leak memory
- // otherwise.
- ASSERT(m_bitmap.width() == 0 && m_bitmap.height() == 0);
- m_bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
- if (!m_bitmap.allocPixels())
- return false; // Allocation failure, maybe the bitmap was too big.
-
- // Clear the image.
- m_bitmap.eraseARGB(0, 0, 0, 0);
-
- return true;
- }
-
- int width() const { return m_bitmap.width(); }
- int height() const { return m_bitmap.height(); }
-
- 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 hasAlpha() const { return !m_bitmap.isOpaque(); }
-
- void setRect(const IntRect& r) { m_rect = r; }
- void setStatus(FrameStatus s)
- {
- if (s == FrameComplete)
- m_bitmap.setDataComplete(); // Tell the bitmap it's done.
- m_status = s;
- }
- void setDuration(unsigned duration) { m_duration = duration; }
- void setDisposalMethod(FrameDisposalMethod method) { m_disposalMethod = method; }
- void setHasAlpha(bool alpha) { m_bitmap.setIsOpaque(!alpha); }
-
- static void setRGBA(uint32_t* dest, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
- {
- // We store this data pre-multiplied.
-#ifdef ANDROID_ANIMATED_GIF
- // Chrome should take this change as well.
- *dest = SkPreMultiplyARGB(a, r, g, b);
-#else
- if (a == 0)
- *dest = 0;
- else {
- if (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);
- }
- *dest = (a << 24 | r << 16 | g << 8 | b);
- }
-#endif
- }
-
- void setRGBA(int x, int y, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
- {
- setRGBA(m_bitmap.getAddr32(x, y), r, g, b, a);
- }
-
- private:
- NativeImageSkia m_bitmap;
- 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.
- };
-
- // 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.
- class ImageDecoder {
- public:
- ImageDecoder()
- : m_failed(false)
- , m_sizeAvailable(false)
- {
- }
-
- virtual ~ImageDecoder() {}
-
- // The the filename extension usually associated with an undecoded image of this type.
- virtual String filenameExtension() const = 0;
-
- // All specific decoder plugins must do something with the data they are given.
- virtual void setData(SharedBuffer* data, bool allDataReceived) { m_data = data; }
-
- // 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() const
- {
- return !m_failed && m_sizeAvailable;
- }
-
- // Requests the size.
- virtual IntSize size() const
- {
- // Requesting the size of an invalid bitmap is meaningless.
- ASSERT(!m_failed);
- return m_size;
- }
-
- // 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 int 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 index) = 0;
-
- // Whether or not the underlying image format even supports alpha transparency.
- virtual bool supportsAlpha() const { return true; }
-
- bool failed() const { return m_failed; }
- void setFailed() { m_failed = true; }
-
- // 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) { }
-
- protected:
- // Called by the image decoders to set their decoded size, this also check
- // 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.
- bool setSize(unsigned width, unsigned height)
- {
- if (isOverSize(width, height)) {
- m_failed = true;
- return false;
- }
- m_size = IntSize(width, height);
- m_sizeAvailable = true;
- return true;
- }
-
- RefPtr<SharedBuffer> m_data; // The encoded data.
- Vector<RGBA32Buffer> m_frameBufferCache;
- mutable bool m_failed;
-
- private:
- // This function allows us to make sure the image is not too large. Very
- // large images, even if the allocation succeeds, can take a very long time
- // to process, giving the appearance of a DoS.
- //
- // WebKit also seems to like to ask for the size before data is available
- // and in some cases when the failed flag is set. Some of these code paths
- // such as BitmapImage::resetAnimation then compute the size of the image
- // based on the width and height. Because of this, our total computed image
- // byte size must never overflow an int.
- static bool isOverSize(unsigned width, unsigned height)
- {
- unsigned long long total_size = static_cast<unsigned long long>(width)
- * static_cast<unsigned long long>(height);
- if (total_size > 32 * 1024 * 1024) // 32M = 128MB memory total (32 bpp).
- return true;
- return false;
- }
-
- IntSize m_size;
- bool m_sizeAvailable;
- };
-
-} // namespace WebCore
-
-#endif
diff --git a/WebCore/platform/image-decoders/skia/ImageDecoderSkia.cpp b/WebCore/platform/image-decoders/skia/ImageDecoderSkia.cpp
new file mode 100644
index 0000000..ea7f227
--- /dev/null
+++ b/WebCore/platform/image-decoders/skia/ImageDecoderSkia.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2008, 2009 Google, Inc.
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include "ImageDecoder.h"
+
+namespace WebCore {
+
+RGBA32Buffer::RGBA32Buffer()
+ : m_status(FrameEmpty)
+ , m_duration(0)
+ , m_disposalMethod(DisposeNotSpecified)
+{
+}
+
+void RGBA32Buffer::clear()
+{
+ m_bitmap.reset();
+ m_status = FrameEmpty;
+ // NOTE: Do not reset other members here; clearFrameBufferCache()
+ // calls this to free the bitmap data, but other functions like
+ // initFrameBuffer() and frameComplete() may still need to read
+ // other metadata out of this frame later.
+}
+
+void RGBA32Buffer::zeroFill()
+{
+ m_bitmap.eraseARGB(0, 0, 0, 0);
+}
+
+void RGBA32Buffer::copyBitmapData(const RGBA32Buffer& other)
+{
+ if (this == &other)
+ return;
+
+ m_bitmap.reset();
+ const NativeImageSkia& otherBitmap = other.m_bitmap;
+ otherBitmap.copyTo(&m_bitmap, otherBitmap.config());
+}
+
+bool RGBA32Buffer::setSize(int newWidth, int newHeight)
+{
+ // This function should only be called once, it will leak memory
+ // otherwise.
+ ASSERT(width() == 0 && height() == 0);
+ m_bitmap.setConfig(SkBitmap::kARGB_8888_Config, newWidth, newHeight);
+ if (!m_bitmap.allocPixels()) {
+ // Allocation failure, maybe the bitmap was too big.
+ setStatus(FrameComplete);
+ return false;
+ }
+
+ // Zero the image.
+ zeroFill();
+
+ return true;
+}
+
+NativeImagePtr RGBA32Buffer::asNewNativeImage() const
+{
+ return new NativeImageSkia(m_bitmap);
+}
+
+bool RGBA32Buffer::hasAlpha() const
+{
+ return !m_bitmap.isOpaque();
+}
+
+void RGBA32Buffer::setHasAlpha(bool alpha)
+{
+ m_bitmap.setIsOpaque(!alpha);
+}
+
+void RGBA32Buffer::setStatus(FrameStatus status)
+{
+ m_status = status;
+ if (m_status == FrameComplete)
+ m_bitmap.setDataComplete(); // Tell the bitmap it's done.
+}
+
+RGBA32Buffer& RGBA32Buffer::operator=(const RGBA32Buffer& other)
+{
+ if (this == &other)
+ return *this;
+
+ m_bitmap = other.m_bitmap;
+ // Keep the pixels locked since we will be writing directly into the
+ // bitmap throughout this object's lifetime.
+ m_bitmap.lockPixels();
+ setRect(other.rect());
+ setStatus(other.status());
+ setDuration(other.duration());
+ setDisposalMethod(other.disposalMethod());
+ return *this;
+}
+
+int RGBA32Buffer::width() const
+{
+ return m_bitmap.width();
+}
+
+int RGBA32Buffer::height() const
+{
+ return m_bitmap.height();
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/image-decoders/skia/JPEGImageDecoder.cpp b/WebCore/platform/image-decoders/skia/JPEGImageDecoder.cpp
deleted file mode 100644
index ab74012..0000000
--- a/WebCore/platform/image-decoders/skia/JPEGImageDecoder.cpp
+++ /dev/null
@@ -1,512 +0,0 @@
-/*
- * Copyright (C) 2006 Apple Computer, Inc.
- * Copyright (C) 2008, 2009 Google, Inc.
- *
- * Portions are Copyright (C) 2001-6 mozilla.org
- *
- * Other contributors:
- * Stuart Parmenter <stuart@mozilla.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Alternatively, the contents of this file may be used under the terms
- * of either the Mozilla Public License Version 1.1, found at
- * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
- * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
- * (the "GPL"), in which case the provisions of the MPL or the GPL are
- * applicable instead of those above. If you wish to allow use of your
- * version of this file only under the terms of one of those two
- * licenses (the MPL or the GPL) and not to allow others to use your
- * version of this file under the LGPL, indicate your decision by
- * deletingthe provisions above and replace them with the notice and
- * other provisions required by the MPL or the GPL, as the case may be.
- * If you do not delete the provisions above, a recipient may use your
- * version of this file under any of the LGPL, the MPL or the GPL.
- */
-
-#include "config.h"
-#include "JPEGImageDecoder.h"
-#include <assert.h>
-
-extern "C" {
-#include "jpeglib.h"
-}
-
-#include <setjmp.h>
-
-namespace WebCore {
-
-struct decoder_error_mgr {
- struct jpeg_error_mgr pub; /* "public" fields for IJG library*/
- jmp_buf setjmp_buffer; /* For handling catastropic errors */
-};
-
-enum jstate {
- JPEG_HEADER, /* Reading JFIF headers */
- JPEG_START_DECOMPRESS,
- JPEG_DECOMPRESS_PROGRESSIVE, /* Output progressive pixels */
- JPEG_DECOMPRESS_SEQUENTIAL, /* Output sequential pixels */
- JPEG_DONE,
- JPEG_SINK_NON_JPEG_TRAILER, /* Some image files have a */
- /* non-JPEG trailer */
- JPEG_ERROR
-};
-
-void init_source(j_decompress_ptr jd);
-boolean fill_input_buffer(j_decompress_ptr jd);
-void skip_input_data(j_decompress_ptr jd, long num_bytes);
-void term_source(j_decompress_ptr jd);
-void error_exit(j_common_ptr cinfo);
-
-/*
- * Implementation of a JPEG src object that understands our state machine
- */
-struct decoder_source_mgr {
- /* public fields; must be first in this struct! */
- struct jpeg_source_mgr pub;
-
- JPEGImageReader *decoder;
-};
-
-class JPEGImageReader
-{
-public:
- JPEGImageReader(JPEGImageDecoder* decoder)
- : m_decoder(decoder)
- , m_bufferLength(0)
- , m_bytesToSkip(0)
- , m_state(JPEG_HEADER)
- , m_samples(0)
- {
- memset(&m_info, 0, sizeof(jpeg_decompress_struct));
-
- /* We set up the normal JPEG error routines, then override error_exit. */
- m_info.err = jpeg_std_error(&m_err.pub);
- m_err.pub.error_exit = error_exit;
-
- /* Allocate and initialize JPEG decompression object */
- jpeg_create_decompress(&m_info);
-
- decoder_source_mgr* src = 0;
- if (!m_info.src) {
- src = (decoder_source_mgr*)fastCalloc(sizeof(decoder_source_mgr), 1);
- if (!src) {
- m_state = JPEG_ERROR;
- return;
- }
- }
-
- m_info.src = (jpeg_source_mgr*)src;
-
- /* Set up callback functions. */
- src->pub.init_source = init_source;
- src->pub.fill_input_buffer = fill_input_buffer;
- src->pub.skip_input_data = skip_input_data;
- src->pub.resync_to_restart = jpeg_resync_to_restart;
- src->pub.term_source = term_source;
- src->decoder = this;
- }
-
- ~JPEGImageReader()
- {
- close();
- }
-
- void close() {
- decoder_source_mgr* src = (decoder_source_mgr*)m_info.src;
- if (src)
- fastFree(src);
- m_info.src = 0;
-
- jpeg_destroy_decompress(&m_info);
- }
-
- void skipBytes(long num_bytes) {
- decoder_source_mgr* src = (decoder_source_mgr*)m_info.src;
- long bytesToSkip = std::min(num_bytes, (long)src->pub.bytes_in_buffer);
- src->pub.bytes_in_buffer -= (size_t)bytesToSkip;
- src->pub.next_input_byte += bytesToSkip;
-
- if (num_bytes > bytesToSkip)
- m_bytesToSkip = (size_t)(num_bytes - bytesToSkip);
- else
- m_bytesToSkip = 0;
- }
-
- bool decode(const Vector<char>& data, bool sizeOnly) {
- m_decodingSizeOnly = sizeOnly;
-
- unsigned newByteCount = data.size() - m_bufferLength;
- unsigned readOffset = m_bufferLength - m_info.src->bytes_in_buffer;
-
- m_info.src->bytes_in_buffer += newByteCount;
- m_info.src->next_input_byte = (JOCTET*)(data.data()) + readOffset;
-
- // If we still have bytes to skip, try to skip those now.
- if (m_bytesToSkip)
- skipBytes(m_bytesToSkip);
-
- m_bufferLength = data.size();
-
- // We need to do the setjmp here. Otherwise bad things will happen
- if (setjmp(m_err.setjmp_buffer)) {
- m_state = JPEG_SINK_NON_JPEG_TRAILER;
- close();
- return false;
- }
-
- switch (m_state) {
- case JPEG_HEADER:
- {
- /* Read file parameters with jpeg_read_header() */
- if (jpeg_read_header(&m_info, true) == JPEG_SUSPENDED)
- return true; /* I/O suspension */
-
- /* let libjpeg take care of gray->RGB and YCbCr->RGB conversions */
- switch (m_info.jpeg_color_space) {
- case JCS_GRAYSCALE:
- case JCS_RGB:
- case JCS_YCbCr:
- m_info.out_color_space = JCS_RGB;
- break;
- case JCS_CMYK:
- case JCS_YCCK:
- default:
- m_state = JPEG_ERROR;
- return false;
- }
-
- /*
- * Don't allocate a giant and superfluous memory buffer
- * when the image is a sequential JPEG.
- */
- m_info.buffered_image = jpeg_has_multiple_scans(&m_info);
-
- /* Used to set up image size so arrays can be allocated */
- jpeg_calc_output_dimensions(&m_info);
-
- /*
- * Make a one-row-high sample array that will go away
- * when done with image. Always make it big enough to
- * hold an RGB row. Since this uses the IJG memory
- * manager, it must be allocated before the call to
- * jpeg_start_compress().
- */
- int row_stride = m_info.output_width * 4; // RGBA buffer
-
-
- m_samples = (*m_info.mem->alloc_sarray)((j_common_ptr) &m_info,
- JPOOL_IMAGE,
- row_stride, 1);
-
- m_state = JPEG_START_DECOMPRESS;
-
- // We can fill in the size now that the header is available.
- if (!m_decoder->setSize(m_info.image_width, m_info.image_height)) {
- m_state = JPEG_ERROR;
- return false;
- }
-
- if (m_decodingSizeOnly) {
- // We can stop here.
- // Reduce our buffer length and available data.
- m_bufferLength -= m_info.src->bytes_in_buffer;
- m_info.src->bytes_in_buffer = 0;
- return true;
- }
- }
-
- case JPEG_START_DECOMPRESS:
- {
- /* Set parameters for decompression */
- /* FIXME -- Should reset dct_method and dither mode
- * for final pass of progressive JPEG
- */
- m_info.dct_method = JDCT_ISLOW;
- m_info.dither_mode = JDITHER_FS;
- m_info.do_fancy_upsampling = true;
- m_info.enable_2pass_quant = false;
- m_info.do_block_smoothing = true;
-
- /* Start decompressor */
- if (!jpeg_start_decompress(&m_info))
- return true; /* I/O suspension */
-
- /* If this is a progressive JPEG ... */
- m_state = (m_info.buffered_image) ? JPEG_DECOMPRESS_PROGRESSIVE : JPEG_DECOMPRESS_SEQUENTIAL;
- }
-
- case JPEG_DECOMPRESS_SEQUENTIAL:
- {
- if (m_state == JPEG_DECOMPRESS_SEQUENTIAL) {
-
- if (!m_decoder->outputScanlines())
- return true; /* I/O suspension */
-
- /* If we've completed image output ... */
- assert(m_info.output_scanline == m_info.output_height);
- m_state = JPEG_DONE;
- }
- }
-
- case JPEG_DECOMPRESS_PROGRESSIVE:
- {
- if (m_state == JPEG_DECOMPRESS_PROGRESSIVE) {
- int status;
- do {
- status = jpeg_consume_input(&m_info);
- } while ((status != JPEG_SUSPENDED) &&
- (status != JPEG_REACHED_EOI));
-
- for (;;) {
- if (m_info.output_scanline == 0) {
- int scan = m_info.input_scan_number;
-
- /* if we haven't displayed anything yet (output_scan_number==0)
- and we have enough data for a complete scan, force output
- of the last full scan */
- if ((m_info.output_scan_number == 0) &&
- (scan > 1) &&
- (status != JPEG_REACHED_EOI))
- scan--;
-
- if (!jpeg_start_output(&m_info, scan))
- return true; /* I/O suspension */
- }
-
- if (m_info.output_scanline == 0xffffff)
- m_info.output_scanline = 0;
-
- if (!m_decoder->outputScanlines()) {
- if (m_info.output_scanline == 0)
- /* didn't manage to read any lines - flag so we don't call
- jpeg_start_output() multiple times for the same scan */
- m_info.output_scanline = 0xffffff;
- return true; /* I/O suspension */
- }
-
- if (m_info.output_scanline == m_info.output_height) {
- if (!jpeg_finish_output(&m_info))
- return true; /* I/O suspension */
-
- if (jpeg_input_complete(&m_info) &&
- (m_info.input_scan_number == m_info.output_scan_number))
- break;
-
- m_info.output_scanline = 0;
- }
- }
-
- m_state = JPEG_DONE;
- }
- }
-
- case JPEG_DONE:
- {
- /* Finish decompression */
- if (!jpeg_finish_decompress(&m_info))
- return true; /* I/O suspension */
-
- m_state = JPEG_SINK_NON_JPEG_TRAILER;
-
- /* we're done */
- break;
- }
-
- case JPEG_SINK_NON_JPEG_TRAILER:
- break;
-
- case JPEG_ERROR:
- break;
- }
-
- return true;
- }
-
- jpeg_decompress_struct* info() { return &m_info; }
- JSAMPARRAY samples() const { return m_samples; }
- JPEGImageDecoder* decoder() { return m_decoder; }
-
-private:
- JPEGImageDecoder* m_decoder;
- unsigned m_bufferLength;
- int m_bytesToSkip;
- bool m_decodingSizeOnly;
- bool m_initialized;
-
- jpeg_decompress_struct m_info;
- decoder_error_mgr m_err;
- jstate m_state;
-
- JSAMPARRAY m_samples;
-};
-
-/* Override the standard error method in the IJG JPEG decoder code. */
-void error_exit(j_common_ptr cinfo)
-{
- /* Return control to the setjmp point. */
- decoder_error_mgr *err = (decoder_error_mgr *) cinfo->err;
- longjmp(err->setjmp_buffer, -1);
-}
-
-void init_source(j_decompress_ptr jd)
-{
-}
-
-void skip_input_data(j_decompress_ptr jd, long num_bytes)
-{
- decoder_source_mgr *src = (decoder_source_mgr *)jd->src;
- src->decoder->skipBytes(num_bytes);
-}
-
-boolean fill_input_buffer(j_decompress_ptr jd)
-{
- // Our decode step always sets things up properly, so if this method is ever
- // called, then we have hit the end of the buffer. A return value of FALSE indicates
- // that we have no data to supply yet.
- return false;
-}
-
-void term_source (j_decompress_ptr jd)
-{
- decoder_source_mgr *src = (decoder_source_mgr *)jd->src;
- src->decoder->decoder()->jpegComplete();
-}
-
-JPEGImageDecoder::JPEGImageDecoder()
-: m_reader(0)
-{}
-
-JPEGImageDecoder::~JPEGImageDecoder()
-{
- delete m_reader;
-}
-
-// Take the data and store it.
-void JPEGImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
-{
- if (m_failed)
- return;
-
- // Cache our new data.
- ImageDecoder::setData(data, allDataReceived);
-
- // Create the JPEG reader.
- if (!m_reader && !m_failed)
- m_reader = new JPEGImageReader(this);
-}
-
-// Whether or not the size information has been decoded yet.
-bool JPEGImageDecoder::isSizeAvailable() const
-{
- // If we have pending data to decode, send it to the JPEG reader now.
- if (!ImageDecoder::isSizeAvailable() && m_reader) {
- if (m_failed)
- return false;
-
- // The decoder will go ahead and aggressively consume everything up until the
- // size is encountered.
- decode(true);
- }
-
- return ImageDecoder::isSizeAvailable();
-}
-
-RGBA32Buffer* JPEGImageDecoder::frameBufferAtIndex(size_t index)
-{
- if (index)
- return 0;
-
- if (m_frameBufferCache.isEmpty())
- m_frameBufferCache.resize(1);
-
- RGBA32Buffer& frame = m_frameBufferCache[0];
- if (frame.status() != RGBA32Buffer::FrameComplete && m_reader)
- // Decode this frame.
- decode();
- return &frame;
-}
-
-// Feed data to the JPEG reader.
-void JPEGImageDecoder::decode(bool sizeOnly) const
-{
- if (m_failed)
- return;
-
- m_failed = !m_reader->decode(m_data->buffer(), sizeOnly);
-
- if (m_failed || (!m_frameBufferCache.isEmpty() && m_frameBufferCache[0].status() == RGBA32Buffer::FrameComplete)) {
- delete m_reader;
- m_reader = 0;
- }
-}
-
-bool JPEGImageDecoder::outputScanlines()
-{
- if (m_frameBufferCache.isEmpty())
- return false;
-
- // Resize to the width and height of the image.
- RGBA32Buffer& buffer = m_frameBufferCache[0];
- if (buffer.status() == RGBA32Buffer::FrameEmpty) {
- // Let's resize our buffer now to the correct width/height. This will
- // also initialize it to transparent.
- if (!buffer.setSize(size().width(), size().height())) {
- m_failed = true;
- buffer.setStatus(RGBA32Buffer::FrameComplete);
- return false;
- }
-
- // Update our status to be partially complete.
- buffer.setStatus(RGBA32Buffer::FramePartial);
-
- // For JPEGs, the frame always fills the entire image.
- buffer.setRect(IntRect(0, 0, size().width(), size().height()));
-
- // We don't have alpha (this is the default when the buffer is constructed).
- }
-
- jpeg_decompress_struct* info = m_reader->info();
- JSAMPARRAY samples = m_reader->samples();
-
- while (info->output_scanline < info->output_height) {
- /* Request one scanline. Returns 0 or 1 scanlines. */
- if (jpeg_read_scanlines(info, samples, 1) != 1)
- return false;
- JSAMPLE *j1 = samples[0];
- for (unsigned x = 0; x < info->output_width; ++x) {
- unsigned r = *j1++;
- unsigned g = *j1++;
- unsigned b = *j1++;
- // read_scanlines has increased the scanline counter, so we
- // actually mean the previous one.
- buffer.setRGBA(x, info->output_scanline - 1, r, g, b, 0xFF);
- }
- }
-
- return true;
-}
-
-void JPEGImageDecoder::jpegComplete()
-{
- if (m_frameBufferCache.isEmpty())
- return;
-
- // Hand back an appropriately sized buffer, even if the image ended up being empty.
- RGBA32Buffer& buffer = m_frameBufferCache[0];
- buffer.setStatus(RGBA32Buffer::FrameComplete);
-}
-
-}
diff --git a/WebCore/platform/image-decoders/skia/JPEGImageDecoder.h b/WebCore/platform/image-decoders/skia/JPEGImageDecoder.h
deleted file mode 100644
index 51dd050..0000000
--- a/WebCore/platform/image-decoders/skia/JPEGImageDecoder.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- * Copyright (C) 2008, 2009 Google, Inc.
- *
- * 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 JPEGImageDecoder_h
-#define JPEGImageDecoder_h
-
-#include "ImageDecoder.h"
-
-namespace WebCore {
-
- class JPEGImageReader;
-
- // This class decodes the JPEG image format.
- class JPEGImageDecoder : public ImageDecoder {
- public:
- JPEGImageDecoder();
- ~JPEGImageDecoder();
-
- virtual String filenameExtension() const { return "jpg"; }
-
- // Take the data and store it.
- virtual void setData(SharedBuffer* data, bool allDataReceived);
-
- // Whether or not the size information has been decoded yet.
- virtual bool isSizeAvailable() const;
-
- virtual RGBA32Buffer* frameBufferAtIndex(size_t index);
-
- virtual bool supportsAlpha() const { return false; }
-
- void decode(bool sizeOnly = false) const;
-
- JPEGImageReader* reader() { return m_reader; }
-
- bool outputScanlines();
- void jpegComplete();
-
- private:
- friend class JPEGImageReader;
- mutable JPEGImageReader* m_reader;
- };
-
-} // namespace WebCore
-
-#endif
diff --git a/WebCore/platform/image-decoders/skia/PNGImageDecoder.cpp b/WebCore/platform/image-decoders/skia/PNGImageDecoder.cpp
deleted file mode 100644
index ad12b86..0000000
--- a/WebCore/platform/image-decoders/skia/PNGImageDecoder.cpp
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- * Copyright (C) 2006 Apple Computer, Inc.
- * Copyright (C) 2008, 2009 Google, Inc.
- *
- * Portions are Copyright (C) 2001 mozilla.org
- *
- * Other contributors:
- * Stuart Parmenter <stuart@mozilla.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Alternatively, the contents of this file may be used under the terms
- * of either the Mozilla Public License Version 1.1, found at
- * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
- * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
- * (the "GPL"), in which case the provisions of the MPL or the GPL are
- * applicable instead of those above. If you wish to allow use of your
- * version of this file only under the terms of one of those two
- * licenses (the MPL or the GPL) and not to allow others to use your
- * version of this file under the LGPL, indicate your decision by
- * deletingthe provisions above and replace them with the notice and
- * other provisions required by the MPL or the GPL, as the case may be.
- * If you do not delete the provisions above, a recipient may use your
- * version of this file under any of the LGPL, the MPL or the GPL.
- */
-
-#include "config.h"
-#include "PNGImageDecoder.h"
-#include "png.h"
-#include "assert.h"
-
-namespace WebCore {
-
-// Gamma constants.
-const double cMaxGamma = 21474.83;
-const double cDefaultGamma = 2.2;
-const double cInverseGamma = 0.45455;
-
-// Protect against large PNGs. See Mozilla's bug #251381 for more info.
-const unsigned long cMaxPNGSize = 1000000UL;
-
-// Called if the decoding of the image fails.
-static void PNGAPI decodingFailed(png_structp png_ptr, png_const_charp error_msg);
-
-// Callbacks given to the read struct. The first is for warnings (we want to treat a particular warning
-// as an error, which is why we have to register this callback.
-static void PNGAPI decodingWarning(png_structp png_ptr, png_const_charp warning_msg);
-
-// Called when we have obtained the header information (including the size).
-static void PNGAPI headerAvailable(png_structp png_ptr, png_infop info_ptr);
-
-// Called when a row is ready.
-static void PNGAPI rowAvailable(png_structp png_ptr, png_bytep new_row,
- png_uint_32 row_num, int pass);
-
-// Called when we have completely finished decoding the image.
-static void PNGAPI pngComplete(png_structp png_ptr, png_infop info_ptr);
-
-class PNGImageReader
-{
-public:
- PNGImageReader(PNGImageDecoder* decoder)
- : m_readOffset(0)
- , m_decodingSizeOnly(false)
- , m_interlaceBuffer(0)
- , m_hasAlpha(0)
- {
- m_png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, decodingFailed, decodingWarning);
- m_info = png_create_info_struct(m_png);
- png_set_progressive_read_fn(m_png, decoder, headerAvailable, rowAvailable, pngComplete);
- }
-
- ~PNGImageReader()
- {
- close();
- }
-
- void close() {
- if (m_png && m_info)
- png_destroy_read_struct(&m_png, &m_info, 0); // Will zero the pointers.
- delete []m_interlaceBuffer;
- m_interlaceBuffer = 0;
- m_readOffset = 0;
- }
-
- void decode(const Vector<char>& data, bool sizeOnly)
- {
- m_decodingSizeOnly = sizeOnly;
-
- // We need to do the setjmp here. Otherwise bad things will happen
- if (setjmp(m_png->jmpbuf)) {
- close();
- return;
- }
-
- // Go ahead and assume we consumed all the data. If we consume less, the
- // callback will adjust our read offset accordingly. Do not attempt to adjust the
- // offset after png_process_data returns.
- unsigned offset = m_readOffset;
- unsigned remaining = data.size() - m_readOffset;
- m_readOffset = data.size();
- png_process_data(m_png, m_info, (png_bytep)(data.data()) + offset, remaining);
- }
-
- bool decodingSizeOnly() const { return m_decodingSizeOnly; }
- png_structp pngPtr() const { return m_png; }
- png_infop infoPtr() const { return m_info; }
- png_bytep interlaceBuffer() const { return m_interlaceBuffer; }
- bool hasAlpha() const { return m_hasAlpha; }
-
- void setReadOffset(unsigned offset) { m_readOffset = offset; }
- void setHasAlpha(bool b) { m_hasAlpha = b; }
-
- void createInterlaceBuffer(int size) {
- m_interlaceBuffer = new png_byte[size];
- }
-
-private:
- unsigned m_readOffset;
- bool m_decodingSizeOnly;
- png_structp m_png;
- png_infop m_info;
- png_bytep m_interlaceBuffer;
- bool m_hasAlpha;
-};
-
-PNGImageDecoder::PNGImageDecoder()
- : m_reader(0)
-{
-}
-
-PNGImageDecoder::~PNGImageDecoder()
-{
- delete m_reader;
-}
-
-// Take the data and store it.
-void PNGImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
-{
- if (m_failed)
- return;
-
- // Cache our new data.
- ImageDecoder::setData(data, allDataReceived);
-
- // Create the PNG reader.
- if (!m_reader && !m_failed)
- m_reader = new PNGImageReader(this);
-}
-
-// Whether or not the size information has been decoded yet.
-bool PNGImageDecoder::isSizeAvailable() const
-{
- // If we have pending data to decode, send it to the PNG reader now.
- if (!ImageDecoder::isSizeAvailable() && m_reader) {
- if (m_failed)
- return false;
-
- // The decoder will go ahead and aggressively consume everything up until the
- // size is encountered.
- decode(true);
- }
-
- return ImageDecoder::isSizeAvailable();
-}
-
-RGBA32Buffer* PNGImageDecoder::frameBufferAtIndex(size_t index)
-{
- if (index)
- return 0;
-
- if (m_frameBufferCache.isEmpty())
- m_frameBufferCache.resize(1);
-
- RGBA32Buffer& frame = m_frameBufferCache[0];
- if (frame.status() != RGBA32Buffer::FrameComplete && m_reader)
- // Decode this frame.
- decode();
- return &frame;
-}
-
-// Feed data to the PNG reader.
-void PNGImageDecoder::decode(bool sizeOnly) const
-{
- if (m_failed)
- return;
-
- m_reader->decode(m_data->buffer(), sizeOnly);
-
- if (m_failed || (!m_frameBufferCache.isEmpty() && m_frameBufferCache[0].status() == RGBA32Buffer::FrameComplete)) {
- delete m_reader;
- m_reader = 0;
- }
-}
-
-void decodingFailed(png_structp png, png_const_charp errorMsg)
-{
- static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png))->decodingFailed();
- longjmp(png->jmpbuf, 1);
-}
-
-void decodingWarning(png_structp png, png_const_charp warningMsg)
-{
- // Mozilla did this, so we will too.
- // Convert a tRNS warning to be an error (documented in bugzilla.mozilla.org bug #251381)
- if (!strncmp(warningMsg, "Missing PLTE before tRNS", 24))
- png_error(png, warningMsg);
-}
-
-void headerAvailable(png_structp png, png_infop info)
-{
- static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png))->headerAvailable();
-}
-
-void PNGImageDecoder::decodingFailed() {
- m_failed = true;
-}
-
-void PNGImageDecoder::headerAvailable()
-{
- png_structp png = reader()->pngPtr();
- png_infop info = reader()->infoPtr();
- png_uint_32 width = png->width;
- png_uint_32 height = png->height;
-
- // Protect against large images.
- if (png->width > cMaxPNGSize || png->height > cMaxPNGSize) {
- m_failed = true;
- longjmp(png->jmpbuf, 1);
- return;
- }
-
- // We can fill in the size now that the header is available.
- if (!ImageDecoder::isSizeAvailable()) {
- if (!setSize(width, height)) {
- // Size unreasonable, bail out.
- longjmp(png->jmpbuf, 1);
- return;
- }
- }
-
- int bitDepth, colorType, interlaceType, compressionType, filterType, channels;
- png_get_IHDR(png, info, &width, &height, &bitDepth, &colorType,
- &interlaceType, &compressionType, &filterType);
-
- // The options we set here match what Mozilla does.
-
- // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA.
- if (colorType == PNG_COLOR_TYPE_PALETTE ||
- (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8))
- png_set_expand(png);
-
- png_bytep trns = 0;
- int trnsCount = 0;
- if (png_get_valid(png, info, PNG_INFO_tRNS)) {
- png_get_tRNS(png, info, &trns, &trnsCount, 0);
- png_set_expand(png);
- }
-
- if (bitDepth == 16)
- png_set_strip_16(png);
-
- if (colorType == PNG_COLOR_TYPE_GRAY ||
- colorType == PNG_COLOR_TYPE_GRAY_ALPHA)
- png_set_gray_to_rgb(png);
-
- // Deal with gamma and keep it under our control.
- double gamma;
- if (png_get_gAMA(png, info, &gamma)) {
- if ((gamma <= 0.0) || (gamma > cMaxGamma)) {
- gamma = cInverseGamma;
- png_set_gAMA(png, info, gamma);
- }
- png_set_gamma(png, cDefaultGamma, gamma);
- }
- else
- png_set_gamma(png, cDefaultGamma, cInverseGamma);
-
- // Tell libpng to send us rows for interlaced pngs.
- if (interlaceType == PNG_INTERLACE_ADAM7)
- png_set_interlace_handling(png);
-
- // Update our info now
- png_read_update_info(png, info);
- channels = png_get_channels(png, info);
- assert(channels == 3 || channels == 4);
-
- reader()->setHasAlpha(channels == 4);
-
- if (reader()->decodingSizeOnly()) {
- // If we only needed the size, halt the reader.
- reader()->setReadOffset(m_data->size() - png->buffer_size);
- png->buffer_size = 0;
- }
-}
-
-void rowAvailable(png_structp png, png_bytep rowBuffer,
- png_uint_32 rowIndex, int interlacePass)
-{
- static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png))->rowAvailable(rowBuffer, rowIndex, interlacePass);
-}
-
-void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, unsigned rowIndex, int interlacePass)
-{
- if (m_frameBufferCache.isEmpty())
- return;
-
- // Resize to the width and height of the image.
- RGBA32Buffer& buffer = m_frameBufferCache[0];
- if (buffer.status() == RGBA32Buffer::FrameEmpty) {
- // Let's resize our buffer now to the correct width/height.
- if (!buffer.setSize(size().width(), size().height())) {
- // Error allocating the bitmap. We should not continue.
- static_cast<PNGImageDecoder*>(png_get_progressive_ptr(reader()->pngPtr()))->decodingFailed();
- longjmp(reader()->pngPtr()->jmpbuf, 1);
- return;
- }
-
- // Update our status to be partially complete.
- buffer.setStatus(RGBA32Buffer::FramePartial);
-
- // For PNGs, the frame always fills the entire image.
- buffer.setRect(IntRect(0, 0, size().width(), size().height()));
-
- if (reader()->pngPtr()->interlaced)
- reader()->createInterlaceBuffer((reader()->hasAlpha() ? 4 : 3) * size().width() * size().height());
- }
-
- if (rowBuffer == 0)
- return;
-
- /* libpng comments (pasted in here to explain what follows)
- *
- * this function is called for every row in the image. If the
- * image is interlacing, and you turned on the interlace handler,
- * this function will be called for every row in every pass.
- * Some of these rows will not be changed from the previous pass.
- * When the row is not changed, the new_row variable will be NULL.
- * The rows and passes are called in order, so you don't really
- * need the row_num and pass, but I'm supplying them because it
- * may make your life easier.
- *
- * For the non-NULL rows of interlaced images, you must call
- * png_progressive_combine_row() passing in the row and the
- * old row. You can call this function for NULL rows (it will
- * just return) and for non-interlaced images (it just does the
- * memcpy for you) if it will make the code easier. Thus, you
- * can just do this for all cases:
- *
- * png_progressive_combine_row(png_ptr, old_row, new_row);
- *
- * where old_row is what was displayed for previous rows. Note
- * that the first pass (pass == 0 really) will completely cover
- * the old row, so the rows do not have to be initialized. After
- * the first pass (and only for interlaced images), you will have
- * to pass the current row, and the function will combine the
- * old row and the new row.
- */
-
- png_structp png = reader()->pngPtr();
- bool hasAlpha = reader()->hasAlpha();
- unsigned colorChannels = hasAlpha ? 4 : 3;
- png_bytep row;
- png_bytep interlaceBuffer = reader()->interlaceBuffer();
- if (interlaceBuffer) {
- row = interlaceBuffer + (rowIndex * colorChannels * size().width());
- png_progressive_combine_row(png, row, rowBuffer);
- }
- else
- row = rowBuffer;
-
- // Copy the data into our buffer.
- int width = size().width();
- bool sawAlpha = false;
- for (int x = 0; x < width; x++) {
- unsigned red = *row++;
- unsigned green = *row++;
- unsigned blue = *row++;
- unsigned alpha = (hasAlpha ? *row++ : 255);
- buffer.setRGBA(x, rowIndex, red, green, blue, alpha);
- if (!sawAlpha && alpha < 255) {
- sawAlpha = true;
- buffer.setHasAlpha(true);
- }
- }
-}
-
-void pngComplete(png_structp png, png_infop info)
-{
- static_cast<PNGImageDecoder*>(png_get_progressive_ptr(png))->pngComplete();
-}
-
-void PNGImageDecoder::pngComplete()
-{
- if (m_frameBufferCache.isEmpty())
- return;
-
- // Hand back an appropriately sized buffer, even if the image ended up being empty.
- RGBA32Buffer& buffer = m_frameBufferCache[0];
- buffer.setStatus(RGBA32Buffer::FrameComplete);
-}
-
-} // namespace WebCore
diff --git a/WebCore/platform/image-decoders/skia/PNGImageDecoder.h b/WebCore/platform/image-decoders/skia/PNGImageDecoder.h
deleted file mode 100644
index 83cf343..0000000
--- a/WebCore/platform/image-decoders/skia/PNGImageDecoder.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- * Copyright (C) 2008, 2009 Google, Inc.
- *
- * 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 PNGImageDecoder_h
-#define PNGImageDecoder_h
-
-#include "ImageDecoder.h"
-
-namespace WebCore {
-
- class PNGImageReader;
-
- // This class decodes the PNG image format.
- class PNGImageDecoder : public ImageDecoder {
- public:
- PNGImageDecoder();
- ~PNGImageDecoder();
-
- virtual String filenameExtension() const { return "png"; }
-
- // Take the data and store it.
- virtual void setData(SharedBuffer* data, bool allDataReceived);
-
- // Whether or not the size information has been decoded yet.
- virtual bool isSizeAvailable() const;
-
- virtual RGBA32Buffer* frameBufferAtIndex(size_t index);
-
- void decode(bool sizeOnly = false) const;
-
- PNGImageReader* reader() { return m_reader; }
-
- // Callbacks from libpng
- void decodingFailed();
- void headerAvailable();
- void rowAvailable(unsigned char* rowBuffer, unsigned rowIndex, int interlacePass);
- void pngComplete();
-
- private:
- mutable PNGImageReader* m_reader;
- };
-
-} // namespace WebCore
-
-#endif
diff --git a/WebCore/platform/image-decoders/skia/XBMImageDecoder.cpp b/WebCore/platform/image-decoders/skia/XBMImageDecoder.cpp
deleted file mode 100644
index 8908504..0000000
--- a/WebCore/platform/image-decoders/skia/XBMImageDecoder.cpp
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * 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.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 THE COPYRIGHT
- * OWNER 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.
- */
-
-#include "config.h"
-#include "XBMImageDecoder.h"
-
-#include <algorithm>
-
-namespace WebCore {
-
-XBMImageDecoder::XBMImageDecoder()
- : m_decodeOffset(0)
- , m_allDataReceived(false)
- , m_decodedHeader(false)
- , m_dataType(Unknown)
- , m_bitsDecoded(0)
-{
-}
-
-void XBMImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
-{
- ImageDecoder::setData(data, allDataReceived);
-
- const Vector<char>& buf = m_data->buffer();
- if (buf.size() > m_xbmString.size())
- m_xbmString.append(&buf[m_xbmString.size()], buf.size() - m_xbmString.size());
-
- m_allDataReceived = allDataReceived;
-}
-
-bool XBMImageDecoder::isSizeAvailable() const
-{
- // This method should either (a) not be const, or (b) not be expected to
- // do anything that changes m_sizeAvailable. The png and jpeg decoders
- // get around this with callbacks from external libraries.
- //
- // FIXME: Find out if we can patch webkit to take care of this.
- if (!ImageDecoder::isSizeAvailable() && !m_failed)
- const_cast<XBMImageDecoder*>(this)->decodeXBM(true);
-
- return !m_failed && ImageDecoder::isSizeAvailable();
-}
-
-RGBA32Buffer* XBMImageDecoder::frameBufferAtIndex(size_t index)
-{
- // Allocate a framebuffer if necessary. New framebuffers have their status
- // initialized to RGBA32Buffer::FrameEmpty.
- if (m_frameBufferCache.isEmpty())
- m_frameBufferCache.resize(1);
-
- RGBA32Buffer& frame = m_frameBufferCache[0];
-
- // Attempt to get the size if we don't have it yet.
- if (!ImageDecoder::isSizeAvailable())
- decodeXBM(true);
-
- // Size the framebuffer once we know the right size.
- if (ImageDecoder::isSizeAvailable() &&
- frame.status() == RGBA32Buffer::FrameEmpty) {
- if (!frame.setSize(size().width(), size().height())) {
- m_failed = true;
- frame.setStatus(RGBA32Buffer::FrameComplete);
- return 0;
- }
- frame.setStatus(RGBA32Buffer::FramePartial);
- }
-
- // Keep trying to decode until we've got the entire image.
- if (frame.status() != RGBA32Buffer::FrameComplete)
- decodeXBM(false);
-
- return &frame;
-}
-
-bool XBMImageDecoder::decodeHeader()
-{
- ASSERT(m_decodeOffset <= m_xbmString.size());
- ASSERT(!m_decodedHeader);
-
- const char* input = m_xbmString.c_str();
-
- // At least 2 "#define <string> <unsigned>" sequences are required. These
- // specify the width and height of the image.
- int width, height;
- if (!ImageDecoder::isSizeAvailable()) {
- int count;
- if (sscanf(&input[m_decodeOffset], "#define %*s %i #define %*s %i%n",
- &width, &height, &count) != 2)
- return false;
-
- // The width and height need to follow some rules.
- if (width < 0 || width > maxDimension || height < 0 || height > maxDimension) {
- // If this happens, decoding should not continue.
- setFailed();
- return false;
- }
-
- if (!setSize(width, height)) {
- setFailed();
- return false;
- }
- m_decodeOffset += count;
- ASSERT(m_decodeOffset <= m_xbmString.size());
- }
-
- ASSERT(ImageDecoder::isSizeAvailable());
-
- // Now we're looking for something that tells us that we've seen all of the
- // "#define <string> <unsigned>" sequences that we're going to. Mozilla
- // just looks for " char " or " short ". We'll do the same.
- if (m_dataType == Unknown) {
- const char* x11hint = " char ";
- const char* x11HintLocation = strstr(&input[m_decodeOffset], x11hint);
- if (x11HintLocation) {
- m_dataType = X11;
- m_decodeOffset += ((x11HintLocation - &input[m_decodeOffset]) + strlen(x11hint));
- } else {
- const char* x10hint = " short ";
- const char* x10HintLocation = strstr(&input[m_decodeOffset], x10hint);
- if (x10HintLocation) {
- m_dataType = X10;
- m_decodeOffset += ((x10HintLocation - &input[m_decodeOffset]) + strlen(x10hint));
- } else
- return false;
- }
- ASSERT(m_decodeOffset <= m_xbmString.size());
- }
-
- // Find the start of the data. Again, we do what mozilla does and just
- // look for a '{' in the input.
- const char* found = strchr(&input[m_decodeOffset], '{');
- if (!found)
- return false;
-
- // Advance to character after the '{'
- m_decodeOffset += ((found - &input[m_decodeOffset]) + 1);
- ASSERT(m_decodeOffset <= m_xbmString.size());
- m_decodedHeader = true;
-
- return true;
-}
-
-// The data in an XBM file is provided as an array of either "char" or "short"
-// values. These values are decoded one at a time using strtoul() and the bits
-// are used to set the alpha value for the image.
-//
-// The value for the color is always set to RGB(0,0,0), the alpha value takes
-// care of whether or not the pixel shows up.
-//
-// Since the data may arrive in chunks, and many prefixes of valid numbers are
-// themselves valid numbers, this code needs to check to make sure that the
-// value is not truncated. This is done by consuming space after the value
-// read until a ',' or a '}' occurs. In a valid XBM, one of these characters
-// will occur after each value.
-//
-// The checks after strtoul are based on Mozilla's nsXBMDecoder.cpp.
-bool XBMImageDecoder::decodeDatum(uint16_t* result)
-{
- const char* input = m_xbmString.c_str();
- char* endPtr;
- const uint16_t value = strtoul(&input[m_decodeOffset], &endPtr, 0);
-
- // End of input or couldn't decode anything, can't go any further.
- if (endPtr == &input[m_decodeOffset] || !*endPtr)
- return false;
-
- // Possibly a hex value truncated at "0x". Need more data.
- if (value == 0 && (*endPtr == 'x' || *endPtr == 'X'))
- return false;
-
- // Skip whitespace
- while (*endPtr && isspace(*endPtr))
- ++endPtr;
-
- // Out of input, don't know what comes next.
- if (!*endPtr)
- return false;
-
- // If the next non-whitespace character is not one of these, it's an error.
- // Every valid entry in the data array needs to be followed by ',' or '}'.
- if (*endPtr != ',' && *endPtr != '}') {
- setFailed();
- return false;
- }
-
- // At this point we have a value.
- *result = value;
-
- // Skip over the decoded value plus the delimiter (',' or '}').
- m_decodeOffset += ((endPtr - &input[m_decodeOffset]) + 1);
- ASSERT(m_decodeOffset <= m_xbmString.size());
-
- return true;
-}
-
-bool XBMImageDecoder::decodeData()
-{
- ASSERT(m_decodeOffset <= m_xbmString.size());
- ASSERT(m_decodedHeader && !m_frameBufferCache.isEmpty());
-
- RGBA32Buffer& frame = m_frameBufferCache[0];
-
- ASSERT(frame.status() == RGBA32Buffer::FramePartial);
-
- const int bitsPerRow = size().width();
-
- ASSERT(m_dataType != Unknown);
-
- while (m_bitsDecoded < (size().width() * size().height())) {
- uint16_t value;
- if (!decodeDatum(&value))
- return false;
-
- int x = m_bitsDecoded % bitsPerRow;
- const int y = m_bitsDecoded / bitsPerRow;
-
- // How many bits will be written?
- const int bits = std::min(bitsPerRow - x, (m_dataType == X11) ? 8 : 16);
-
- // Only the alpha channel matters here, so the color values are always
- // set to 0.
- for (int i = 0; i < bits; ++i)
- frame.setRGBA(x++, y, 0, 0, 0, value & (1 << i) ? 255 : 0);
-
- m_bitsDecoded += bits;
- }
-
- frame.setStatus(RGBA32Buffer::FrameComplete);
-
- return true;
-}
-
-// Decode as much as we can of the XBM file.
-void XBMImageDecoder::decodeXBM(bool sizeOnly)
-{
- if (failed())
- return;
-
- bool decodeResult = false;
-
- if (!m_decodedHeader)
- decodeResult = decodeHeader();
-
- if (m_decodedHeader && !sizeOnly)
- decodeResult = decodeData();
-
- // The header or the data could not be decoded, but there is no more
- // data: decoding has failed.
- if (!decodeResult && m_allDataReceived)
- setFailed();
-}
-
-} // namespace WebCore
diff --git a/WebCore/platform/image-decoders/skia/XBMImageDecoder.h b/WebCore/platform/image-decoders/skia/XBMImageDecoder.h
deleted file mode 100644
index cdcf8e6..0000000
--- a/WebCore/platform/image-decoders/skia/XBMImageDecoder.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * 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.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 THE COPYRIGHT
- * OWNER 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 XBMImageDecoder_h
-#define XBMImageDecoder_h
-
-#include <string>
-#include "ImageDecoder.h"
-
-namespace WebCore {
-
- // This class decodes the XBM image format.
- class XBMImageDecoder : public ImageDecoder {
- public:
- XBMImageDecoder();
- virtual ~XBMImageDecoder() {}
-
- virtual String filenameExtension() const { return "xbm"; }
-
- virtual void setData(SharedBuffer* data, bool allDataReceived);
- // Whether or not the size information has been decoded yet.
- virtual bool isSizeAvailable() const;
- virtual RGBA32Buffer* frameBufferAtIndex(size_t index);
-
- private:
- // Restricts image size to something "reasonable".
- // This protects agains ridiculously large XBMs and prevents bad things
- // like overflow of m_bitsDecoded.
- static const int maxDimension = 65535;
-
- // In X10, an array of type "short" is used to declare the image bits,
- // but in X11, the type is "char".
- enum DataType {
- Unknown,
- X10,
- X11,
- };
-
- bool decodeHeader();
- bool decodeDatum(uint16_t* result);
- bool decodeData();
- void decodeXBM(bool sizeOnly);
-
- std::string m_xbmString; // Null-terminated copy of the XBM data.
- size_t m_decodeOffset; // The current offset in m_xbmString for decoding.
- bool m_allDataReceived;
- bool m_decodedHeader;
- enum DataType m_dataType;
- int m_bitsDecoded;
- };
-
-} // namespace WebCore
-
-#endif
diff --git a/WebCore/platform/image-decoders/wx/ImageDecoderWx.cpp b/WebCore/platform/image-decoders/wx/ImageDecoderWx.cpp
new file mode 100644
index 0000000..8e8809e
--- /dev/null
+++ b/WebCore/platform/image-decoders/wx/ImageDecoderWx.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * 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.
+ */
+
+#include "config.h"
+#include "ImageDecoder.h"
+
+// FIXME: Are all these needed?
+#include <wx/defs.h>
+#include <wx/bitmap.h>
+#if USE(WXGC)
+#include <wx/graphics.h>
+#endif
+#include <wx/image.h>
+#include <wx/rawbmp.h>
+
+namespace WebCore {
+
+RGBA32Buffer::RGBA32Buffer()
+ : m_hasAlpha(false)
+ , m_status(FrameEmpty)
+ , m_duration(0)
+ , m_disposalMethod(DisposeNotSpecified)
+{
+}
+
+void RGBA32Buffer::clear()
+{
+ m_bytes.clear();
+ m_status = FrameEmpty;
+ // NOTE: Do not reset other members here; clearFrameBufferCache()
+ // calls this to free the bitmap data, but other functions like
+ // initFrameBuffer() and frameComplete() may still need to read
+ // other metadata out of this frame later.
+}
+
+void RGBA32Buffer::zeroFill()
+{
+ m_bytes.fill(0);
+ m_hasAlpha = true;
+}
+
+void RGBA32Buffer::copyBitmapData(const RGBA32Buffer& other)
+{
+ if (this == &other)
+ return;
+
+ m_bytes = other.m_bytes;
+ m_size = other.m_size;
+ setHasAlpha(other.m_hasAlpha);
+}
+
+bool RGBA32Buffer::setSize(int newWidth, int newHeight)
+{
+ // NOTE: This has no way to check for allocation failure if the
+ // requested size was too big...
+ m_bytes.resize(newWidth * newHeight);
+ m_size = IntSize(newWidth, newHeight);
+
+ // Zero the image.
+ zeroFill();
+
+ return true;
+}
+
+NativeImagePtr RGBA32Buffer::asNewNativeImage() const
+{
+ const unsigned char* bytes = (const unsigned char*)m_bytes.data();
+
+ typedef wxPixelData<wxBitmap, wxAlphaPixelFormat> WxPixelData;
+
+ wxBitmap* bmp = new wxBitmap(width(), height(), 32);
+ WxPixelData data(*bmp);
+
+ int rowCounter = 0;
+ long pixelCounter = 0;
+
+ WxPixelData::Iterator p(data);
+
+ WxPixelData::Iterator rowStart = p;
+
+ // NB: It appears that the data is in BGRA format instead of RGBA format.
+ // This code works properly on both ppc and intel, meaning the issue is
+ // likely not an issue of byte order getting mixed up on different archs.
+ for (long i = 0; i < m_bytes.size() * sizeof(PixelData); i += sizeof(PixelData)) {
+ p.Red() = bytes[i+2];
+ p.Green() = bytes[i+1];
+ p.Blue() = bytes[i+0];
+ p.Alpha() = bytes[i+3];
+
+ p++;
+
+ pixelCounter++;
+ if ( (pixelCounter % width() ) == 0 ) {
+ rowCounter++;
+ p = rowStart;
+ p.MoveTo(data, 0, rowCounter);
+ }
+
+ }
+#if !wxCHECK_VERSION(2,9,0)
+ bmp->UseAlpha();
+#endif
+ ASSERT(bmp->IsOk());
+
+#if USE(WXGC)
+ wxGraphicsBitmap* bitmap = new wxGraphicsBitmap(wxGraphicsRenderer::GetDefaultRenderer()->CreateBitmap(*bmp));
+ delete bmp;
+ return bitmap;
+#else
+ return bmp;
+#endif
+}
+
+bool RGBA32Buffer::hasAlpha() const
+{
+ return m_hasAlpha;
+}
+
+void RGBA32Buffer::setHasAlpha(bool alpha)
+{
+ m_hasAlpha = alpha;
+}
+
+void RGBA32Buffer::setStatus(FrameStatus status)
+{
+ m_status = status;
+}
+
+RGBA32Buffer& RGBA32Buffer::operator=(const RGBA32Buffer& other)
+{
+ if (this == &other)
+ return *this;
+
+ copyBitmapData(other);
+ setRect(other.rect());
+ setStatus(other.status());
+ setDuration(other.duration());
+ setDisposalMethod(other.disposalMethod());
+ return *this;
+}
+
+int RGBA32Buffer::width() const {
+ return m_size.width();
+}
+
+int RGBA32Buffer::height() const {
+ return m_size.height();
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/image-decoders/xbm/XBMImageDecoder.cpp b/WebCore/platform/image-decoders/xbm/XBMImageDecoder.cpp
index 3e8ae57..332bc72 100644
--- a/WebCore/platform/image-decoders/xbm/XBMImageDecoder.cpp
+++ b/WebCore/platform/image-decoders/xbm/XBMImageDecoder.cpp
@@ -1,42 +1,278 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- *
+ * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
+ *
* 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
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
+
#include "config.h"
#include "XBMImageDecoder.h"
-
-namespace WebCore
+
+#include "ASCIICType.h"
+
+#include <algorithm>
+#include <cstdio>
+
+namespace WebCore {
+
+XBMImageDecoder::XBMImageDecoder()
+ : m_decodeOffset(0)
+ , m_allDataReceived(false)
+ , m_decodedHeader(false)
+ , m_dataType(Unknown)
+ , m_bitsDecoded(0)
{
+}
-bool XBMImageDecoder::isSizeAvailable() const
+void XBMImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
{
- return false;
+ ImageDecoder::setData(data, allDataReceived);
+ m_xbmString = data->buffer();
+ m_xbmString.append('\0');
+
+ m_allDataReceived = allDataReceived;
}
-
+
+bool XBMImageDecoder::isSizeAvailable()
+{
+ if (!ImageDecoder::isSizeAvailable() && !m_failed)
+ decode(true);
+
+ return ImageDecoder::isSizeAvailable();
+}
+
RGBA32Buffer* XBMImageDecoder::frameBufferAtIndex(size_t index)
{
- return 0;
+ if (index)
+ return 0;
+
+ if (m_frameBufferCache.isEmpty())
+ m_frameBufferCache.resize(1);
+
+ // Attempt to get the size if we don't have it yet.
+ if (!ImageDecoder::isSizeAvailable())
+ decode(true);
+
+ // Initialize the framebuffer if needed.
+ RGBA32Buffer& buffer = m_frameBufferCache[0];
+ if (!failed() && ImageDecoder::isSizeAvailable()
+ && (buffer.status() == RGBA32Buffer::FrameEmpty)) {
+ if (!buffer.setSize(size().width(), size().height())) {
+ m_failed = true;
+ return 0;
+ }
+ buffer.setStatus(RGBA32Buffer::FramePartial);
+
+ // For XBMs, the frame always fills the entire image.
+ buffer.setRect(IntRect(IntPoint(), size()));
+ }
+
+ // Keep trying to decode until we've got the entire image.
+ if (buffer.status() == RGBA32Buffer::FramePartial)
+ decode(false);
+
+ return &buffer;
+}
+
+bool XBMImageDecoder::decodeHeader()
+{
+ ASSERT(m_decodeOffset <= m_xbmString.size());
+ ASSERT(!m_decodedHeader);
+
+ const char* input = m_xbmString.data();
+
+ // At least 2 "#define <string> <unsigned>" sequences are required. These
+ // specify the width and height of the image.
+ int width, height;
+ if (!ImageDecoder::isSizeAvailable()) {
+ int count;
+ if (sscanf(&input[m_decodeOffset], "#define %*s %i #define %*s %i%n",
+ &width, &height, &count) != 2)
+ return false;
+
+ // The width and height need to follow some rules.
+ if (width < 0 || width > maxDimension || height < 0 || height > maxDimension) {
+ // If this happens, decoding should not continue.
+ setFailed();
+ return false;
+ }
+
+ if (!setSize(width, height)) {
+ setFailed();
+ return false;
+ }
+ m_decodeOffset += count;
+ ASSERT(m_decodeOffset <= m_xbmString.size());
+ }
+
+ ASSERT(ImageDecoder::isSizeAvailable());
+
+ // Now we're looking for something that tells us that we've seen all of the
+ // "#define <string> <unsigned>" sequences that we're going to. Mozilla
+ // just looks for " char " or " short ". We'll do the same.
+ if (m_dataType == Unknown) {
+ const char* x11hint = " char ";
+ const char* x11HintLocation = strstr(&input[m_decodeOffset], x11hint);
+ if (x11HintLocation) {
+ m_dataType = X11;
+ m_decodeOffset += ((x11HintLocation - &input[m_decodeOffset]) + strlen(x11hint));
+ } else {
+ const char* x10hint = " short ";
+ const char* x10HintLocation = strstr(&input[m_decodeOffset], x10hint);
+ if (x10HintLocation) {
+ m_dataType = X10;
+ m_decodeOffset += ((x10HintLocation - &input[m_decodeOffset]) + strlen(x10hint));
+ } else
+ return false;
+ }
+ ASSERT(m_decodeOffset <= m_xbmString.size());
+ }
+
+ // Find the start of the data. Again, we do what mozilla does and just
+ // look for a '{' in the input.
+ const char* found = strchr(&input[m_decodeOffset], '{');
+ if (!found)
+ return false;
+
+ // Advance to character after the '{'
+ m_decodeOffset += ((found - &input[m_decodeOffset]) + 1);
+ ASSERT(m_decodeOffset <= m_xbmString.size());
+ m_decodedHeader = true;
+
+ return true;
+}
+
+// The data in an XBM file is provided as an array of either "char" or "short"
+// values. These values are decoded one at a time using strtoul() and the bits
+// are used to set the alpha value for the image.
+//
+// The value for the color is always set to RGB(0,0,0), the alpha value takes
+// care of whether or not the pixel shows up.
+//
+// Since the data may arrive in chunks, and many prefixes of valid numbers are
+// themselves valid numbers, this code needs to check to make sure that the
+// value is not truncated. This is done by consuming space after the value
+// read until a ',' or a '}' occurs. In a valid XBM, one of these characters
+// will occur after each value.
+//
+// The checks after strtoul are based on Mozilla's nsXBMDecoder.cpp.
+bool XBMImageDecoder::decodeDatum(uint16_t* result)
+{
+ const char* input = m_xbmString.data();
+ char* endPtr;
+ const uint16_t value = strtoul(&input[m_decodeOffset], &endPtr, 0);
+
+ // End of input or couldn't decode anything, can't go any further.
+ if (endPtr == &input[m_decodeOffset] || !*endPtr)
+ return false;
+
+ // Possibly a hex value truncated at "0x". Need more data.
+ if (value == 0 && (*endPtr == 'x' || *endPtr == 'X'))
+ return false;
+
+ // Skip whitespace
+ while (*endPtr && isASCIISpace(*endPtr))
+ ++endPtr;
+
+ // Out of input, don't know what comes next.
+ if (!*endPtr)
+ return false;
+
+ // If the next non-whitespace character is not one of these, it's an error.
+ // Every valid entry in the data array needs to be followed by ',' or '}'.
+ if (*endPtr != ',' && *endPtr != '}') {
+ setFailed();
+ return false;
+ }
+
+ // At this point we have a value.
+ *result = value;
+
+ // Skip over the decoded value plus the delimiter (',' or '}').
+ m_decodeOffset += ((endPtr - &input[m_decodeOffset]) + 1);
+ ASSERT(m_decodeOffset <= m_xbmString.size());
+
+ return true;
+}
+
+bool XBMImageDecoder::decodeData()
+{
+ ASSERT(m_decodeOffset <= m_xbmString.size());
+ ASSERT(m_decodedHeader && !m_frameBufferCache.isEmpty());
+
+ RGBA32Buffer& frame = m_frameBufferCache[0];
+
+ ASSERT(frame.status() == RGBA32Buffer::FramePartial);
+
+ const int bitsPerRow = size().width();
+
+ ASSERT(m_dataType != Unknown);
+
+ while (m_bitsDecoded < (size().width() * size().height())) {
+ uint16_t value;
+ if (!decodeDatum(&value))
+ return false;
+
+ int x = m_bitsDecoded % bitsPerRow;
+ const int y = m_bitsDecoded / bitsPerRow;
+
+ // How many bits will be written?
+ const int bits = std::min(bitsPerRow - x, (m_dataType == X11) ? 8 : 16);
+
+ // Only the alpha channel matters here, so the color values are always
+ // set to 0.
+ for (int i = 0; i < bits; ++i)
+ frame.setRGBA(x++, y, 0, 0, 0, value & (1 << i) ? 255 : 0);
+
+ m_bitsDecoded += bits;
+ }
+
+ frame.setStatus(RGBA32Buffer::FrameComplete);
+
+ return true;
+}
+
+// Decode as much as we can of the XBM file.
+void XBMImageDecoder::decode(bool sizeOnly)
+{
+ if (failed())
+ return;
+
+ bool decodeResult = false;
+
+ if (!m_decodedHeader)
+ decodeResult = decodeHeader();
+
+ if (m_decodedHeader && !sizeOnly)
+ decodeResult = decodeData();
+
+ // The header or the data could not be decoded, but there is no more
+ // data: decoding has failed.
+ if (!decodeResult && m_allDataReceived)
+ setFailed();
}
} // namespace WebCore
diff --git a/WebCore/platform/image-decoders/xbm/XBMImageDecoder.h b/WebCore/platform/image-decoders/xbm/XBMImageDecoder.h
index 80cfb3f..00f62ce 100644
--- a/WebCore/platform/image-decoders/xbm/XBMImageDecoder.h
+++ b/WebCore/platform/image-decoders/xbm/XBMImageDecoder.h
@@ -1,26 +1,31 @@
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- *
+ * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
+ *
* 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
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef XBMImageDecoder_h
@@ -30,17 +35,47 @@
namespace WebCore {
- class XBMImageReader;
-
// This class decodes the XBM image format.
class XBMImageDecoder : public ImageDecoder {
public:
+ XBMImageDecoder();
+ virtual ~XBMImageDecoder() {}
+
virtual String filenameExtension() const { return "xbm"; }
+ virtual void setData(SharedBuffer* data, bool allDataReceived);
// Whether or not the size information has been decoded yet.
- virtual bool isSizeAvailable() const;
-
+ virtual bool isSizeAvailable();
virtual RGBA32Buffer* frameBufferAtIndex(size_t index);
+
+ private:
+ // Restricts image size to something "reasonable".
+ // This protects agains ridiculously large XBMs and prevents bad things
+ // like overflow of m_bitsDecoded.
+ static const int maxDimension = 65535;
+
+ // In X10, an array of type "short" is used to declare the image bits,
+ // but in X11, the type is "char".
+ enum DataType {
+ Unknown,
+ X10,
+ X11,
+ };
+
+ bool decodeHeader();
+ bool decodeDatum(uint16_t* result);
+ bool decodeData();
+ void decode(bool sizeOnly);
+
+ // FIXME: Copying all the XBM data just so we can NULL-terminate, just
+ // so we can use sscanf() and friends, is lame. The decoder should be
+ // rewritten to operate on m_data directly.
+ Vector<char> m_xbmString; // Null-terminated copy of the XBM data.
+ size_t m_decodeOffset; // The current offset in m_xbmString for decoding.
+ bool m_allDataReceived;
+ bool m_decodedHeader;
+ enum DataType m_dataType;
+ int m_bitsDecoded;
};
} // namespace WebCore