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