BMPImageReader.h   [plain text]


/*
 * 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.
 */

#pragma once

#include "ScalableImageDecoder.h"
#include <stdint.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 BMPImageReader {
    WTF_MAKE_FAST_ALLOCATED;
public:
    // Read a value from |data[offset]|, converting from little to native
    // endianness.
    static inline uint16_t readUint16(const SharedBuffer::DataSegment& 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(const SharedBuffer::DataSegment& 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 ScalableImageDecoderFrame that we'll initialize and
    // fill with decoded data.
    BMPImageReader(ScalableImageDecoder* parent, size_t decodedAndHeaderOffset, size_t imgDataOffset, bool usesAndMask);

    void setBuffer(ScalableImageDecoderFrame* buffer) { m_buffer = buffer; }
    void setData(SharedBuffer::DataSegment& 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, m_decodedOffset + offset);
    }

    inline uint32_t readUint32(int offset) const
    {
        return readUint32(*m_data, 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)
    {
        setPixel(m_colorTable[colorIndex].rgbRed, m_colorTable[colorIndex].rgbGreen, m_colorTable[colorIndex].rgbBlue, 0xff);
    }

    // Like setI(), but with the individual component values specified.
    inline void setPixel(unsigned red, unsigned green, unsigned blue, unsigned alpha)
    {
        m_buffer->backingStore()->setPixel(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)
    {
        if (endCoord <= m_coord.x())
            return;
        m_buffer->backingStore()->fillRect(IntRect(m_coord.x(), m_coord.y(), endCoord - m_coord.x(), 1), red, green, blue, alpha);
        m_coord.setX(endCoord);
    }

    // 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.
    ScalableImageDecoder* m_parent;

    // The destination for the pixel data.
    ScalableImageDecoderFrame* m_buffer;

    // The file to decode.
    RefPtr<SharedBuffer::DataSegment> 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