18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Redistribution and use in source and binary forms, with or without
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modification, are permitted provided that the following conditions
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * are met:
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 1. Redistributions of source code must retain the above copyright
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer in the
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    documentation and/or other materials provided with the distribution.
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h"
278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "GIFImageDecoder.h"
288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "GIFImageReader.h"
298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore {
318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
32f05b935882198ccf7d81675736e3aeb089c5113aBen MurdochGIFImageDecoder::GIFImageDecoder(ImageSource::AlphaOption alphaOption,
33f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch                                 ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption)
34f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    : ImageDecoder(alphaOption, gammaAndColorProfileOption)
35e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    , m_alreadyScannedThisDataForFrameCount(true)
365f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    , m_repetitionCount(cAnimationLoopOnce)
37d0825bca7fe65beaee391d30da42e937db621564Steve Block    , m_readOffset(0)
385f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
395f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectGIFImageDecoder::~GIFImageDecoder()
428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GIFImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
47dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (failed())
488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ImageDecoder::setData(data, allDataReceived);
518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
52692e5dbf12901edacf14812a6fae25462920af42Steve Block    // We need to rescan the frame count, as the new data may have changed it.
53692e5dbf12901edacf14812a6fae25462920af42Steve Block    m_alreadyScannedThisDataForFrameCount = false;
548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochbool GIFImageDecoder::isSizeAvailable()
578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
58dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (!ImageDecoder::isSizeAvailable())
59692e5dbf12901edacf14812a6fae25462920af42Steve Block         decode(0, GIFSizeQuery);
608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
610bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return ImageDecoder::isSizeAvailable();
628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochbool GIFImageDecoder::setSize(unsigned width, unsigned height)
65dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
6681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (ImageDecoder::isSizeAvailable() && size() == IntSize(width, height))
67dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch        return true;
68dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch
69dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (!ImageDecoder::setSize(width, height))
70dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return false;
71dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
72dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    prepareScaleDataIfNecessary();
73dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    return true;
74dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
75dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochsize_t GIFImageDecoder::frameCount()
778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
78692e5dbf12901edacf14812a6fae25462920af42Steve Block    if (!m_alreadyScannedThisDataForFrameCount) {
79692e5dbf12901edacf14812a6fae25462920af42Steve Block        // FIXME: Scanning all the data has O(n^2) behavior if the data were to
80692e5dbf12901edacf14812a6fae25462920af42Steve Block        // come in really slowly.  Might be interesting to try to clone our
81692e5dbf12901edacf14812a6fae25462920af42Steve Block        // existing read session to preserve state, but for now we just crawl
82692e5dbf12901edacf14812a6fae25462920af42Steve Block        // all the data.  Note that this is no worse than what ImageIO does on
83692e5dbf12901edacf14812a6fae25462920af42Steve Block        // Mac right now (it also crawls all the data again).
84d0825bca7fe65beaee391d30da42e937db621564Steve Block        GIFImageReader reader(0);
85d0825bca7fe65beaee391d30da42e937db621564Steve Block        reader.read((const unsigned char*)m_data->data(), m_data->size(), GIFFrameCountQuery, static_cast<unsigned>(-1));
86692e5dbf12901edacf14812a6fae25462920af42Steve Block        m_alreadyScannedThisDataForFrameCount = true;
87d0825bca7fe65beaee391d30da42e937db621564Steve Block        m_frameBufferCache.resize(reader.images_count);
88e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        for (int i = 0; i < reader.images_count; ++i)
89e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block            m_frameBufferCache[i].setPremultiplyAlpha(m_premultiplyAlpha);
908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return m_frameBufferCache.size();
938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectint GIFImageDecoder::repetitionCount() const
968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // This value can arrive at any point in the image data stream.  Most GIFs
988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // in the wild declare it near the beginning of the file, so it usually is
998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // set by the time we've decoded the size, but (depending on the GIF and the
10028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // packets sent back by the webserver) not always.  If the reader hasn't
10128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // seen a loop count yet, it will return cLoopCountNotSeen, in which case we
10228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // should default to looping once (the initial value for
10328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // |m_repetitionCount|).
10428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    //
10528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // There are two additional wrinkles here.  First, ImageSource::clear() may
10628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // destroy the reader, making the result from the reader _less_
10728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // authoritative on future calls if the recreated reader hasn't seen the
10828040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // loop count.  We don't need to special-case this because in this case the
10928040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // new reader will once again return cLoopCountNotSeen, and we won't
11028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // overwrite the cached correct value.
11128040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    //
11228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // Second, a GIF might never set a loop count at all, in which case we
11328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // should continue to treat it as a "loop once" animation.  We don't need
11428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // special code here either, because in this case we'll never change
11528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // |m_repetitionCount| from its default value.
11628040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    if (m_reader && (m_reader->loop_count != cLoopCountNotSeen))
11728040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu        m_repetitionCount = m_reader->loop_count;
1188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return m_repetitionCount;
1198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben MurdochImageFrame* GIFImageDecoder::frameBufferAtIndex(size_t index)
1228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (index >= frameCount())
1248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return 0;
1258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    ImageFrame& frame = m_frameBufferCache[index];
12765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    if (frame.status() != ImageFrame::FrameComplete)
128dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        decode(index + 1, GIFFullQuery);
1298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return &frame;
1308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsenbool GIFImageDecoder::setFailed()
13306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen{
13406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    m_reader.clear();
13506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    return ImageDecoder::setFailed();
13606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen}
13706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen
138635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid GIFImageDecoder::clearFrameBufferCache(size_t clearBeforeFrame)
139635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
140635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // In some cases, like if the decoder was destroyed while animating, we
141635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // can be asked to clear more frames than we currently have.
142635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (m_frameBufferCache.isEmpty())
1438f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        return; // Nothing to do.
1448f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
145635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // The "-1" here is tricky.  It does not mean that |clearBeforeFrame| is the
146635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // last frame we wish to preserve, but rather that we never want to clear
147635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // the very last frame in the cache: it's empty (so clearing it is
148635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // pointless), it's partial (so we don't want to clear it anyway), or the
149635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // cache could be enlarged with a future setData() call and it could be
150635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // needed to construct the next frame (see comments below).  Callers can
151635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // always use ImageSource::clear(true, ...) to completely free the memory in
152635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // this case.
153635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    clearBeforeFrame = std::min(clearBeforeFrame, m_frameBufferCache.size() - 1);
15465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    const Vector<ImageFrame>::iterator end(m_frameBufferCache.begin() + clearBeforeFrame);
1558f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
1568f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    // We need to preserve frames such that:
1578f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    //   * We don't clear |end|
1588f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    //   * We don't clear the frame we're currently decoding
1598f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    //   * We don't clear any frame from which a future initFrameBuffer() call
1608f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    //     will copy bitmap data
1618f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    // All other frames can be cleared.  Because of the constraints on when
1628f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    // ImageSource::clear() can be called (see ImageSource.h), we're guaranteed
1638f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    // not to have non-empty frames after the frame we're currently decoding.
1648f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    // So, scan backwards from |end| as follows:
1658f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    //   * If the frame is empty, we're still past any frames we care about.
1668f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    //   * If the frame is complete, but is DisposeOverwritePrevious, we'll
1678f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    //     skip over it in future initFrameBuffer() calls.  We can clear it
1688f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    //     unless it's |end|, and keep scanning.  For any other disposal method,
1698f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    //     stop scanning, as we've found the frame initFrameBuffer() will need
1708f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    //     next.
1718f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    //   * If the frame is partial, we're decoding it, so don't clear it; if it
1728f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    //     has a disposal method other than DisposeOverwritePrevious, stop
1738f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    //     scanning, as we'll only need this frame when decoding the next one.
17465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    Vector<ImageFrame>::iterator i(end);
17565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    for (; (i != m_frameBufferCache.begin()) && ((i->status() == ImageFrame::FrameEmpty) || (i->disposalMethod() == ImageFrame::DisposeOverwritePrevious)); --i) {
17665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        if ((i->status() == ImageFrame::FrameComplete) && (i != end))
1772fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            i->clearPixelData();
1788f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    }
1798f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
1808f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    // Now |i| holds the last frame we need to preserve; clear prior frames.
18165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    for (Vector<ImageFrame>::iterator j(m_frameBufferCache.begin()); j != i; ++j) {
18265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        ASSERT(j->status() != ImageFrame::FramePartial);
18365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        if (j->status() != ImageFrame::FrameEmpty)
1842fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            j->clearPixelData();
185635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
186635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
187635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
1888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GIFImageDecoder::decodingHalted(unsigned bytesLeft)
1898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
190d0825bca7fe65beaee391d30da42e937db621564Steve Block    m_readOffset = m_data->size() - bytesLeft;
1918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
193692e5dbf12901edacf14812a6fae25462920af42Steve Blockbool GIFImageDecoder::haveDecodedRow(unsigned frameIndex, unsigned char* rowBuffer, unsigned char* rowEnd, unsigned rowNumber, unsigned repeatCount, bool writeTransparentPixels)
1948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
195d0825bca7fe65beaee391d30da42e937db621564Steve Block    const GIFFrameReader* frameReader = m_reader->frame_reader;
1960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    // The pixel data and coordinates supplied to us are relative to the frame's
1970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    // origin within the entire image size, i.e.
198d0825bca7fe65beaee391d30da42e937db621564Steve Block    // (frameReader->x_offset, frameReader->y_offset).  There is no guarantee
199d0825bca7fe65beaee391d30da42e937db621564Steve Block    // that (rowEnd - rowBuffer) == (size().width() - frameReader->x_offset), so
200d0825bca7fe65beaee391d30da42e937db621564Steve Block    // we must ensure we don't run off the end of either the source data or the
201d0825bca7fe65beaee391d30da42e937db621564Steve Block    // row's X-coordinates.
202d0825bca7fe65beaee391d30da42e937db621564Steve Block    int xBegin = upperBoundScaledX(frameReader->x_offset);
203d0825bca7fe65beaee391d30da42e937db621564Steve Block    int yBegin = upperBoundScaledY(frameReader->y_offset + rowNumber);
20468513a70bcd92384395513322f1b801e7bf9c729Steve Block    int xEnd = lowerBoundScaledX(std::min(static_cast<int>(frameReader->x_offset + (rowEnd - rowBuffer)), size().width()) - 1, xBegin + 1) + 1;
20568513a70bcd92384395513322f1b801e7bf9c729Steve Block    int yEnd = lowerBoundScaledY(std::min(static_cast<int>(frameReader->y_offset + rowNumber + repeatCount), size().height()) - 1, yBegin + 1) + 1;
206d0825bca7fe65beaee391d30da42e937db621564Steve Block    if (!rowBuffer || (xBegin < 0) || (yBegin < 0) || (xEnd <= xBegin) || (yEnd <= yBegin))
207d0825bca7fe65beaee391d30da42e937db621564Steve Block        return true;
2088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    // Get the colormap.
210d0825bca7fe65beaee391d30da42e937db621564Steve Block    const unsigned char* colorMap;
2118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned colorMapSize;
212d0825bca7fe65beaee391d30da42e937db621564Steve Block    if (frameReader->is_local_colormap_defined) {
213d0825bca7fe65beaee391d30da42e937db621564Steve Block        colorMap = frameReader->local_colormap;
214d0825bca7fe65beaee391d30da42e937db621564Steve Block        colorMapSize = (unsigned)frameReader->local_colormap_size;
215d0825bca7fe65beaee391d30da42e937db621564Steve Block    } else {
216d0825bca7fe65beaee391d30da42e937db621564Steve Block        colorMap = m_reader->global_colormap;
217d0825bca7fe65beaee391d30da42e937db621564Steve Block        colorMapSize = m_reader->global_colormap_size;
218d0825bca7fe65beaee391d30da42e937db621564Steve Block    }
2198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!colorMap)
220d0825bca7fe65beaee391d30da42e937db621564Steve Block        return true;
2218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    // Initialize the frame if necessary.
22365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    ImageFrame& buffer = m_frameBufferCache[frameIndex];
22465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    if ((buffer.status() == ImageFrame::FrameEmpty) && !initFrameBuffer(frameIndex))
225d0825bca7fe65beaee391d30da42e937db621564Steve Block        return false;
2260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
227d0825bca7fe65beaee391d30da42e937db621564Steve Block    // Write one row's worth of data into the frame.
228d0825bca7fe65beaee391d30da42e937db621564Steve Block    for (int x = xBegin; x < xEnd; ++x) {
229d0825bca7fe65beaee391d30da42e937db621564Steve Block        const unsigned char sourceValue = *(rowBuffer + (m_scaled ? m_scaledColumns[x] : x) - frameReader->x_offset);
230d0825bca7fe65beaee391d30da42e937db621564Steve Block        if ((!frameReader->is_transparent || (sourceValue != frameReader->tpixel)) && (sourceValue < colorMapSize)) {
2310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            const size_t colorIndex = static_cast<size_t>(sourceValue) * 3;
232d0825bca7fe65beaee391d30da42e937db621564Steve Block            buffer.setRGBA(x, yBegin, colorMap[colorIndex], colorMap[colorIndex + 1], colorMap[colorIndex + 2], 255);
2338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else {
2348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            m_currentBufferSawAlpha = true;
2358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // We may or may not need to write transparent pixels to the buffer.
2368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // If we're compositing against a previous image, it's wrong, and if
2378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // we're writing atop a cleared, fully transparent buffer, it's
2388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // unnecessary; but if we're decoding an interlaced gif and
2398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // displaying it "Haeberli"-style, we must write these for passes
2408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // beyond the first, or the initial passes will "show through" the
2418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // later ones.
2428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (writeTransparentPixels)
243d0825bca7fe65beaee391d30da42e937db621564Steve Block                buffer.setRGBA(x, yBegin, 0, 0, 0, 0);
2448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
2458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    // Tell the frame to copy the row data if need be.
2480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (repeatCount > 1)
249d0825bca7fe65beaee391d30da42e937db621564Steve Block        buffer.copyRowNTimes(xBegin, xEnd, yBegin, yEnd);
250d0825bca7fe65beaee391d30da42e937db621564Steve Block
251d0825bca7fe65beaee391d30da42e937db621564Steve Block    return true;
2528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
25465f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdochbool GIFImageDecoder::frameComplete(unsigned frameIndex, unsigned frameDuration, ImageFrame::FrameDisposalMethod disposalMethod)
2558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
256635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Initialize the frame if necessary.  Some GIFs insert do-nothing frames,
257635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // in which case we never reach haveDecodedRow() before getting here.
25865f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    ImageFrame& buffer = m_frameBufferCache[frameIndex];
25965f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    if ((buffer.status() == ImageFrame::FrameEmpty) && !initFrameBuffer(frameIndex))
26021939df44de1705786c545cd1bf519d47250322dBen Murdoch        return false; // initFrameBuffer() has already called setFailed().
261635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
26265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    buffer.setStatus(ImageFrame::FrameComplete);
2638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    buffer.setDuration(frameDuration);
2648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    buffer.setDisposalMethod(disposalMethod);
2658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_currentBufferSawAlpha) {
2678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // The whole frame was non-transparent, so it's possible that the entire
2688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // resulting buffer was non-transparent, and we can setHasAlpha(false).
2692fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        if (buffer.originalFrameRect().contains(IntRect(IntPoint(), scaledSize())))
2708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            buffer.setHasAlpha(false);
271692e5dbf12901edacf14812a6fae25462920af42Steve Block        else if (frameIndex) {
2728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // Tricky case.  This frame does not have alpha only if everywhere
2738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // outside its rect doesn't have alpha.  To know whether this is
2748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // true, we check the start state of the frame -- if it doesn't have
2758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // alpha, we're safe.
2768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            //
2778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // First skip over prior DisposeOverwritePrevious frames (since they
2788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // don't affect the start state of this frame) the same way we do in
2798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // initFrameBuffer().
28065f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            const ImageFrame* prevBuffer = &m_frameBufferCache[--frameIndex];
28165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch            while (frameIndex && (prevBuffer->disposalMethod() == ImageFrame::DisposeOverwritePrevious))
2828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                prevBuffer = &m_frameBufferCache[--frameIndex];
2838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // Now, if we're at a DisposeNotSpecified or DisposeKeep frame, then
2858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // we can say we have no alpha if that frame had no alpha.  But
2868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // since in initFrameBuffer() we already copied that frame's alpha
2878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // state into the current frame's, we need do nothing at all here.
2888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            //
2898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // The only remaining case is a DisposeOverwriteBgcolor frame.  If
2908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // it had no alpha, and its rect is contained in the current frame's
2918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // rect, we know the current frame has no alpha.
2922fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            if ((prevBuffer->disposalMethod() == ImageFrame::DisposeOverwriteBgcolor) && !prevBuffer->hasAlpha() && buffer.originalFrameRect().contains(prevBuffer->originalFrameRect()))
2938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                buffer.setHasAlpha(false);
2948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
2958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
29621939df44de1705786c545cd1bf519d47250322dBen Murdoch
29721939df44de1705786c545cd1bf519d47250322dBen Murdoch    return true;
2988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid GIFImageDecoder::gifComplete()
3018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
30228040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // Cache the repetition count, which is now as authoritative as it's ever
30328040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    // going to be.
30428040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu    repetitionCount();
30528040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu
306d0825bca7fe65beaee391d30da42e937db621564Steve Block    m_reader.clear();
3078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
309692e5dbf12901edacf14812a6fae25462920af42Steve Blockvoid GIFImageDecoder::decode(unsigned haltAtFrame, GIFQuery query)
310692e5dbf12901edacf14812a6fae25462920af42Steve Block{
311dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (failed())
312692e5dbf12901edacf14812a6fae25462920af42Steve Block        return;
313692e5dbf12901edacf14812a6fae25462920af42Steve Block
314dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (!m_reader)
315dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        m_reader.set(new GIFImageReader(this));
316dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
31721939df44de1705786c545cd1bf519d47250322dBen Murdoch    // If we couldn't decode the image but we've received all the data, decoding
31821939df44de1705786c545cd1bf519d47250322dBen Murdoch    // has failed.
31921939df44de1705786c545cd1bf519d47250322dBen Murdoch    if (!m_reader->read((const unsigned char*)m_data->data() + m_readOffset, m_data->size() - m_readOffset, query, haltAtFrame) && isAllDataReceived())
320dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        setFailed();
321692e5dbf12901edacf14812a6fae25462920af42Steve Block}
322692e5dbf12901edacf14812a6fae25462920af42Steve Block
323692e5dbf12901edacf14812a6fae25462920af42Steve Blockbool GIFImageDecoder::initFrameBuffer(unsigned frameIndex)
324692e5dbf12901edacf14812a6fae25462920af42Steve Block{
325692e5dbf12901edacf14812a6fae25462920af42Steve Block    // Initialize the frame rect in our buffer.
326692e5dbf12901edacf14812a6fae25462920af42Steve Block    const GIFFrameReader* frameReader = m_reader->frame_reader;
327692e5dbf12901edacf14812a6fae25462920af42Steve Block    IntRect frameRect(frameReader->x_offset, frameReader->y_offset, frameReader->width, frameReader->height);
328692e5dbf12901edacf14812a6fae25462920af42Steve Block
329692e5dbf12901edacf14812a6fae25462920af42Steve Block    // Make sure the frameRect doesn't extend outside the buffer.
3302fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (frameRect.maxX() > size().width())
331692e5dbf12901edacf14812a6fae25462920af42Steve Block        frameRect.setWidth(size().width() - frameReader->x_offset);
3322fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (frameRect.maxY() > size().height())
333692e5dbf12901edacf14812a6fae25462920af42Steve Block        frameRect.setHeight(size().height() - frameReader->y_offset);
334692e5dbf12901edacf14812a6fae25462920af42Steve Block
33565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    ImageFrame* const buffer = &m_frameBufferCache[frameIndex];
336692e5dbf12901edacf14812a6fae25462920af42Steve Block    int left = upperBoundScaledX(frameRect.x());
3372fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    int right = lowerBoundScaledX(frameRect.maxX(), left);
338692e5dbf12901edacf14812a6fae25462920af42Steve Block    int top = upperBoundScaledY(frameRect.y());
3392fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    int bottom = lowerBoundScaledY(frameRect.maxY(), top);
3402fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    buffer->setOriginalFrameRect(IntRect(left, top, right - left, bottom - top));
341692e5dbf12901edacf14812a6fae25462920af42Steve Block
342692e5dbf12901edacf14812a6fae25462920af42Steve Block    if (!frameIndex) {
343692e5dbf12901edacf14812a6fae25462920af42Steve Block        // This is the first frame, so we're not relying on any previous data.
344dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if (!buffer->setSize(scaledSize().width(), scaledSize().height()))
345dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            return setFailed();
346692e5dbf12901edacf14812a6fae25462920af42Steve Block    } else {
347692e5dbf12901edacf14812a6fae25462920af42Steve Block        // The starting state for this frame depends on the previous frame's
348692e5dbf12901edacf14812a6fae25462920af42Steve Block        // disposal method.
349692e5dbf12901edacf14812a6fae25462920af42Steve Block        //
350692e5dbf12901edacf14812a6fae25462920af42Steve Block        // Frames that use the DisposeOverwritePrevious method are effectively
351692e5dbf12901edacf14812a6fae25462920af42Steve Block        // no-ops in terms of changing the starting state of a frame compared to
352692e5dbf12901edacf14812a6fae25462920af42Steve Block        // the starting state of the previous frame, so skip over them.  (If the
353692e5dbf12901edacf14812a6fae25462920af42Steve Block        // first frame specifies this method, it will get treated like
354692e5dbf12901edacf14812a6fae25462920af42Steve Block        // DisposeOverwriteBgcolor below and reset to a completely empty image.)
35565f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        const ImageFrame* prevBuffer = &m_frameBufferCache[--frameIndex];
35665f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        ImageFrame::FrameDisposalMethod prevMethod = prevBuffer->disposalMethod();
35765f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        while (frameIndex && (prevMethod == ImageFrame::DisposeOverwritePrevious)) {
358692e5dbf12901edacf14812a6fae25462920af42Steve Block            prevBuffer = &m_frameBufferCache[--frameIndex];
359692e5dbf12901edacf14812a6fae25462920af42Steve Block            prevMethod = prevBuffer->disposalMethod();
360692e5dbf12901edacf14812a6fae25462920af42Steve Block        }
36165f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        ASSERT(prevBuffer->status() == ImageFrame::FrameComplete);
362692e5dbf12901edacf14812a6fae25462920af42Steve Block
36365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch        if ((prevMethod == ImageFrame::DisposeNotSpecified) || (prevMethod == ImageFrame::DisposeKeep)) {
364692e5dbf12901edacf14812a6fae25462920af42Steve Block            // Preserve the last frame as the starting state for this frame.
365bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen            if (!buffer->copyBitmapData(*prevBuffer))
366bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen                return setFailed();
367692e5dbf12901edacf14812a6fae25462920af42Steve Block        } else {
368692e5dbf12901edacf14812a6fae25462920af42Steve Block            // We want to clear the previous frame to transparent, without
369692e5dbf12901edacf14812a6fae25462920af42Steve Block            // affecting pixels in the image outside of the frame.
3702fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            const IntRect& prevRect = prevBuffer->originalFrameRect();
371692e5dbf12901edacf14812a6fae25462920af42Steve Block            const IntSize& bufferSize = scaledSize();
372692e5dbf12901edacf14812a6fae25462920af42Steve Block            if (!frameIndex || prevRect.contains(IntRect(IntPoint(), scaledSize()))) {
373692e5dbf12901edacf14812a6fae25462920af42Steve Block                // Clearing the first frame, or a frame the size of the whole
374692e5dbf12901edacf14812a6fae25462920af42Steve Block                // image, results in a completely empty image.
375dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                if (!buffer->setSize(bufferSize.width(), bufferSize.height()))
376dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                    return setFailed();
377692e5dbf12901edacf14812a6fae25462920af42Steve Block            } else {
378692e5dbf12901edacf14812a6fae25462920af42Steve Block              // Copy the whole previous buffer, then clear just its frame.
379bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen              if (!buffer->copyBitmapData(*prevBuffer))
380bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen                  return setFailed();
3812fc2651226baac27029e38c9d6ef883fa32084dbSteve Block              for (int y = prevRect.y(); y < prevRect.maxY(); ++y) {
3822fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                  for (int x = prevRect.x(); x < prevRect.maxX(); ++x)
383692e5dbf12901edacf14812a6fae25462920af42Steve Block                      buffer->setRGBA(x, y, 0, 0, 0, 0);
384692e5dbf12901edacf14812a6fae25462920af42Steve Block              }
385692e5dbf12901edacf14812a6fae25462920af42Steve Block              if ((prevRect.width() > 0) && (prevRect.height() > 0))
386692e5dbf12901edacf14812a6fae25462920af42Steve Block                  buffer->setHasAlpha(true);
387692e5dbf12901edacf14812a6fae25462920af42Steve Block            }
388692e5dbf12901edacf14812a6fae25462920af42Steve Block        }
389692e5dbf12901edacf14812a6fae25462920af42Steve Block    }
390692e5dbf12901edacf14812a6fae25462920af42Steve Block
391692e5dbf12901edacf14812a6fae25462920af42Steve Block    // Update our status to be partially complete.
39265f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch    buffer->setStatus(ImageFrame::FramePartial);
393692e5dbf12901edacf14812a6fae25462920af42Steve Block
394692e5dbf12901edacf14812a6fae25462920af42Steve Block    // Reset the alpha pixel tracker for this frame.
395692e5dbf12901edacf14812a6fae25462920af42Steve Block    m_currentBufferSawAlpha = false;
396692e5dbf12901edacf14812a6fae25462920af42Steve Block    return true;
397692e5dbf12901edacf14812a6fae25462920af42Steve Block}
398692e5dbf12901edacf14812a6fae25462920af42Steve Block
3995f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} // namespace WebCore
400