|  | /* | 
|  | * 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 SKY_ENGINE_PLATFORM_IMAGE_DECODERS_BMP_BMPIMAGEREADER_H_ | 
|  | #define SKY_ENGINE_PLATFORM_IMAGE_DECODERS_BMP_BMPIMAGEREADER_H_ | 
|  |  | 
|  | #include <stdint.h> | 
|  | #include "platform/image-decoders/ImageDecoder.h" | 
|  | #include "sky/engine/wtf/CPU.h" | 
|  |  | 
|  | namespace blink { | 
|  |  | 
|  | // 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 isInICO); | 
|  |  | 
|  | 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 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 | 
|  | { | 
|  | uint8_t value = (pixel & m_bitMasks[component]) >> m_bitShiftsRight[component]; | 
|  | return m_lookupTableAddresses[component] ? m_lookupTableAddresses[component][value] : value; | 
|  | } | 
|  |  | 
|  | 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. | 
|  | uint32_t m_bitMasks[4]; | 
|  |  | 
|  | // Right shift values, meant to be applied after the masks. We need to shift | 
|  | // the bitfield values down from their offsets into the 32 bits of pixel | 
|  | // data, as well as truncate the least significant bits of > 8-bit fields. | 
|  | int m_bitShiftsRight[4]; | 
|  |  | 
|  | // We use a lookup table to convert < 8-bit values into 8-bit values. The | 
|  | // values in the table are "round(val * 255.0 / ((1 << n) - 1))" for an | 
|  | // n-bit source value. These elements are set to 0 for 8-bit sources. | 
|  | const uint8_t* m_lookupTableAddresses[4]; | 
|  |  | 
|  | // The color palette, for paletted formats. | 
|  | 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; | 
|  |  | 
|  | // BMPs-in-ICOs have a few differences from standalone BMPs, so we need to | 
|  | // know if we're in an ICO container. | 
|  | bool m_isInICO; | 
|  |  | 
|  | // 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). If |m_isInICO| is true, this variable tracks | 
|  | // whether we've begun decoding this mask yet. | 
|  | bool m_decodingAndMask; | 
|  | }; | 
|  |  | 
|  | } // namespace blink | 
|  |  | 
|  | #endif  // SKY_ENGINE_PLATFORM_IMAGE_DECODERS_BMP_BMPIMAGEREADER_H_ |