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

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

Issue 15350006: Decode GIF image frames on demand. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 7 years, 7 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
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/PassOwnPtr.h> 32 #include "wtf/NotFound.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 bool GIFImageDecoder::setSize(unsigned width, unsigned height) 66 bool GIFImageDecoder::setSize(unsigned width, unsigned height)
66 { 67 {
67 if (ImageDecoder::isSizeAvailable() && size() == IntSize(width, height)) 68 if (ImageDecoder::isSizeAvailable() && size() == IntSize(width, height))
68 return true; 69 return true;
69 70
70 if (!ImageDecoder::setSize(width, height)) 71 if (!ImageDecoder::setSize(width, height))
71 return false; 72 return false;
72 73
73 prepareScaleDataIfNecessary(); 74 prepareScaleDataIfNecessary();
74 return true; 75 return true;
75 } 76 }
76 77
77 size_t GIFImageDecoder::frameCount() 78 size_t GIFImageDecoder::frameCount()
78 { 79 {
79 decode(std::numeric_limits<unsigned>::max(), GIFFrameCountQuery); 80 parse(GIFFrameCountQuery);
80 return m_frameBufferCache.size(); 81 return m_frameBufferCache.size();
81 } 82 }
82 83
83 int GIFImageDecoder::repetitionCount() const 84 int GIFImageDecoder::repetitionCount() const
84 { 85 {
85 // This value can arrive at any point in the image data stream. Most GIFs 86 // This value can arrive at any point in the image data stream. Most GIFs
86 // in the wild declare it near the beginning of the file, so it usually is 87 // in the wild declare it near the beginning of the file, so it usually is
87 // set by the time we've decoded the size, but (depending on the GIF and the 88 // set by the time we've decoded the size, but (depending on the GIF and the
88 // packets sent back by the webserver) not always. If the reader hasn't 89 // packets sent back by the webserver) not always. If the reader hasn't
89 // seen a loop count yet, it will return cLoopCountNotSeen, in which case we 90 // seen a loop count yet, it will return cLoopCountNotSeen, in which case we
(...skipping 24 matching lines...) Expand all
114 } 115 }
115 116
116 ImageFrame* GIFImageDecoder::frameBufferAtIndex(size_t index) 117 ImageFrame* GIFImageDecoder::frameBufferAtIndex(size_t index)
117 { 118 {
118 if (index >= frameCount()) 119 if (index >= frameCount())
119 return 0; 120 return 0;
120 121
121 ImageFrame& frame = m_frameBufferCache[index]; 122 ImageFrame& frame = m_frameBufferCache[index];
122 if (frame.status() != ImageFrame::FrameComplete) { 123 if (frame.status() != ImageFrame::FrameComplete) {
123 PlatformInstrumentation::willDecodeImage("GIF"); 124 PlatformInstrumentation::willDecodeImage("GIF");
124 decode(index + 1, GIFFullQuery); 125 decode(index);
125 PlatformInstrumentation::didDecodeImage(); 126 PlatformInstrumentation::didDecodeImage();
126 } 127 }
127 return &frame; 128 return &frame;
128 } 129 }
129 130
130 bool GIFImageDecoder::frameIsCompleteAtIndex(size_t index) const 131 bool GIFImageDecoder::frameIsCompleteAtIndex(size_t index) const
131 { 132 {
132 return m_reader && (index < m_reader->imagesCount()) && m_reader->frameConte xt(index)->isComplete(); 133 return m_reader && (index < m_reader->imagesCount()) && m_reader->frameConte xt(index)->isComplete();
133 } 134 }
134 135
135 float GIFImageDecoder::frameDurationAtIndex(size_t index) const 136 float GIFImageDecoder::frameDurationAtIndex(size_t index) const
136 { 137 {
137 return (m_reader && (index < m_reader->imagesCount()) && 138 return (m_reader && (index < m_reader->imagesCount()) &&
138 m_reader->frameContext(index)->isHeaderDefined()) ? 139 m_reader->frameContext(index)->isHeaderDefined()) ?
139 m_reader->frameContext(index)->delayTime : 0; 140 m_reader->frameContext(index)->delayTime : 0;
140 } 141 }
141 142
142 bool GIFImageDecoder::setFailed() 143 bool GIFImageDecoder::setFailed()
143 { 144 {
144 m_reader.clear(); 145 m_reader.clear();
145 return ImageDecoder::setFailed(); 146 return ImageDecoder::setFailed();
146 } 147 }
147 148
148 void GIFImageDecoder::clearFrameBufferCache(size_t clearBeforeFrame) 149 bool GIFImageDecoder::haveDecodedRow(size_t frameIndex, const Vector<unsigned ch ar>& rowBuffer, size_t width, size_t rowNumber, unsigned repeatCount, bool write TransparentPixels)
149 {
150 // In some cases, like if the decoder was destroyed while animating, we
151 // can be asked to clear more frames than we currently have.
152 if (m_frameBufferCache.isEmpty())
153 return; // Nothing to do.
154
155 // The "-1" here is tricky. It does not mean that |clearBeforeFrame| is the
156 // last frame we wish to preserve, but rather that we never want to clear
157 // the very last frame in the cache: it's empty (so clearing it is
158 // pointless), it's partial (so we don't want to clear it anyway), or the
159 // cache could be enlarged with a future setData() call and it could be
160 // needed to construct the next frame (see comments below). Callers can
161 // always use ImageSource::clear(true, ...) to completely free the memory in
162 // this case.
163 clearBeforeFrame = std::min(clearBeforeFrame, m_frameBufferCache.size() - 1) ;
164 const Vector<ImageFrame>::iterator end(m_frameBufferCache.begin() + clearBef oreFrame);
165
166 // We need to preserve frames such that:
167 // * We don't clear |end|
168 // * We don't clear the frame we're currently decoding
169 // * We don't clear any frame from which a future initFrameBuffer() call
170 // will copy bitmap data
171 // All other frames can be cleared. Because of the constraints on when
172 // ImageSource::clear() can be called (see ImageSource.h), we're guaranteed
173 // not to have non-empty frames after the frame we're currently decoding.
174 // So, scan backwards from |end| as follows:
175 // * If the frame is empty, we're still past any frames we care about.
176 // * If the frame is complete, but is DisposeOverwritePrevious, we'll
177 // skip over it in future initFrameBuffer() calls. We can clear it
178 // unless it's |end|, and keep scanning. For any other disposal method,
179 // stop scanning, as we've found the frame initFrameBuffer() will need
180 // next.
181 // * If the frame is partial, we're decoding it, so don't clear it; if it
182 // has a disposal method other than DisposeOverwritePrevious, stop
183 // scanning, as we'll only need this frame when decoding the next one.
184 Vector<ImageFrame>::iterator i(end);
185 for (; (i != m_frameBufferCache.begin()) && ((i->status() == ImageFrame::Fra meEmpty) || (i->disposalMethod() == ImageFrame::DisposeOverwritePrevious)); --i) {
186 if ((i->status() == ImageFrame::FrameComplete) && (i != end))
187 i->clearPixelData();
188 }
189
190 // Now |i| holds the last frame we need to preserve; clear prior frames.
191 for (Vector<ImageFrame>::iterator j(m_frameBufferCache.begin()); j != i; ++j ) {
192 ASSERT(j->status() != ImageFrame::FramePartial);
193 if (j->status() != ImageFrame::FrameEmpty)
194 j->clearPixelData();
195 }
196 }
197
198 bool GIFImageDecoder::haveDecodedRow(unsigned frameIndex, const Vector<unsigned char>& rowBuffer, size_t width, size_t rowNumber, unsigned repeatCount, bool wri teTransparentPixels)
199 { 150 {
200 const GIFFrameContext* frameContext = m_reader->frameContext(frameIndex); 151 const GIFFrameContext* frameContext = m_reader->frameContext(frameIndex);
201 // The pixel data and coordinates supplied to us are relative to the frame's 152 // The pixel data and coordinates supplied to us are relative to the frame's
202 // origin within the entire image size, i.e. 153 // origin within the entire image size, i.e.
203 // (frameContext->xOffset, frameContext->yOffset). There is no guarantee 154 // (frameContext->xOffset, frameContext->yOffset). There is no guarantee
204 // that width == (size().width() - frameContext->xOffset), so 155 // that width == (size().width() - frameContext->xOffset), so
205 // we must ensure we don't run off the end of either the source data or the 156 // we must ensure we don't run off the end of either the source data or the
206 // row's X-coordinates. 157 // row's X-coordinates.
207 int xBegin = upperBoundScaledX(frameContext->xOffset); 158 int xBegin = upperBoundScaledX(frameContext->xOffset);
208 int yBegin = upperBoundScaledY(frameContext->yOffset + rowNumber); 159 int yBegin = upperBoundScaledY(frameContext->yOffset + rowNumber);
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
251 ++currentAddress; 202 ++currentAddress;
252 } 203 }
253 204
254 // Tell the frame to copy the row data if need be. 205 // Tell the frame to copy the row data if need be.
255 if (repeatCount > 1) 206 if (repeatCount > 1)
256 buffer.copyRowNTimes(xBegin, xEnd, yBegin, yEnd); 207 buffer.copyRowNTimes(xBegin, xEnd, yBegin, yEnd);
257 208
258 return true; 209 return true;
259 } 210 }
260 211
261 bool GIFImageDecoder::frameComplete(unsigned frameIndex, unsigned frameDuration, ImageFrame::FrameDisposalMethod disposalMethod) 212 bool GIFImageDecoder::parseCompleted() const
213 {
214 return m_reader && m_reader->parseCompleted();
215 }
216
217 bool GIFImageDecoder::frameComplete(size_t frameIndex)
262 { 218 {
263 // Initialize the frame if necessary. Some GIFs insert do-nothing frames, 219 // Initialize the frame if necessary. Some GIFs insert do-nothing frames,
264 // in which case we never reach haveDecodedRow() before getting here. 220 // in which case we never reach haveDecodedRow() before getting here.
265 ImageFrame& buffer = m_frameBufferCache[frameIndex]; 221 ImageFrame& buffer = m_frameBufferCache[frameIndex];
266 if ((buffer.status() == ImageFrame::FrameEmpty) && !initFrameBuffer(frameInd ex)) 222 if ((buffer.status() == ImageFrame::FrameEmpty) && !initFrameBuffer(frameInd ex))
267 return false; // initFrameBuffer() has already called setFailed(). 223 return false; // initFrameBuffer() has already called setFailed().
268 224
269 buffer.setStatus(ImageFrame::FrameComplete); 225 buffer.setStatus(ImageFrame::FrameComplete);
270 buffer.setDuration(frameDuration);
271 buffer.setDisposalMethod(disposalMethod);
272 226
273 if (!m_currentBufferSawAlpha) { 227 if (!m_currentBufferSawAlpha) {
274 // The whole frame was non-transparent, so it's possible that the entire 228 // The whole frame was non-transparent, so it's possible that the entire
275 // resulting buffer was non-transparent, and we can setHasAlpha(false). 229 // resulting buffer was non-transparent, and we can setHasAlpha(false).
276 if (buffer.originalFrameRect().contains(IntRect(IntPoint(), scaledSize() ))) 230 if (buffer.originalFrameRect().contains(IntRect(IntPoint(), scaledSize() ))) {
277 buffer.setHasAlpha(false); 231 buffer.setHasAlpha(false);
278 else if (frameIndex) { 232 buffer.setRequiredPreviousFrameIndex(notFound);
233 } else if (buffer.requiredPreviousFrameIndex() != notFound) {
279 // Tricky case. This frame does not have alpha only if everywhere 234 // Tricky case. This frame does not have alpha only if everywhere
280 // outside its rect doesn't have alpha. To know whether this is 235 // outside its rect doesn't have alpha. To know whether this is
281 // true, we check the start state of the frame -- if it doesn't have 236 // true, we check the start state of the frame -- if it doesn't have
282 // alpha, we're safe. 237 // alpha, we're safe.
283 // 238 const ImageFrame* prevBuffer = &m_frameBufferCache[buffer.requiredPr eviousFrameIndex()];
284 // First skip over prior DisposeOverwritePrevious frames (since they 239 ASSERT(prevBuffer->disposalMethod() != ImageFrame::DisposeOverwriteP revious);
285 // don't affect the start state of this frame) the same way we do in
286 // initFrameBuffer().
287 const ImageFrame* prevBuffer = &m_frameBufferCache[--frameIndex];
288 while (frameIndex && (prevBuffer->disposalMethod() == ImageFrame::Di sposeOverwritePrevious))
289 prevBuffer = &m_frameBufferCache[--frameIndex];
290 240
291 // Now, if we're at a DisposeNotSpecified or DisposeKeep frame, then 241 // Now, if we're at a DisposeNotSpecified or DisposeKeep frame, then
292 // we can say we have no alpha if that frame had no alpha. But 242 // we can say we have no alpha if that frame had no alpha. But
293 // since in initFrameBuffer() we already copied that frame's alpha 243 // since in initFrameBuffer() we already copied that frame's alpha
294 // state into the current frame's, we need do nothing at all here. 244 // state into the current frame's, we need do nothing at all here.
295 // 245 //
296 // The only remaining case is a DisposeOverwriteBgcolor frame. If 246 // The only remaining case is a DisposeOverwriteBgcolor frame. If
297 // it had no alpha, and its rect is contained in the current frame's 247 // it had no alpha, and its rect is contained in the current frame's
298 // rect, we know the current frame has no alpha. 248 // rect, we know the current frame has no alpha.
299 if ((prevBuffer->disposalMethod() == ImageFrame::DisposeOverwriteBgc olor) && !prevBuffer->hasAlpha() && buffer.originalFrameRect().contains(prevBuff er->originalFrameRect())) 249 if ((prevBuffer->disposalMethod() == ImageFrame::DisposeOverwriteBgc olor) && !prevBuffer->hasAlpha() && buffer.originalFrameRect().contains(prevBuff er->originalFrameRect()))
300 buffer.setHasAlpha(false); 250 buffer.setHasAlpha(false);
301 } 251 }
302 } 252 }
303 253
304 return true; 254 return true;
305 } 255 }
306 256
307 void GIFImageDecoder::gifComplete() 257 void GIFImageDecoder::clearFrameBuffer(size_t frameIndex)
308 { 258 {
309 // Cache the repetition count, which is now as authoritative as it's ever 259 if (m_reader && m_frameBufferCache[frameIndex].status() == ImageFrame::Frame Partial) {
310 // going to be. 260 // Reset the states of the partial frame in the reader so that the frame
Peter Kasting 2013/05/24 03:15:22 Nit: states -> state
Xianzhu 2013/05/28 22:54:21 Done.
311 repetitionCount(); 261 // can be decoded again when requested.
262 m_reader->clearDecodeState(frameIndex);
263 }
264 ImageDecoder::clearFrameBuffer(frameIndex);
312 } 265 }
313 266
314 void GIFImageDecoder::decode(unsigned haltAtFrame, GIFQuery query) 267 void GIFImageDecoder::parse(GIFParseQuery query)
315 { 268 {
316 if (failed()) 269 if (failed())
317 return; 270 return;
318 271
319 if (!m_reader) { 272 if (!m_reader) {
320 m_reader = adoptPtr(new GIFImageReader(this)); 273 m_reader = adoptPtr(new GIFImageReader(this));
321 m_reader->setData(m_data); 274 m_reader->setData(m_data);
322 } 275 }
323 276
324 if (query == GIFSizeQuery) { 277 if (!m_reader->parse(query)) {
325 if (!m_reader->decode(GIFSizeQuery, haltAtFrame))
326 setFailed();
327 return;
328 }
329
330 if (!m_reader->decode(GIFFrameCountQuery, haltAtFrame)) {
331 setFailed(); 278 setFailed();
332 return; 279 return;
333 } 280 }
334 281
335 const size_t oldSize = m_frameBufferCache.size(); 282 const size_t oldSize = m_frameBufferCache.size();
336 m_frameBufferCache.resize(m_reader->imagesCount()); 283 m_frameBufferCache.resize(m_reader->imagesCount());
337 for (size_t i = oldSize; i < m_reader->imagesCount(); ++i)
338 m_frameBufferCache[i].setPremultiplyAlpha(m_premultiplyAlpha);
339 284
340 if (query == GIFFrameCountQuery) 285 for (size_t i = oldSize; i < m_reader->imagesCount(); ++i) {
286 ImageFrame& buffer = m_frameBufferCache[i];
287 const GIFFrameContext* frameContext = m_reader->frameContext(i);
288 buffer.setPremultiplyAlpha(m_premultiplyAlpha);
289 buffer.setRequiredPreviousFrameIndex(findRequiredPreviousFrame(i));
290 buffer.setDuration(frameContext->delayTime);
291 buffer.setDisposalMethod(frameContext->disposalMethod);
292 }
293 }
294
295 void GIFImageDecoder::decode(size_t frameIndex)
296 {
297 parse(GIFFrameCountQuery);
298
299 if (failed())
341 return; 300 return;
342 301
343 if (!m_reader->decode(GIFFullQuery, haltAtFrame)) { 302 Vector<size_t> framesToDecode;
344 setFailed(); 303 size_t frameToDecode = frameIndex;
345 return; 304 do {
305 framesToDecode.append(frameToDecode);
306 frameToDecode = m_frameBufferCache[frameToDecode].requiredPreviousFrameI ndex();
307 } while (frameToDecode != notFound && m_frameBufferCache[frameToDecode].stat us() == ImageFrame::FrameEmpty);
Peter Kasting 2013/05/24 03:15:22 Doesn't this mean if frame 1 is FramePartial, we a
Xianzhu 2013/05/28 22:54:21 Thanks for finding the mistake. Corrected.
308
309 for (size_t i = framesToDecode.size(); i; --i) {
Peter Kasting 2013/05/24 03:15:22 Nit: Use a const_reverse_iterator, it's clearer an
Xianzhu 2013/05/28 22:54:21 Done.
310 size_t frameIndex = framesToDecode[i - 1];
311 if (!m_reader->decode(frameIndex)) {
312 setFailed();
313 return;
314 }
315
316 // We need more data to continue decoding.
317 if (m_frameBufferCache[frameIndex].status() != ImageFrame::FrameComplete )
318 break;
346 } 319 }
347 320
348 // It is also a fatal error if all data is received and we have decoded all 321 // It is also a fatal error if all data is received and we have decoded all
349 // frames available but the file is truncated. 322 // frames available but the file is truncated.
350 if (haltAtFrame >= m_frameBufferCache.size() && isAllDataReceived() && m_rea der && !m_reader->parseCompleted()) 323 if (frameIndex >= m_frameBufferCache.size() - 1 && isAllDataReceived() && m_ reader && !m_reader->parseCompleted())
351 setFailed(); 324 setFailed();
352 } 325 }
353 326
354 bool GIFImageDecoder::initFrameBuffer(unsigned frameIndex) 327 bool GIFImageDecoder::initFrameBuffer(size_t frameIndex)
355 { 328 {
356 // Initialize the frame rect in our buffer. 329 // Initialize the frame rect in our buffer.
357 const GIFFrameContext* frameContext = m_reader->frameContext(frameIndex); 330 const GIFFrameContext* frameContext = m_reader->frameContext(frameIndex);
358 IntRect frameRect(frameContext->xOffset, frameContext->yOffset, frameContext ->width, frameContext->height); 331 IntRect frameRect(frameContext->xOffset, frameContext->yOffset, frameContext ->width, frameContext->height);
359 332
360 // Make sure the frameRect doesn't extend outside the buffer. 333 // Make sure the frameRect doesn't extend outside the buffer.
361 if (frameRect.maxX() > size().width()) 334 if (frameRect.maxX() > size().width())
362 frameRect.setWidth(size().width() - frameContext->xOffset); 335 frameRect.setWidth(size().width() - frameContext->xOffset);
363 if (frameRect.maxY() > size().height()) 336 if (frameRect.maxY() > size().height())
364 frameRect.setHeight(size().height() - frameContext->yOffset); 337 frameRect.setHeight(size().height() - frameContext->yOffset);
365 338
366 ImageFrame* const buffer = &m_frameBufferCache[frameIndex]; 339 ImageFrame* const buffer = &m_frameBufferCache[frameIndex];
367 int left = upperBoundScaledX(frameRect.x()); 340 int left = upperBoundScaledX(frameRect.x());
368 int right = lowerBoundScaledX(frameRect.maxX(), left); 341 int right = lowerBoundScaledX(frameRect.maxX(), left);
369 int top = upperBoundScaledY(frameRect.y()); 342 int top = upperBoundScaledY(frameRect.y());
370 int bottom = lowerBoundScaledY(frameRect.maxY(), top); 343 int bottom = lowerBoundScaledY(frameRect.maxY(), top);
371 buffer->setOriginalFrameRect(IntRect(left, top, right - left, bottom - top)) ; 344 buffer->setOriginalFrameRect(IntRect(left, top, right - left, bottom - top)) ;
372 345
373 if (!frameIndex) { 346 size_t requiredPreviousFrameIndex = m_frameBufferCache[frameIndex].requiredP reviousFrameIndex();
Peter Kasting 2013/05/24 03:15:22 Nit: Use |buffer|
Xianzhu 2013/05/28 22:54:21 Done.
374 // This is the first frame, so we're not relying on any previous data. 347 if (requiredPreviousFrameIndex == notFound) {
348 // This frame doesn't rely on any previous data.
375 if (!buffer->setSize(scaledSize().width(), scaledSize().height())) 349 if (!buffer->setSize(scaledSize().width(), scaledSize().height()))
376 return setFailed(); 350 return setFailed();
377 } else { 351 } else {
378 // The starting state for this frame depends on the previous frame's 352 const ImageFrame* prevBuffer = &m_frameBufferCache[requiredPreviousFrame Index];
379 // disposal method.
380 //
381 // Frames that use the DisposeOverwritePrevious method are effectively
382 // no-ops in terms of changing the starting state of a frame compared to
383 // the starting state of the previous frame, so skip over them. (If the
384 // first frame specifies this method, it will get treated like
385 // DisposeOverwriteBgcolor below and reset to a completely empty image.)
386 const ImageFrame* prevBuffer = &m_frameBufferCache[--frameIndex];
387 ImageFrame::FrameDisposalMethod prevMethod = prevBuffer->disposalMethod( );
388 while (frameIndex && (prevMethod == ImageFrame::DisposeOverwritePrevious )) {
389 prevBuffer = &m_frameBufferCache[--frameIndex];
390 prevMethod = prevBuffer->disposalMethod();
391 }
392 ASSERT(prevBuffer->status() == ImageFrame::FrameComplete); 353 ASSERT(prevBuffer->status() == ImageFrame::FrameComplete);
393 354
394 if ((prevMethod == ImageFrame::DisposeNotSpecified) || (prevMethod == Im ageFrame::DisposeKeep)) { 355 // Preserve the last frame as the starting state for this frame.
395 // Preserve the last frame as the starting state for this frame. 356 if (!buffer->copyBitmapData(*prevBuffer))
Peter Kasting 2013/05/24 03:15:22 Your code here is simpler than before, but much le
Xianzhu 2013/05/28 22:54:21 In the case findRequiredPreviousFrame() should hav
396 if (!buffer->copyBitmapData(*prevBuffer)) 357 return setFailed();
397 return setFailed(); 358
398 } else { 359 if (prevBuffer->disposalMethod() == ImageFrame::DisposeOverwriteBgcolor) {
399 // We want to clear the previous frame to transparent, without 360 // We want to clear the previous frame to transparent, without
400 // affecting pixels in the image outside of the frame. 361 // affecting pixels in the image outside of the frame.
401 const IntRect& prevRect = prevBuffer->originalFrameRect(); 362 const IntRect& prevRect = prevBuffer->originalFrameRect();
402 const IntSize& bufferSize = scaledSize(); 363 for (int y = prevRect.y(); y < prevRect.maxY(); ++y) {
403 if (!frameIndex || prevRect.contains(IntRect(IntPoint(), scaledSize( )))) { 364 for (int x = prevRect.x(); x < prevRect.maxX(); ++x)
404 // Clearing the first frame, or a frame the size of the whole 365 buffer->setRGBA(x, y, 0, 0, 0, 0);
405 // image, results in a completely empty image.
406 if (!buffer->setSize(bufferSize.width(), bufferSize.height()))
407 return setFailed();
408 } else {
409 // Copy the whole previous buffer, then clear just its frame.
410 if (!buffer->copyBitmapData(*prevBuffer))
411 return setFailed();
412 for (int y = prevRect.y(); y < prevRect.maxY(); ++y) {
413 for (int x = prevRect.x(); x < prevRect.maxX(); ++x)
414 buffer->setRGBA(x, y, 0, 0, 0, 0);
415 }
416 if ((prevRect.width() > 0) && (prevRect.height() > 0))
417 buffer->setHasAlpha(true);
418 } 366 }
367 if ((prevRect.width() > 0) && (prevRect.height() > 0))
368 buffer->setHasAlpha(true);
419 } 369 }
420 } 370 }
421 371
422 // Update our status to be partially complete. 372 // Update our status to be partially complete.
423 buffer->setStatus(ImageFrame::FramePartial); 373 buffer->setStatus(ImageFrame::FramePartial);
424 374
425 // Reset the alpha pixel tracker for this frame. 375 // Reset the alpha pixel tracker for this frame.
426 m_currentBufferSawAlpha = false; 376 m_currentBufferSawAlpha = false;
427 return true; 377 return true;
428 } 378 }
429 379
430 } // namespace WebCore 380 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698