1635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project/*
2635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
3635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *
4635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * Redistribution and use in source and binary forms, with or without
5635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * modification, are permitted provided that the following conditions are
6635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * met:
7635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *
8635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *     * Redistributions of source code must retain the above copyright
9635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * notice, this list of conditions and the following disclaimer.
10635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *     * Redistributions in binary form must reproduce the above
11635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * copyright notice, this list of conditions and the following disclaimer
12635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * in the documentation and/or other materials provided with the
13635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * distribution.
14635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *     * Neither the name of Google Inc. nor the names of its
15635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * contributors may be used to endorse or promote products derived from
16635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * this software without specific prior written permission.
17635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *
18635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project */
30635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
31635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "config.h"
32635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "BMPImageReader.h"
33635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
34635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectnamespace WebCore {
35635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
36692e5dbf12901edacf14812a6fae25462920af42Steve BlockBMPImageReader::BMPImageReader(ImageDecoder* parent, size_t decodedAndHeaderOffset, size_t imgDataOffset, bool usesAndMask)
370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    : m_parent(parent)
380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    , m_buffer(0)
390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    , m_decodedOffset(decodedAndHeaderOffset)
400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    , m_headerOffset(decodedAndHeaderOffset)
410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    , m_imgDataOffset(imgDataOffset)
42635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    , m_isOS21x(false)
43635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    , m_isOS22x(false)
44635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    , m_isTopDown(false)
45635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    , m_needToProcessBitmasks(false)
46635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    , m_needToProcessColorTable(false)
47635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    , m_tableSizeInBytes(0)
48635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    , m_seenNonZeroAlphaPixel(false)
49635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    , m_seenZeroAlphaPixel(false)
500bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    , m_andMaskState(usesAndMask ? NotYetDecoded : None)
51635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
52635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Clue-in decodeBMP() that we need to detect the correct info header size.
53635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    memset(&m_infoHeader, 0, sizeof(m_infoHeader));
54635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
55635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochbool BMPImageReader::decodeBMP(bool onlySize)
57635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
58635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Calculate size of info header.
590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (!m_infoHeader.biSize && !readInfoHeaderSize())
600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return false;
61635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
62635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Read and process info header.
63692e5dbf12901edacf14812a6fae25462920af42Steve Block    if ((m_decodedOffset < (m_headerOffset + m_infoHeader.biSize)) && !processInfoHeader())
640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return false;
650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
660bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    // processInfoHeader() set the size, so if that's all we needed, we're done.
670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (onlySize)
680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return true;
69635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
70635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Read and process the bitmasks, if needed.
710bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (m_needToProcessBitmasks && !processBitmasks())
720bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return false;
73635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
74635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Read and process the color table, if needed.
750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (m_needToProcessColorTable && !processColorTable())
760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return false;
77635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    // Initialize the framebuffer if needed.
790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ASSERT(m_buffer);  // Parent should set this before asking us to decode!
8065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    if (m_buffer->status() == ImageFrame::FrameEmpty) {
81692e5dbf12901edacf14812a6fae25462920af42Steve Block        if (!m_buffer->setSize(m_parent->size().width(), m_parent->size().height()))
8206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen            return m_parent->setFailed(); // Unable to allocate.
8365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        m_buffer->setStatus(ImageFrame::FramePartial);
84635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // setSize() calls eraseARGB(), which resets the alpha flag, so we force
85635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // it back to false here.  We'll set it true below in all cases where
86635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // these 0s could actually show through.
870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_buffer->setHasAlpha(false);
880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        // For BMPs, the frame always fills the entire image.
902fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        m_buffer->setOriginalFrameRect(IntRect(IntPoint(), m_parent->size()));
910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
92635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (!m_isTopDown)
930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            m_coord.setY(m_parent->size().height() - 1);
94635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
95635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
96635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Decode the data.
97635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if ((m_andMaskState != Decoding) && !pastEndOfImage(0)) {
9806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        if ((m_infoHeader.biCompression != RLE4) && (m_infoHeader.biCompression != RLE8) && (m_infoHeader.biCompression != RLE24)) {
9906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen            const ProcessingResult result = processNonRLEData(false, 0);
10006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen            if (result != Success)
10106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen                return (result == Failure) ? m_parent->setFailed() : false;
10206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        } else if (!processRLEData())
1030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            return false;
104635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
105635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
106635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // If the image has an AND mask and there was no alpha data, process the
107635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // mask.
1080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if ((m_andMaskState == NotYetDecoded) && !m_buffer->hasAlpha()) {
109635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Reset decoding coordinates to start of image.
110635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        m_coord.setX(0);
1110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_coord.setY(m_isTopDown ? 0 : (m_parent->size().height() - 1));
112635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
113635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // The AND mask is stored as 1-bit data.
114635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        m_infoHeader.biBitCount = 1;
115635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
116635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        m_andMaskState = Decoding;
117635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
11806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    if (m_andMaskState == Decoding) {
11906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        const ProcessingResult result = processNonRLEData(false, 0);
12006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        if (result != Success)
12106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen            return (result == Failure) ? m_parent->setFailed() : false;
12206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    }
123635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
124635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Done!
12565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    m_buffer->setStatus(ImageFrame::FrameComplete);
1260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return true;
127635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
128635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
1290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochbool BMPImageReader::readInfoHeaderSize()
130635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
131635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Get size of info header.
132635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ASSERT(m_decodedOffset == m_headerOffset);
133692e5dbf12901edacf14812a6fae25462920af42Steve Block    if ((m_decodedOffset > m_data->size()) || ((m_data->size() - m_decodedOffset) < 4))
134635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return false;
1350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    m_infoHeader.biSize = readUint32(0);
136635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Don't increment m_decodedOffset here, it just makes the code in
137635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // processInfoHeader() more confusing.
138635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
139635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Don't allow the header to overflow (which would be harmless here, but
140635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // problematic or at least confusing in other places), or to overrun the
141635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // image data.
142692e5dbf12901edacf14812a6fae25462920af42Steve Block    if (((m_headerOffset + m_infoHeader.biSize) < m_headerOffset) || (m_imgDataOffset && (m_imgDataOffset < (m_headerOffset + m_infoHeader.biSize))))
14306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        return m_parent->setFailed();
144635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
145635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // See if this is a header size we understand:
146635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // OS/2 1.x: 12
147635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (m_infoHeader.biSize == 12)
148635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        m_isOS21x = true;
149635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Windows V3: 40
150635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    else if ((m_infoHeader.biSize == 40) || isWindowsV4Plus())
151635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        ;
152635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // OS/2 2.x: any multiple of 4 between 16 and 64, inclusive, or 42 or 46
153692e5dbf12901edacf14812a6fae25462920af42Steve Block    else if ((m_infoHeader.biSize >= 16) && (m_infoHeader.biSize <= 64) && (!(m_infoHeader.biSize & 3) || (m_infoHeader.biSize == 42) || (m_infoHeader.biSize == 46)))
154635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        m_isOS22x = true;
155635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    else
15606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        return m_parent->setFailed();
157635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
1580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return true;
159635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
160635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
1610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochbool BMPImageReader::processInfoHeader()
162635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
163635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Read info header.
164635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ASSERT(m_decodedOffset == m_headerOffset);
165692e5dbf12901edacf14812a6fae25462920af42Steve Block    if ((m_decodedOffset > m_data->size()) || ((m_data->size() - m_decodedOffset) < m_infoHeader.biSize) || !readInfoHeader())
166635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return false;
167635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_decodedOffset += m_infoHeader.biSize;
168635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
169635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Sanity-check header values.
1700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (!isInfoHeaderValid())
17106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        return m_parent->setFailed();
172635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
1730bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    // Set our size.
1740bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (!m_parent->setSize(m_infoHeader.biWidth, m_infoHeader.biHeight))
17506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        return false;
176635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
177635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // For paletted images, bitmaps can set biClrUsed to 0 to mean "all
178635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // colors", so set it to the maximum number of colors for this bit depth.
179635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Also do this for bitmaps that put too large a value here.
180635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (m_infoHeader.biBitCount < 16) {
181692e5dbf12901edacf14812a6fae25462920af42Steve Block      const uint32_t maxColors = static_cast<uint32_t>(1) << m_infoHeader.biBitCount;
182692e5dbf12901edacf14812a6fae25462920af42Steve Block      if (!m_infoHeader.biClrUsed || (m_infoHeader.biClrUsed > maxColors))
183692e5dbf12901edacf14812a6fae25462920af42Steve Block          m_infoHeader.biClrUsed = maxColors;
184635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
185635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
186635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // For any bitmaps that set their BitCount to the wrong value, reset the
187635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // counts now that we've calculated the number of necessary colors, since
188635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // other code relies on this value being correct.
189635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (m_infoHeader.biCompression == RLE8)
190635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        m_infoHeader.biBitCount = 8;
191635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    else if (m_infoHeader.biCompression == RLE4)
192635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        m_infoHeader.biBitCount = 4;
193635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
194635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Tell caller what still needs to be processed.
195635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (m_infoHeader.biBitCount >= 16)
196635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        m_needToProcessBitmasks = true;
197692e5dbf12901edacf14812a6fae25462920af42Steve Block    else if (m_infoHeader.biBitCount)
198635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        m_needToProcessColorTable = true;
199635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
200635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return true;
201635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
202635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
2030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochbool BMPImageReader::readInfoHeader()
204635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
205635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Pre-initialize some fields that not all headers set.
206635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_infoHeader.biCompression = RGB;
207635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_infoHeader.biClrUsed = 0;
208635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
209635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (m_isOS21x) {
2100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_infoHeader.biWidth = readUint16(4);
2110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_infoHeader.biHeight = readUint16(6);
212635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        ASSERT(m_andMaskState == None);  // ICO is a Windows format, not OS/2!
2130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_infoHeader.biBitCount = readUint16(10);
214635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return true;
215635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
216635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
2170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    m_infoHeader.biWidth = readUint32(4);
2180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    m_infoHeader.biHeight = readUint32(8);
219635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (m_andMaskState != None)
220635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        m_infoHeader.biHeight /= 2;
2210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    m_infoHeader.biBitCount = readUint16(14);
222635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
223635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Read compression type, if present.
224635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (m_infoHeader.biSize >= 20) {
2250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        uint32_t biCompression = readUint32(16);
226635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
227635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Detect OS/2 2.x-specific compression types.
228635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if ((biCompression == 3) && (m_infoHeader.biBitCount == 1)) {
229635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            m_infoHeader.biCompression = HUFFMAN1D;
230635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            m_isOS22x = true;
231635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        } else if ((biCompression == 4) && (m_infoHeader.biBitCount == 24)) {
232635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            m_infoHeader.biCompression = RLE24;
233635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            m_isOS22x = true;
2340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        } else if (biCompression > 5)
23506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen            return m_parent->setFailed(); // Some type we don't understand.
2360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        else
237692e5dbf12901edacf14812a6fae25462920af42Steve Block            m_infoHeader.biCompression = static_cast<CompressionType>(biCompression);
238635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
239635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
240635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Read colors used, if present.
241635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (m_infoHeader.biSize >= 36)
2420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_infoHeader.biClrUsed = readUint32(32);
243635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
244635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Windows V4+ can safely read the four bitmasks from 40-56 bytes in, so do
245635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // that here.  If the bit depth is less than 16, these values will be
246635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // ignored by the image data decoders.  If the bit depth is at least 16 but
247635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // the compression format isn't BITFIELDS, these values will be ignored and
248635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // overwritten* in processBitmasks().
249635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // NOTE: We allow alpha here.  Microsoft doesn't really document this well,
250635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // but some BMPs appear to use it.
251635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //
252635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // For non-Windows V4+, m_bitMasks[] et. al will be initialized later
253635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // during processBitmasks().
254635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //
255635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // *Except the alpha channel.  Bizarrely, some RGB bitmaps expect decoders
256635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // to pay attention to the alpha mask here, so there's a special case in
257635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // processBitmasks() that doesn't always overwrite that value.
258635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (isWindowsV4Plus()) {
2590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_bitMasks[0] = readUint32(40);
2600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_bitMasks[1] = readUint32(44);
2610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_bitMasks[2] = readUint32(48);
2620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_bitMasks[3] = readUint32(52);
263635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
264635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
265635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Detect top-down BMPs.
266635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (m_infoHeader.biHeight < 0) {
267635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        m_isTopDown = true;
268635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        m_infoHeader.biHeight = -m_infoHeader.biHeight;
269635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
270635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
271635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return true;
272635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
273635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
274635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectbool BMPImageReader::isInfoHeaderValid() const
275635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
276635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Non-positive widths/heights are invalid.  (We've already flipped the
277635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // sign of the height for top-down bitmaps.)
278692e5dbf12901edacf14812a6fae25462920af42Steve Block    if ((m_infoHeader.biWidth <= 0) || !m_infoHeader.biHeight)
279635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return false;
280635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
281635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Only Windows V3+ has top-down bitmaps.
282635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (m_isTopDown && (m_isOS21x || m_isOS22x))
283635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return false;
284635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
285635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Only bit depths of 1, 4, 8, or 24 are universally supported.
286692e5dbf12901edacf14812a6fae25462920af42Steve Block    if ((m_infoHeader.biBitCount != 1) && (m_infoHeader.biBitCount != 4) && (m_infoHeader.biBitCount != 8) && (m_infoHeader.biBitCount != 24)) {
287635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Windows V3+ additionally supports bit depths of 0 (for embedded
288635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // JPEG/PNG images), 16, and 32.
289692e5dbf12901edacf14812a6fae25462920af42Steve Block        if (m_isOS21x || m_isOS22x || (m_infoHeader.biBitCount && (m_infoHeader.biBitCount != 16) && (m_infoHeader.biBitCount != 32)))
290635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            return false;
291635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
292635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
293635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Each compression type is only valid with certain bit depths (except RGB,
294635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // which can be used with any bit depth).  Also, some formats do not
295635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // some compression types.
296635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    switch (m_infoHeader.biCompression) {
297635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    case RGB:
298692e5dbf12901edacf14812a6fae25462920af42Steve Block        if (!m_infoHeader.biBitCount)
299635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            return false;
300635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        break;
301635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
302635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    case RLE8:
303635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Supposedly there are undocumented formats like "BitCount = 1,
304635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Compression = RLE4" (which means "4 bit, but with a 2-color table"),
305635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // so also allow the paletted RLE compression types to have too low a
306635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // bit count; we'll correct this later.
307692e5dbf12901edacf14812a6fae25462920af42Steve Block        if (!m_infoHeader.biBitCount || (m_infoHeader.biBitCount > 8))
308635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            return false;
309635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        break;
310635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
311635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    case RLE4:
312635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // See comments in RLE8.
313692e5dbf12901edacf14812a6fae25462920af42Steve Block        if (!m_infoHeader.biBitCount || (m_infoHeader.biBitCount > 4))
314635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            return false;
315635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        break;
316635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
317635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    case BITFIELDS:
318635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Only valid for Windows V3+.
319692e5dbf12901edacf14812a6fae25462920af42Steve Block        if (m_isOS21x || m_isOS22x || ((m_infoHeader.biBitCount != 16) && (m_infoHeader.biBitCount != 32)))
320635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            return false;
321635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        break;
322635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
323635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    case JPEG:
324635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    case PNG:
325635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Only valid for Windows V3+.
326692e5dbf12901edacf14812a6fae25462920af42Steve Block        if (m_isOS21x || m_isOS22x || m_infoHeader.biBitCount)
327635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            return false;
328635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        break;
329635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
330635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    case HUFFMAN1D:
331635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Only valid for OS/2 2.x.
332692e5dbf12901edacf14812a6fae25462920af42Steve Block        if (!m_isOS22x || (m_infoHeader.biBitCount != 1))
333635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            return false;
334635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        break;
335635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
336635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    case RLE24:
337635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Only valid for OS/2 2.x.
338692e5dbf12901edacf14812a6fae25462920af42Steve Block        if (!m_isOS22x || (m_infoHeader.biBitCount != 24))
339635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            return false;
340635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        break;
341635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
342635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    default:
343635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Some type we don't understand.  This should have been caught in
344635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // readInfoHeader().
345635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        ASSERT_NOT_REACHED();
346635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return false;
347635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
348635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
349635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Top-down bitmaps cannot be compressed; they must be RGB or BITFIELDS.
350692e5dbf12901edacf14812a6fae25462920af42Steve Block    if (m_isTopDown && (m_infoHeader.biCompression != RGB) && (m_infoHeader.biCompression != BITFIELDS))
351635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return false;
352635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
353635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Reject the following valid bitmap types that we don't currently bother
354635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // decoding.  Few other people decode these either, they're unlikely to be
355635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // in much use.
356635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // TODO(pkasting): Consider supporting these someday.
357635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //   * Bitmaps larger than 2^16 pixels in either dimension (Windows
358635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //     probably doesn't draw these well anyway, and the decoded data would
359635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //     take a lot of memory).
360692e5dbf12901edacf14812a6fae25462920af42Steve Block    if ((m_infoHeader.biWidth >= (1 << 16)) || (m_infoHeader.biHeight >= (1 << 16)))
361635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return false;
362635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //   * Windows V3+ JPEG-in-BMP and PNG-in-BMP bitmaps (supposedly not found
363635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //     in the wild, only used to send data to printers?).
364692e5dbf12901edacf14812a6fae25462920af42Steve Block    if ((m_infoHeader.biCompression == JPEG) || (m_infoHeader.biCompression == PNG))
365635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return false;
366635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //   * OS/2 2.x Huffman-encoded monochrome bitmaps (see
367635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //      http://www.fileformat.info/mirror/egff/ch09_05.htm , re: "G31D"
368635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //      algorithm).
369635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (m_infoHeader.biCompression == HUFFMAN1D)
370635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return false;
371635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
372635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return true;
373635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
374635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
3750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochbool BMPImageReader::processBitmasks()
376635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
377635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Create m_bitMasks[] values.
378635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (m_infoHeader.biCompression != BITFIELDS) {
379635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // The format doesn't actually use bitmasks.  To simplify the decode
380635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // logic later, create bitmasks for the RGB data.  For Windows V4+,
381635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // this overwrites the masks we read from the header, which are
382635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // supposed to be ignored in non-BITFIELDS cases.
383635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // 16 bits:    MSB <-                     xRRRRRGG GGGBBBBB -> LSB
384635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // 24/32 bits: MSB <- [AAAAAAAA] RRRRRRRR GGGGGGGG BBBBBBBB -> LSB
385635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        const int numBits = (m_infoHeader.biBitCount == 16) ? 5 : 8;
386692e5dbf12901edacf14812a6fae25462920af42Steve Block        for (int i = 0; i <= 2; ++i)
387692e5dbf12901edacf14812a6fae25462920af42Steve Block            m_bitMasks[i] = ((static_cast<uint32_t>(1) << (numBits * (3 - i))) - 1) ^ ((static_cast<uint32_t>(1) << (numBits * (2 - i))) - 1);
388635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
389635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // For Windows V4+ 32-bit RGB, don't overwrite the alpha mask from the
390635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // header (see note in readInfoHeader()).
391635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (m_infoHeader.biBitCount < 32)
392635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            m_bitMasks[3] = 0;
393635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        else if (!isWindowsV4Plus())
394635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            m_bitMasks[3] = static_cast<uint32_t>(0xff000000);
395635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    } else if (!isWindowsV4Plus()) {
396635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // For Windows V4+ BITFIELDS mode bitmaps, this was already done when
397635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // we read the info header.
398635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
399635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Fail if we don't have enough file space for the bitmasks.
4000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        static const size_t SIZEOF_BITMASKS = 12;
401692e5dbf12901edacf14812a6fae25462920af42Steve Block        if (((m_headerOffset + m_infoHeader.biSize + SIZEOF_BITMASKS) < (m_headerOffset + m_infoHeader.biSize)) || (m_imgDataOffset && (m_imgDataOffset < (m_headerOffset + m_infoHeader.biSize + SIZEOF_BITMASKS))))
40206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen            return m_parent->setFailed();
403635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
404635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Read bitmasks.
4050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if ((m_data->size() - m_decodedOffset) < SIZEOF_BITMASKS)
406635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            return false;
4070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_bitMasks[0] = readUint32(0);
4080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_bitMasks[1] = readUint32(4);
4090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_bitMasks[2] = readUint32(8);
410635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // No alpha in anything other than Windows V4+.
411635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        m_bitMasks[3] = 0;
412635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
413635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        m_decodedOffset += SIZEOF_BITMASKS;
414635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
415635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
416635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // We've now decoded all the non-image data we care about.  Skip anything
417635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // else before the actual raster data.
418635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (m_imgDataOffset)
419635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        m_decodedOffset = m_imgDataOffset;
420635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_needToProcessBitmasks = false;
421635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
422635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Check masks and set shift values.
423635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    for (int i = 0; i < 4; ++i) {
424635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Trim the mask to the allowed bit depth.  Some Windows V4+ BMPs
425635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // specify a bogus alpha channel in bits that don't exist in the pixel
426635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // data (for example, bits 25-31 in a 24-bit RGB format).
427635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (m_infoHeader.biBitCount < 32)
428692e5dbf12901edacf14812a6fae25462920af42Steve Block            m_bitMasks[i] &= ((static_cast<uint32_t>(1) << m_infoHeader.biBitCount) - 1);
429635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
430635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // For empty masks (common on the alpha channel, especially after the
431635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // trimming above), quickly clear the shifts and continue, to avoid an
432635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // infinite loop in the counting code below.
433635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        uint32_t tempMask = m_bitMasks[i];
434635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (!tempMask) {
435635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            m_bitShiftsRight[i] = m_bitShiftsLeft[i] = 0;
436635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            continue;
437635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
438635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
439635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Make sure bitmask does not overlap any other bitmasks.
440635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        for (int j = 0; j < i; ++j) {
4410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            if (tempMask & m_bitMasks[j])
44206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen                return m_parent->setFailed();
443635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
444635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
445635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Count offset into pixel data.
446635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        for (m_bitShiftsRight[i] = 0; !(tempMask & 1); tempMask >>= 1)
447635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            ++m_bitShiftsRight[i];
448635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
449635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Count size of mask.
450635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        for (m_bitShiftsLeft[i] = 8; tempMask & 1; tempMask >>= 1)
451635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            --m_bitShiftsLeft[i];
452635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
453635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Make sure bitmask is contiguous.
4540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (tempMask)
45506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen            return m_parent->setFailed();
456635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
457635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Since RGBABuffer tops out at 8 bits per channel, adjust the shift
458635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // amounts to use the most significant 8 bits of the channel.
459635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (m_bitShiftsLeft[i] < 0) {
460635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            m_bitShiftsRight[i] -= m_bitShiftsLeft[i];
461635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            m_bitShiftsLeft[i] = 0;
462635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
463635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
464635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
465635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return true;
466635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
467635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
4680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochbool BMPImageReader::processColorTable()
469635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
470635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_tableSizeInBytes = m_infoHeader.biClrUsed * (m_isOS21x ? 3 : 4);
471635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
472635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Fail if we don't have enough file space for the color table.
473692e5dbf12901edacf14812a6fae25462920af42Steve Block    if (((m_headerOffset + m_infoHeader.biSize + m_tableSizeInBytes) < (m_headerOffset + m_infoHeader.biSize)) || (m_imgDataOffset && (m_imgDataOffset < (m_headerOffset + m_infoHeader.biSize + m_tableSizeInBytes))))
47406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        return m_parent->setFailed();
475635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
476635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Read color table.
477692e5dbf12901edacf14812a6fae25462920af42Steve Block    if ((m_decodedOffset > m_data->size()) || ((m_data->size() - m_decodedOffset) < m_tableSizeInBytes))
478635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return false;
479635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_colorTable.resize(m_infoHeader.biClrUsed);
480635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    for (size_t i = 0; i < m_infoHeader.biClrUsed; ++i) {
4810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_colorTable[i].rgbBlue = m_data->data()[m_decodedOffset++];
4820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_colorTable[i].rgbGreen = m_data->data()[m_decodedOffset++];
4830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_colorTable[i].rgbRed = m_data->data()[m_decodedOffset++];
484635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Skip padding byte (not present on OS/2 1.x).
485635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (!m_isOS21x)
486635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            ++m_decodedOffset;
487635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
488635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
489635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // We've now decoded all the non-image data we care about.  Skip anything
490635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // else before the actual raster data.
491635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (m_imgDataOffset)
492635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        m_decodedOffset = m_imgDataOffset;
493635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_needToProcessColorTable = false;
494635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
495635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return true;
496635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
497635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
4980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochbool BMPImageReader::processRLEData()
499635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
5000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (m_decodedOffset > m_data->size())
501635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return false;
502635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
503635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // RLE decoding is poorly specified.  Two main problems:
504635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // (1) Are EOL markers necessary?  What happens when we have too many
505635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //     pixels for one row?
506635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //     http://www.fileformat.info/format/bmp/egff.htm says extra pixels
507635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //     should wrap to the next line.  Real BMPs I've encountered seem to
508635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //     instead expect extra pixels to be ignored until the EOL marker is
509635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //     seen, although this has only happened in a few cases and I suspect
510635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //     those BMPs may be invalid.  So we only change lines on EOL (or Delta
511635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //     with dy > 0), and fail in most cases when pixels extend past the end
512635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //     of the line.
513635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // (2) When Delta, EOL, or EOF are seen, what happens to the "skipped"
514635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //     pixels?
515635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //     http://www.daubnet.com/formats/BMP.html says these should be filled
516635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //     with color 0.  However, the "do nothing" and "don't care" comments
517635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //     of other references suggest leaving these alone, i.e. letting them
518635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //     be transparent to the background behind the image.  This seems to
519635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //     match how MSPAINT treats BMPs, so we do that.  Note that when we
520635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //     actually skip pixels for a case like this, we need to note on the
521635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    //     framebuffer that we have alpha.
522635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
523635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Impossible to decode row-at-a-time, so just do things as a stream of
524635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // bytes.
525635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    while (true) {
526635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Every entry takes at least two bytes; bail if there isn't enough
527635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // data.
5280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if ((m_data->size() - m_decodedOffset) < 2)
529635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            return false;
530635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
531635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // For every entry except EOF, we'd better not have reached the end of
532635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // the image.
5330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        const uint8_t count = m_data->data()[m_decodedOffset];
5340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        const uint8_t code = m_data->data()[m_decodedOffset + 1];
535692e5dbf12901edacf14812a6fae25462920af42Steve Block        if ((count || (code != 1)) && pastEndOfImage(0))
53606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen            return m_parent->setFailed();
537635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
538635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Decode.
53906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        if (!count) {
540635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            switch (code) {
541635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            case 0:  // Magic token: EOL
542635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // Skip any remaining pixels in this row.
5430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                if (m_coord.x() < m_parent->size().width())
5440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                    m_buffer->setHasAlpha(true);
545635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                moveBufferToNextRow();
546635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
547635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                m_decodedOffset += 2;
548635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                break;
549635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
550635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            case 1:  // Magic token: EOF
551635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // Skip any remaining pixels in the image.
552692e5dbf12901edacf14812a6fae25462920af42Steve Block                if ((m_coord.x() < m_parent->size().width()) || (m_isTopDown ? (m_coord.y() < (m_parent->size().height() - 1)) : (m_coord.y() > 0)))
5530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                    m_buffer->setHasAlpha(true);
554635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                return true;
555635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
556635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            case 2: {  // Magic token: Delta
557635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // The next two bytes specify dx and dy.  Bail if there isn't
558635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // enough data.
5590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                if ((m_data->size() - m_decodedOffset) < 4)
560635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    return false;
561635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
562635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // Fail if this takes us past the end of the desired row or
563635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // past the end of the image.
5640bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                const uint8_t dx = m_data->data()[m_decodedOffset + 2];
5650bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                const uint8_t dy = m_data->data()[m_decodedOffset + 3];
566692e5dbf12901edacf14812a6fae25462920af42Steve Block                if (dx || dy)
5670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                    m_buffer->setHasAlpha(true);
568692e5dbf12901edacf14812a6fae25462920af42Steve Block                if (((m_coord.x() + dx) > m_parent->size().width()) || pastEndOfImage(dy))
56906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen                    return m_parent->setFailed();
570635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
571635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // Skip intervening pixels.
572635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                m_coord.move(dx, m_isTopDown ? dy : -dy);
573635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
574635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                m_decodedOffset += 4;
575635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                break;
576635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            }
577635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
57806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen            default: { // Absolute mode
579635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // |code| pixels specified as in BI_RGB, zero-padded at the end
580635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // to a multiple of 16 bits.
581635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // Because processNonRLEData() expects m_decodedOffset to
582635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // point to the beginning of the pixel data, bump it past
583635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // the escape bytes and then reset if decoding failed.
584635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                m_decodedOffset += 2;
58506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen                const ProcessingResult result = processNonRLEData(true, code);
58606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen                if (result == Failure)
58706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen                    return m_parent->setFailed();
58806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen                if (result == InsufficientData) {
589635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    m_decodedOffset -= 2;
590635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    return false;
591635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                }
592635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                break;
593635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            }
59406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen            }
595635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        } else {  // Encoded mode
596635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // The following color data is repeated for |count| total pixels.
597635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // Strangely, some BMPs seem to specify excessively large counts
598635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // here; ignore pixels past the end of the row.
599692e5dbf12901edacf14812a6fae25462920af42Steve Block            const int endX = std::min(m_coord.x() + count, m_parent->size().width());
600635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
601635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            if (m_infoHeader.biCompression == RLE24) {
602635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // Bail if there isn't enough data.
6030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                if ((m_data->size() - m_decodedOffset) < 4)
604635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    return false;
605635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
606635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // One BGR triple that we copy |count| times.
607692e5dbf12901edacf14812a6fae25462920af42Steve Block                fillRGBA(endX, m_data->data()[m_decodedOffset + 3], m_data->data()[m_decodedOffset + 2], code, 0xff);
608635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                m_decodedOffset += 4;
609635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            } else {
610635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // RLE8 has one color index that gets repeated; RLE4 has two
611635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // color indexes in the upper and lower 4 bits of the byte,
612635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // which are alternated.
613635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                size_t colorIndexes[2] = {code, code};
614635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                if (m_infoHeader.biCompression == RLE4) {
615635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    colorIndexes[0] = (colorIndexes[0] >> 4) & 0xf;
616635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    colorIndexes[1] &= 0xf;
617635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                }
618692e5dbf12901edacf14812a6fae25462920af42Steve Block                if ((colorIndexes[0] >= m_infoHeader.biClrUsed) || (colorIndexes[1] >= m_infoHeader.biClrUsed))
61906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen                    return m_parent->setFailed();
620635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                for (int which = 0; m_coord.x() < endX; ) {
621635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    setI(colorIndexes[which]);
622635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    which = !which;
623635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                }
624635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
625635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                m_decodedOffset += 2;
626635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            }
627635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
628635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
629635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
630635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
63106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian MonsenBMPImageReader::ProcessingResult BMPImageReader::processNonRLEData(bool inRLE, int numPixels)
632635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
6330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (m_decodedOffset > m_data->size())
63406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        return InsufficientData;
635635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
636635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!inRLE)
6370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        numPixels = m_parent->size().width();
638635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
639635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Fail if we're being asked to decode more pixels than remain in the row.
640635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    const int endX = m_coord.x() + numPixels;
6410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (endX > m_parent->size().width())
64206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        return Failure;
643635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
644635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Determine how many bytes of data the requested number of pixels
645635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // requires.
646635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    const size_t pixelsPerByte = 8 / m_infoHeader.biBitCount;
647635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    const size_t bytesPerPixel = m_infoHeader.biBitCount / 8;
648692e5dbf12901edacf14812a6fae25462920af42Steve Block    const size_t unpaddedNumBytes = (m_infoHeader.biBitCount < 16) ? ((numPixels + pixelsPerByte - 1) / pixelsPerByte) : (numPixels * bytesPerPixel);
649635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // RLE runs are zero-padded at the end to a multiple of 16 bits.  Non-RLE
650635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // data is in rows and is zero-padded to a multiple of 32 bits.
651635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    const size_t alignBits = inRLE ? 1 : 3;
652635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    const size_t paddedNumBytes = (unpaddedNumBytes + alignBits) & ~alignBits;
653635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
654635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Decode as many rows as we can.  (For RLE, where we only want to decode
655635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // one row, we've already checked that this condition is true.)
656635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    while (!pastEndOfImage(0)) {
657635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Bail if we don't have enough data for the desired number of pixels.
6580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if ((m_data->size() - m_decodedOffset) < paddedNumBytes)
65906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen            return InsufficientData;
660635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
661635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (m_infoHeader.biBitCount < 16) {
662635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // Paletted data.  Pixels are stored little-endian within bytes.
663635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // Decode pixels one byte at a time, left to right (so, starting at
664635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // the most significant bits in the byte).
665635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            const uint8_t mask = (1 << m_infoHeader.biBitCount) - 1;
666635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            for (size_t byte = 0; byte < unpaddedNumBytes; ++byte) {
6670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                uint8_t pixelData = m_data->data()[m_decodedOffset + byte];
668692e5dbf12901edacf14812a6fae25462920af42Steve Block                for (size_t pixel = 0; (pixel < pixelsPerByte) && (m_coord.x() < endX); ++pixel) {
669692e5dbf12901edacf14812a6fae25462920af42Steve Block                    const size_t colorIndex = (pixelData >> (8 - m_infoHeader.biBitCount)) & mask;
670635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    if (m_andMaskState == Decoding) {
671635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                        // There's no way to accurately represent an AND + XOR
672635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                        // operation as an RGBA image, so where the AND values
673635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                        // are 1, we simply set the framebuffer pixels to fully
674635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                        // transparent, on the assumption that most ICOs on the
675635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                        // web will not be doing a lot of inverting.
676635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                        if (colorIndex) {
677635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                            setRGBA(0, 0, 0, 0);
6780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                            m_buffer->setHasAlpha(true);
679635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                        } else
680635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                            m_coord.move(1, 0);
681635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    } else {
6820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                        if (colorIndex >= m_infoHeader.biClrUsed)
68306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen                            return Failure;
684635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                        setI(colorIndex);
685635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    }
686635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    pixelData <<= m_infoHeader.biBitCount;
687635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                }
688635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            }
689635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        } else {
690635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            // RGB data.  Decode pixels one at a time, left to right.
691635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            while (m_coord.x() < endX) {
6920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                const uint32_t pixel = readCurrentPixel(bytesPerPixel);
693635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
694635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // Some BMPs specify an alpha channel but don't actually use it
695635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // (it contains all 0s).  To avoid displaying these images as
696635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // fully-transparent, decode as if images are fully opaque
697635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // until we actually see a non-zero alpha value; at that point,
698635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // reset any previously-decoded pixels to fully transparent and
699635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // continue decoding based on the real alpha channel values.
700635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // As an optimization, avoid setting "hasAlpha" to true for
701635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // images where all alpha values are 255; opaque images are
702635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                // faster to draw.
703635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                int alpha = getAlpha(pixel);
704692e5dbf12901edacf14812a6fae25462920af42Steve Block                if (!m_seenNonZeroAlphaPixel && !alpha) {
705635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    m_seenZeroAlphaPixel = true;
706635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    alpha = 255;
707635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                } else {
708635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    m_seenNonZeroAlphaPixel = true;
709635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    if (m_seenZeroAlphaPixel) {
7102fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                        m_buffer->zeroFillPixelData();
711635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                        m_seenZeroAlphaPixel = false;
712635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                    } else if (alpha != 255)
7130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                        m_buffer->setHasAlpha(true);
714635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                }
715635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
716635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                setRGBA(getComponent(pixel, 0), getComponent(pixel, 1),
717635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                        getComponent(pixel, 2), alpha);
718635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            }
719635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
720635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
721635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Success, keep going.
722635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        m_decodedOffset += paddedNumBytes;
723635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (inRLE)
72406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen            return Success;
725635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        moveBufferToNextRow();
726635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
727635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
728635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Finished decoding whole image.
72906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    return Success;
730635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
731635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
732635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid BMPImageReader::moveBufferToNextRow()
733635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
734635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_coord.move(-m_coord.x(), m_isTopDown ? 1 : -1);
735635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
736635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
737635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project} // namespace WebCore
738