Index: Source/platform/image-decoders/bmp/BMPImageReader.h |
diff --git a/Source/platform/image-decoders/bmp/BMPImageReader.h b/Source/platform/image-decoders/bmp/BMPImageReader.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3d109cb9e6ebb90913ab7561c10dfd722ca6dbfe |
--- /dev/null |
+++ b/Source/platform/image-decoders/bmp/BMPImageReader.h |
@@ -0,0 +1,356 @@ |
+/* |
+ * 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 BMPImageReader_h |
+#define BMPImageReader_h |
+ |
+#include <stdint.h> |
+#include "platform/image-decoders/ImageDecoder.h" |
+#include "wtf/CPU.h" |
+ |
+namespace WebCore { |
+ |
+// 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 PLATFORM_EXPORT BMPImageReader { |
+ WTF_MAKE_FAST_ALLOCATED; |
+public: |
+ // 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()[offset], 2); |
+ #if CPU(BIG_ENDIAN) |
+ result = ((result & 0xff) << 8) | ((result & 0xff00) >> 8); |
+ #endif |
+ return result; |
+ } |
+ |
+ static inline uint32_t readUint32(SharedBuffer* data, int offset) |
+ { |
+ uint32_t result; |
+ memcpy(&result, &data->data()[offset], 4); |
+ #if CPU(BIG_ENDIAN) |
+ result = ((result & 0xff) << 24) | ((result & 0xff00) << 8) | ((result & 0xff0000) >> 8) | ((result & 0xff000000) >> 24); |
+ #endif |
+ return result; |
+ } |
+ |
+ // |parent| is the decoder that owns us. |
+ // |startOffset| points to the start of the BMP within the file. |
+ // |buffer| points at an empty ImageFrame that we'll initialize and |
+ // fill with decoded data. |
+ BMPImageReader(ImageDecoder* parent, size_t decodedAndHeaderOffset, size_t imgDataOffset, bool usesAndMask); |
+ |
+ void setBuffer(ImageFrame* buffer) { m_buffer = buffer; } |
+ void setData(SharedBuffer* data) { m_data = data; } |
+ |
+ // 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. |
+ enum CompressionType { |
+ // Universal types |
+ RGB = 0, |
+ RLE8 = 1, |
+ RLE4 = 2, |
+ // Windows V3+ only |
+ BITFIELDS = 3, |
+ JPEG = 4, |
+ PNG = 5, |
+ // OS/2 2.x-only |
+ HUFFMAN1D, // Stored in file as 3 |
+ RLE24, // Stored in file as 4 |
+ }; |
+ enum AndMaskState { |
+ None, |
+ NotYetDecoded, |
+ Decoding, |
+ }; |
+ enum ProcessingResult { |
+ Success, |
+ Failure, |
+ InsufficientData, |
+ }; |
+ |
+ // These are based on the Windows BITMAPINFOHEADER and RGBTRIPLE |
+ // structs, but with unnecessary entries removed. |
+ struct BitmapInfoHeader { |
+ uint32_t biSize; |
+ int32_t biWidth; |
+ int32_t biHeight; |
+ uint16_t biBitCount; |
+ CompressionType biCompression; |
+ uint32_t biClrUsed; |
+ }; |
+ struct RGBTriple { |
+ uint8_t rgbBlue; |
+ uint8_t rgbGreen; |
+ uint8_t rgbRed; |
+ }; |
+ |
+ inline uint16_t readUint16(int offset) const |
+ { |
+ return readUint16(m_data.get(), m_decodedOffset + offset); |
+ } |
+ |
+ 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(); |
+ |
+ // 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 |
+ { |
+ // Windows V4 info header is 108 bytes. V5 is 124 bytes. |
+ return (m_infoHeader.biSize == 108) || (m_infoHeader.biSize == 124); |
+ } |
+ |
+ // 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(); |
+ |
+ // 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(); |
+ |
+ // 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. |
+ // * 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 InsufficientData if |
+ // there wasn't enough data to decode the whole image. |
+ // |
+ // This function returns a ProcessingResult instead of a bool so that it |
+ // can avoid calling m_parent->setFailed(), which could lead to memory |
+ // corruption since that will delete |this| but some callers still want |
+ // to access member variables after this returns. |
+ ProcessingResult 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. |
+ inline bool pastEndOfImage(int numRows) |
+ { |
+ return m_isTopDown ? ((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(int bytesPerPixel) const |
+ { |
+ const int offset = m_coord.x() * bytesPerPixel; |
+ switch (bytesPerPixel) { |
+ case 2: |
+ 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. |
+ uint32_t pixel; |
+ memcpy(&pixel, &m_data->data()[m_decodedOffset + offset], 3); |
+ #if CPU(BIG_ENDIAN) |
+ pixel = ((pixel & 0xff00) << 8) | ((pixel & 0xff0000) >> 8) | ((pixel & 0xff000000) >> 24); |
+ #endif |
+ return pixel; |
+ } |
+ |
+ case 4: |
+ return readUint32(offset); |
+ |
+ default: |
+ ASSERT_NOT_REACHED(); |
+ return 0; |
+ } |
+ } |
+ |
+ // 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]; |
+ } |
+ |
+ inline unsigned getAlpha(uint32_t pixel) const |
+ { |
+ // For images without alpha, return alpha of 0xff. |
+ return m_bitMasks[3] ? getComponent(pixel, 3) : 0xff; |
+ } |
+ |
+ // 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. |
+ inline void setI(size_t colorIndex) |
+ { |
+ 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) |
+ { |
+ 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) |
+ { |
+ 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|. |
+ void moveBufferToNextRow(); |
+ |
+ // The decoder that owns us. |
+ ImageDecoder* m_parent; |
+ |
+ // The destination for the pixel data. |
+ ImageFrame* 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. |
+ 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. |
+ bool m_isOS22x; |
+ |
+ // True if the BMP is not vertically flipped, that is, the first line of |
+ // raster data in the file is the top line of the image. |
+ bool m_isTopDown; |
+ |
+ // These flags get set to false as we finish each processing stage. |
+ 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. |
+ // |
+ // 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"...) |
+ uint32_t m_bitMasks[4]; |
+ int m_bitShiftsRight[4]; |
+ int m_bitShiftsLeft[4]; |
+ |
+ // The color palette, for paletted formats. |
+ size_t m_tableSizeInBytes; |
+ Vector<RGBTriple> m_colorTable; |
+ |
+ // The coordinate to which we've decoded the image. |
+ IntPoint m_coord; |
+ |
+ // Variables that track whether we've seen pixels with alpha values != 0 |
+ // and == 0, respectively. See comments in processNonRLEData() on how |
+ // 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 |
+ |
+#endif |