Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(831)

Side by Side Diff: Source/core/platform/image-decoders/gif/GIFImageDecoder.cpp

Issue 15969015: Reland again "Decode GIF image frames on demand". (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: For landing Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. 2 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 1. Redistributions of source code must retain the above copyright 7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright 9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
(...skipping 11 matching lines...) Expand all
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */ 24 */
25 25
26 #include "config.h" 26 #include "config.h"
27 #include "core/platform/image-decoders/gif/GIFImageDecoder.h" 27 #include "core/platform/image-decoders/gif/GIFImageDecoder.h"
28 28
29 #include <limits> 29 #include <limits>
30 #include "core/platform/PlatformInstrumentation.h" 30 #include "core/platform/PlatformInstrumentation.h"
31 #include "core/platform/image-decoders/gif/GIFImageReader.h" 31 #include "core/platform/image-decoders/gif/GIFImageReader.h"
32 #include "wtf/NotFound.h"
32 #include "wtf/PassOwnPtr.h" 33 #include "wtf/PassOwnPtr.h"
33 34
34 namespace WebCore { 35 namespace WebCore {
35 36
36 GIFImageDecoder::GIFImageDecoder(ImageSource::AlphaOption alphaOption, 37 GIFImageDecoder::GIFImageDecoder(ImageSource::AlphaOption alphaOption,
37 ImageSource::GammaAndColorProfileOption gammaAn dColorProfileOption) 38 ImageSource::GammaAndColorProfileOption gammaAn dColorProfileOption)
38 : ImageDecoder(alphaOption, gammaAndColorProfileOption) 39 : ImageDecoder(alphaOption, gammaAndColorProfileOption)
39 , m_repetitionCount(cAnimationLoopOnce) 40 , m_repetitionCount(cAnimationLoopOnce)
40 { 41 {
41 } 42 }
42 43
43 GIFImageDecoder::~GIFImageDecoder() 44 GIFImageDecoder::~GIFImageDecoder()
44 { 45 {
45 } 46 }
46 47
47 void GIFImageDecoder::setData(SharedBuffer* data, bool allDataReceived) 48 void GIFImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
48 { 49 {
49 if (failed()) 50 if (failed())
50 return; 51 return;
51 52
52 ImageDecoder::setData(data, allDataReceived); 53 ImageDecoder::setData(data, allDataReceived);
53 if (m_reader) 54 if (m_reader)
54 m_reader->setData(data); 55 m_reader->setData(data);
55 } 56 }
56 57
57 bool GIFImageDecoder::isSizeAvailable() 58 bool GIFImageDecoder::isSizeAvailable()
58 { 59 {
59 if (!ImageDecoder::isSizeAvailable()) 60 if (!ImageDecoder::isSizeAvailable())
60 decode(0, GIFSizeQuery); 61 parse(GIFSizeQuery);
61 62
62 return ImageDecoder::isSizeAvailable(); 63 return ImageDecoder::isSizeAvailable();
63 } 64 }
64 65
65 size_t GIFImageDecoder::frameCount() 66 size_t GIFImageDecoder::frameCount()
66 { 67 {
67 decode(std::numeric_limits<unsigned>::max(), GIFFrameCountQuery); 68 parse(GIFFrameCountQuery);
68 return m_frameBufferCache.size(); 69 return m_frameBufferCache.size();
69 } 70 }
70 71
71 int GIFImageDecoder::repetitionCount() const 72 int GIFImageDecoder::repetitionCount() const
72 { 73 {
73 // This value can arrive at any point in the image data stream. Most GIFs 74 // This value can arrive at any point in the image data stream. Most GIFs
74 // in the wild declare it near the beginning of the file, so it usually is 75 // in the wild declare it near the beginning of the file, so it usually is
75 // set by the time we've decoded the size, but (depending on the GIF and the 76 // set by the time we've decoded the size, but (depending on the GIF and the
76 // packets sent back by the webserver) not always. If the reader hasn't 77 // packets sent back by the webserver) not always. If the reader hasn't
77 // seen a loop count yet, it will return cLoopCountNotSeen, in which case we 78 // seen a loop count yet, it will return cLoopCountNotSeen, in which case we
(...skipping 24 matching lines...) Expand all
102 } 103 }
103 104
104 ImageFrame* GIFImageDecoder::frameBufferAtIndex(size_t index) 105 ImageFrame* GIFImageDecoder::frameBufferAtIndex(size_t index)
105 { 106 {
106 if (index >= frameCount()) 107 if (index >= frameCount())
107 return 0; 108 return 0;
108 109
109 ImageFrame& frame = m_frameBufferCache[index]; 110 ImageFrame& frame = m_frameBufferCache[index];
110 if (frame.status() != ImageFrame::FrameComplete) { 111 if (frame.status() != ImageFrame::FrameComplete) {
111 PlatformInstrumentation::willDecodeImage("GIF"); 112 PlatformInstrumentation::willDecodeImage("GIF");
112 decode(index + 1, GIFFullQuery); 113 decode(index);
113 PlatformInstrumentation::didDecodeImage(); 114 PlatformInstrumentation::didDecodeImage();
114 } 115 }
115 return &frame; 116 return &frame;
116 } 117 }
117 118
118 bool GIFImageDecoder::frameIsCompleteAtIndex(size_t index) const 119 bool GIFImageDecoder::frameIsCompleteAtIndex(size_t index) const
119 { 120 {
120 return m_reader && (index < m_reader->imagesCount()) && m_reader->frameConte xt(index)->isComplete(); 121 return m_reader && (index < m_reader->imagesCount()) && m_reader->frameConte xt(index)->isComplete();
121 } 122 }
122 123
123 float GIFImageDecoder::frameDurationAtIndex(size_t index) const 124 float GIFImageDecoder::frameDurationAtIndex(size_t index) const
124 { 125 {
125 return (m_reader && (index < m_reader->imagesCount()) && 126 return (m_reader && (index < m_reader->imagesCount()) &&
126 m_reader->frameContext(index)->isHeaderDefined()) ? 127 m_reader->frameContext(index)->isHeaderDefined()) ?
127 m_reader->frameContext(index)->delayTime : 0; 128 m_reader->frameContext(index)->delayTime : 0;
128 } 129 }
129 130
130 bool GIFImageDecoder::setFailed() 131 bool GIFImageDecoder::setFailed()
131 { 132 {
132 m_reader.clear(); 133 m_reader.clear();
133 return ImageDecoder::setFailed(); 134 return ImageDecoder::setFailed();
134 } 135 }
135 136
136 void GIFImageDecoder::clearFrameBufferCache(size_t clearBeforeFrame) 137 bool GIFImageDecoder::haveDecodedRow(size_t frameIndex, const Vector<unsigned ch ar>& rowBuffer, size_t width, size_t rowNumber, unsigned repeatCount, bool write TransparentPixels)
137 {
138 // In some cases, like if the decoder was destroyed while animating, we
139 // can be asked to clear more frames than we currently have.
140 if (m_frameBufferCache.isEmpty())
141 return; // Nothing to do.
142
143 // The "-1" here is tricky. It does not mean that |clearBeforeFrame| is the
144 // last frame we wish to preserve, but rather that we never want to clear
145 // the very last frame in the cache: it's empty (so clearing it is
146 // pointless), it's partial (so we don't want to clear it anyway), or the
147 // cache could be enlarged with a future setData() call and it could be
148 // needed to construct the next frame (see comments below). Callers can
149 // always use ImageSource::clear(true, ...) to completely free the memory in
150 // this case.
151 clearBeforeFrame = std::min(clearBeforeFrame, m_frameBufferCache.size() - 1) ;
152 const Vector<ImageFrame>::iterator end(m_frameBufferCache.begin() + clearBef oreFrame);
153
154 // We need to preserve frames such that:
155 // * We don't clear |end|
156 // * We don't clear the frame we're currently decoding
157 // * We don't clear any frame from which a future initFrameBuffer() call
158 // will copy bitmap data
159 // All other frames can be cleared. Because of the constraints on when
160 // ImageSource::clear() can be called (see ImageSource.h), we're guaranteed
161 // not to have non-empty frames after the frame we're currently decoding.
162 // So, scan backwards from |end| as follows:
163 // * If the frame is empty, we're still past any frames we care about.
164 // * If the frame is complete, but is DisposeOverwritePrevious, we'll
165 // skip over it in future initFrameBuffer() calls. We can clear it
166 // unless it's |end|, and keep scanning. For any other disposal method,
167 // stop scanning, as we've found the frame initFrameBuffer() will need
168 // next.
169 // * If the frame is partial, we're decoding it, so don't clear it; if it
170 // has a disposal method other than DisposeOverwritePrevious, stop
171 // scanning, as we'll only need this frame when decoding the next one.
172 Vector<ImageFrame>::iterator i(end);
173 for (; (i != m_frameBufferCache.begin()) && ((i->status() == ImageFrame::Fra meEmpty) || (i->disposalMethod() == ImageFrame::DisposeOverwritePrevious)); --i) {
174 if ((i->status() == ImageFrame::FrameComplete) && (i != end))
175 i->clearPixelData();
176 }
177
178 // Now |i| holds the last frame we need to preserve; clear prior frames.
179 for (Vector<ImageFrame>::iterator j(m_frameBufferCache.begin()); j != i; ++j ) {
180 ASSERT(j->status() != ImageFrame::FramePartial);
181 if (j->status() != ImageFrame::FrameEmpty)
182 j->clearPixelData();
183 }
184 }
185
186 bool GIFImageDecoder::haveDecodedRow(unsigned frameIndex, const Vector<unsigned char>& rowBuffer, size_t width, size_t rowNumber, unsigned repeatCount, bool wri teTransparentPixels)
187 { 138 {
188 const GIFFrameContext* frameContext = m_reader->frameContext(frameIndex); 139 const GIFFrameContext* frameContext = m_reader->frameContext(frameIndex);
189 // The pixel data and coordinates supplied to us are relative to the frame's 140 // The pixel data and coordinates supplied to us are relative to the frame's
190 // origin within the entire image size, i.e. 141 // origin within the entire image size, i.e.
191 // (frameContext->xOffset, frameContext->yOffset). There is no guarantee 142 // (frameContext->xOffset, frameContext->yOffset). There is no guarantee
192 // that width == (size().width() - frameContext->xOffset), so 143 // that width == (size().width() - frameContext->xOffset), so
193 // we must ensure we don't run off the end of either the source data or the 144 // we must ensure we don't run off the end of either the source data or the
194 // row's X-coordinates. 145 // row's X-coordinates.
195 int xBegin = frameContext->xOffset; 146 int xBegin = frameContext->xOffset;
196 int yBegin = frameContext->yOffset + rowNumber; 147 int yBegin = frameContext->yOffset + rowNumber;
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
239 ++currentAddress; 190 ++currentAddress;
240 } 191 }
241 192
242 // Tell the frame to copy the row data if need be. 193 // Tell the frame to copy the row data if need be.
243 if (repeatCount > 1) 194 if (repeatCount > 1)
244 buffer.copyRowNTimes(xBegin, xEnd, yBegin, yEnd); 195 buffer.copyRowNTimes(xBegin, xEnd, yBegin, yEnd);
245 196
246 return true; 197 return true;
247 } 198 }
248 199
249 bool GIFImageDecoder::frameComplete(unsigned frameIndex, unsigned frameDuration, ImageFrame::FrameDisposalMethod disposalMethod) 200 bool GIFImageDecoder::parseCompleted() const
201 {
202 return m_reader && m_reader->parseCompleted();
203 }
204
205 bool GIFImageDecoder::frameComplete(size_t frameIndex)
250 { 206 {
251 // Initialize the frame if necessary. Some GIFs insert do-nothing frames, 207 // Initialize the frame if necessary. Some GIFs insert do-nothing frames,
252 // in which case we never reach haveDecodedRow() before getting here. 208 // in which case we never reach haveDecodedRow() before getting here.
253 ImageFrame& buffer = m_frameBufferCache[frameIndex]; 209 ImageFrame& buffer = m_frameBufferCache[frameIndex];
254 if ((buffer.status() == ImageFrame::FrameEmpty) && !initFrameBuffer(frameInd ex)) 210 if ((buffer.status() == ImageFrame::FrameEmpty) && !initFrameBuffer(frameInd ex))
255 return false; // initFrameBuffer() has already called setFailed(). 211 return false; // initFrameBuffer() has already called setFailed().
256 212
257 buffer.setStatus(ImageFrame::FrameComplete); 213 buffer.setStatus(ImageFrame::FrameComplete);
258 buffer.setDuration(frameDuration);
259 buffer.setDisposalMethod(disposalMethod);
260 214
261 if (!m_currentBufferSawAlpha) { 215 if (!m_currentBufferSawAlpha) {
262 // The whole frame was non-transparent, so it's possible that the entire 216 // The whole frame was non-transparent, so it's possible that the entire
263 // resulting buffer was non-transparent, and we can setHasAlpha(false). 217 // resulting buffer was non-transparent, and we can setHasAlpha(false).
264 if (buffer.originalFrameRect().contains(IntRect(IntPoint(), size()))) 218 if (buffer.originalFrameRect().contains(IntRect(IntPoint(), size()))) {
265 buffer.setHasAlpha(false); 219 buffer.setHasAlpha(false);
266 else if (frameIndex) { 220 buffer.setRequiredPreviousFrameIndex(notFound);
221 } else if (buffer.requiredPreviousFrameIndex() != notFound) {
267 // Tricky case. This frame does not have alpha only if everywhere 222 // Tricky case. This frame does not have alpha only if everywhere
268 // outside its rect doesn't have alpha. To know whether this is 223 // outside its rect doesn't have alpha. To know whether this is
269 // true, we check the start state of the frame -- if it doesn't have 224 // true, we check the start state of the frame -- if it doesn't have
270 // alpha, we're safe. 225 // alpha, we're safe.
271 // 226 const ImageFrame* prevBuffer = &m_frameBufferCache[buffer.requiredPr eviousFrameIndex()];
272 // First skip over prior DisposeOverwritePrevious frames (since they 227 ASSERT(prevBuffer->disposalMethod() != ImageFrame::DisposeOverwriteP revious);
273 // don't affect the start state of this frame) the same way we do in
274 // initFrameBuffer().
275 const ImageFrame* prevBuffer = &m_frameBufferCache[--frameIndex];
276 while (frameIndex && (prevBuffer->disposalMethod() == ImageFrame::Di sposeOverwritePrevious))
277 prevBuffer = &m_frameBufferCache[--frameIndex];
278 228
279 // Now, if we're at a DisposeNotSpecified or DisposeKeep frame, then 229 // Now, if we're at a DisposeNotSpecified or DisposeKeep frame, then
280 // we can say we have no alpha if that frame had no alpha. But 230 // we can say we have no alpha if that frame had no alpha. But
281 // since in initFrameBuffer() we already copied that frame's alpha 231 // since in initFrameBuffer() we already copied that frame's alpha
282 // state into the current frame's, we need do nothing at all here. 232 // state into the current frame's, we need do nothing at all here.
283 // 233 //
284 // The only remaining case is a DisposeOverwriteBgcolor frame. If 234 // The only remaining case is a DisposeOverwriteBgcolor frame. If
285 // it had no alpha, and its rect is contained in the current frame's 235 // it had no alpha, and its rect is contained in the current frame's
286 // rect, we know the current frame has no alpha. 236 // rect, we know the current frame has no alpha.
287 if ((prevBuffer->disposalMethod() == ImageFrame::DisposeOverwriteBgc olor) && !prevBuffer->hasAlpha() && buffer.originalFrameRect().contains(prevBuff er->originalFrameRect())) 237 if ((prevBuffer->disposalMethod() == ImageFrame::DisposeOverwriteBgc olor) && !prevBuffer->hasAlpha() && buffer.originalFrameRect().contains(prevBuff er->originalFrameRect()))
288 buffer.setHasAlpha(false); 238 buffer.setHasAlpha(false);
289 } 239 }
290 } 240 }
291 241
292 return true; 242 return true;
293 } 243 }
294 244
295 void GIFImageDecoder::gifComplete() 245 void GIFImageDecoder::clearFrameBuffer(size_t frameIndex)
296 { 246 {
297 // Cache the repetition count, which is now as authoritative as it's ever 247 if (m_reader && m_frameBufferCache[frameIndex].status() == ImageFrame::Frame Partial) {
298 // going to be. 248 // Reset the state of the partial frame in the reader so that the frame
299 repetitionCount(); 249 // can be decoded again when requested.
250 m_reader->clearDecodeState(frameIndex);
251 }
252 ImageDecoder::clearFrameBuffer(frameIndex);
300 } 253 }
301 254
302 void GIFImageDecoder::decode(unsigned haltAtFrame, GIFQuery query) 255 void GIFImageDecoder::parse(GIFParseQuery query)
303 { 256 {
304 if (failed()) 257 if (failed())
305 return; 258 return;
306 259
307 if (!m_reader) { 260 if (!m_reader) {
308 m_reader = adoptPtr(new GIFImageReader(this)); 261 m_reader = adoptPtr(new GIFImageReader(this));
309 m_reader->setData(m_data); 262 m_reader->setData(m_data);
310 } 263 }
311 264
312 if (query == GIFSizeQuery) { 265 if (!m_reader->parse(query)) {
313 if (!m_reader->decode(GIFSizeQuery, haltAtFrame))
314 setFailed();
315 return;
316 }
317
318 if (!m_reader->decode(GIFFrameCountQuery, haltAtFrame)) {
319 setFailed(); 266 setFailed();
320 return; 267 return;
321 } 268 }
322 269
323 const size_t oldSize = m_frameBufferCache.size(); 270 const size_t oldSize = m_frameBufferCache.size();
324 m_frameBufferCache.resize(m_reader->imagesCount()); 271 m_frameBufferCache.resize(m_reader->imagesCount());
325 for (size_t i = oldSize; i < m_reader->imagesCount(); ++i)
326 m_frameBufferCache[i].setPremultiplyAlpha(m_premultiplyAlpha);
327 272
328 if (query == GIFFrameCountQuery) 273 for (size_t i = oldSize; i < m_reader->imagesCount(); ++i) {
274 ImageFrame& buffer = m_frameBufferCache[i];
275 const GIFFrameContext* frameContext = m_reader->frameContext(i);
276 buffer.setPremultiplyAlpha(m_premultiplyAlpha);
277 buffer.setRequiredPreviousFrameIndex(findRequiredPreviousFrame(i));
278 buffer.setDuration(frameContext->delayTime);
279 buffer.setDisposalMethod(frameContext->disposalMethod);
280
281 // Initialize the frame rect in our buffer.
282 IntRect frameRect(frameContext->xOffset, frameContext->yOffset, frameCon text->width, frameContext->height);
283
284 // Make sure the frameRect doesn't extend outside the buffer.
285 if (frameRect.maxX() > size().width())
286 frameRect.setWidth(size().width() - frameContext->xOffset);
287 if (frameRect.maxY() > size().height())
288 frameRect.setHeight(size().height() - frameContext->yOffset);
289
290 buffer.setOriginalFrameRect(frameRect);
291 }
292 }
293
294 void GIFImageDecoder::decode(size_t frameIndex)
295 {
296 parse(GIFFrameCountQuery);
297
298 if (failed())
329 return; 299 return;
330 300
331 if (!m_reader->decode(GIFFullQuery, haltAtFrame)) { 301 Vector<size_t> framesToDecode;
332 setFailed(); 302 size_t frameToDecode = frameIndex;
333 return; 303 do {
304 framesToDecode.append(frameToDecode);
305 frameToDecode = m_frameBufferCache[frameToDecode].requiredPreviousFrameI ndex();
306 } while (frameToDecode != notFound && m_frameBufferCache[frameToDecode].stat us() != ImageFrame::FrameComplete);
307
308 // The |rend| variable is needed by some compilers that can't correctly
309 // select from const and non-const versions of overloaded functions.
310 // Can remove the variable if Android compiler can compile
311 // 'iter != framesToDecode.rend()'.
312 Vector<size_t>::const_reverse_iterator rend = framesToDecode.rend();
313 for (Vector<size_t>::const_reverse_iterator iter = framesToDecode.rbegin(); iter != rend; ++iter) {
314 size_t frameIndex = *iter;
315 if (!m_reader->decode(frameIndex)) {
316 setFailed();
317 return;
318 }
319
320 // We need more data to continue decoding.
321 if (m_frameBufferCache[frameIndex].status() != ImageFrame::FrameComplete )
322 break;
334 } 323 }
335 324
336 // It is also a fatal error if all data is received and we have decoded all 325 // It is also a fatal error if all data is received and we have decoded all
337 // frames available but the file is truncated. 326 // frames available but the file is truncated.
338 if (haltAtFrame >= m_frameBufferCache.size() && isAllDataReceived() && m_rea der && !m_reader->parseCompleted()) 327 if (frameIndex >= m_frameBufferCache.size() - 1 && isAllDataReceived() && m_ reader && !m_reader->parseCompleted())
339 setFailed(); 328 setFailed();
340 } 329 }
341 330
342 bool GIFImageDecoder::initFrameBuffer(unsigned frameIndex) 331 bool GIFImageDecoder::initFrameBuffer(size_t frameIndex)
343 { 332 {
344 // Initialize the frame rect in our buffer. 333 // Initialize the frame rect in our buffer.
345 const GIFFrameContext* frameContext = m_reader->frameContext(frameIndex); 334 const GIFFrameContext* frameContext = m_reader->frameContext(frameIndex);
346 IntRect frameRect(frameContext->xOffset, frameContext->yOffset, frameContext ->width, frameContext->height);
347
348 // Make sure the frameRect doesn't extend outside the buffer.
349 if (frameRect.maxX() > size().width())
350 frameRect.setWidth(size().width() - frameContext->xOffset);
351 if (frameRect.maxY() > size().height())
352 frameRect.setHeight(size().height() - frameContext->yOffset);
353
354 ImageFrame* const buffer = &m_frameBufferCache[frameIndex]; 335 ImageFrame* const buffer = &m_frameBufferCache[frameIndex];
355 buffer->setOriginalFrameRect(frameRect);
356 336
357 if (!frameIndex) { 337 size_t requiredPreviousFrameIndex = buffer->requiredPreviousFrameIndex();
358 // This is the first frame, so we're not relying on any previous data. 338 if (requiredPreviousFrameIndex == notFound) {
339 // This frame doesn't rely on any previous data.
359 if (!buffer->setSize(size().width(), size().height())) 340 if (!buffer->setSize(size().width(), size().height()))
360 return setFailed(); 341 return setFailed();
361 } else { 342 } else {
362 // The starting state for this frame depends on the previous frame's 343 const ImageFrame* prevBuffer = &m_frameBufferCache[requiredPreviousFrame Index];
363 // disposal method.
364 //
365 // Frames that use the DisposeOverwritePrevious method are effectively
366 // no-ops in terms of changing the starting state of a frame compared to
367 // the starting state of the previous frame, so skip over them. (If the
368 // first frame specifies this method, it will get treated like
369 // DisposeOverwriteBgcolor below and reset to a completely empty image.)
370 const ImageFrame* prevBuffer = &m_frameBufferCache[--frameIndex];
371 ImageFrame::FrameDisposalMethod prevMethod = prevBuffer->disposalMethod( );
372 while (frameIndex && (prevMethod == ImageFrame::DisposeOverwritePrevious )) {
373 prevBuffer = &m_frameBufferCache[--frameIndex];
374 prevMethod = prevBuffer->disposalMethod();
375 }
376 ASSERT(prevBuffer->status() == ImageFrame::FrameComplete); 344 ASSERT(prevBuffer->status() == ImageFrame::FrameComplete);
377 345
378 if ((prevMethod == ImageFrame::DisposeNotSpecified) || (prevMethod == Im ageFrame::DisposeKeep)) { 346 // Preserve the last frame as the starting state for this frame.
379 // Preserve the last frame as the starting state for this frame. 347 if (!buffer->copyBitmapData(*prevBuffer))
380 if (!buffer->copyBitmapData(*prevBuffer)) 348 return setFailed();
381 return setFailed(); 349
382 } else { 350 if (prevBuffer->disposalMethod() == ImageFrame::DisposeOverwriteBgcolor) {
383 // We want to clear the previous frame to transparent, without 351 // We want to clear the previous frame to transparent, without
384 // affecting pixels in the image outside of the frame. 352 // affecting pixels in the image outside of the frame.
385 const IntRect& prevRect = prevBuffer->originalFrameRect(); 353 const IntRect& prevRect = prevBuffer->originalFrameRect();
386 const IntSize& bufferSize = size(); 354 ASSERT(!prevRect.contains(IntRect(IntPoint(), size())));
387 if (!frameIndex || prevRect.contains(IntRect(IntPoint(), size()))) { 355 for (int y = prevRect.y(); y < prevRect.maxY(); ++y) {
388 // Clearing the first frame, or a frame the size of the whole 356 for (int x = prevRect.x(); x < prevRect.maxX(); ++x)
389 // image, results in a completely empty image. 357 buffer->setRGBA(x, y, 0, 0, 0, 0);
390 if (!buffer->setSize(bufferSize.width(), bufferSize.height()))
391 return setFailed();
392 } else {
393 // Copy the whole previous buffer, then clear just its frame.
394 if (!buffer->copyBitmapData(*prevBuffer))
395 return setFailed();
396 for (int y = prevRect.y(); y < prevRect.maxY(); ++y) {
397 for (int x = prevRect.x(); x < prevRect.maxX(); ++x)
398 buffer->setRGBA(x, y, 0, 0, 0, 0);
399 }
400 if ((prevRect.width() > 0) && (prevRect.height() > 0))
401 buffer->setHasAlpha(true);
402 } 358 }
359 if ((prevRect.width() > 0) && (prevRect.height() > 0))
360 buffer->setHasAlpha(true);
403 } 361 }
404 } 362 }
405 363
406 // Update our status to be partially complete. 364 // Update our status to be partially complete.
407 buffer->setStatus(ImageFrame::FramePartial); 365 buffer->setStatus(ImageFrame::FramePartial);
408 366
409 // Reset the alpha pixel tracker for this frame. 367 // Reset the alpha pixel tracker for this frame.
410 m_currentBufferSawAlpha = false; 368 m_currentBufferSawAlpha = false;
411 return true; 369 return true;
412 } 370 }
413 371
414 } // namespace WebCore 372 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698