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

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

Issue 1460523002: GIF decoding to Index8, unit tests and misusing unit test as benchmark (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Skia:onGetColorType related implementation. Fix part of Leon's review comments. Created 5 years 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 15 matching lines...) Expand all
26 #include "config.h" 26 #include "config.h"
27 #include "platform/image-decoders/gif/GIFImageDecoder.h" 27 #include "platform/image-decoders/gif/GIFImageDecoder.h"
28 28
29 #include <limits> 29 #include <limits>
30 #include "platform/image-decoders/gif/GIFImageReader.h" 30 #include "platform/image-decoders/gif/GIFImageReader.h"
31 #include "wtf/NotFound.h" 31 #include "wtf/NotFound.h"
32 #include "wtf/PassOwnPtr.h" 32 #include "wtf/PassOwnPtr.h"
33 33
34 namespace blink { 34 namespace blink {
35 35
36 GIFImageDecoder::GIFImageDecoder(AlphaOption alphaOption, GammaAndColorProfileOp tion colorOptions, size_t maxDecodedBytes) 36 GIFImageDecoder::GIFImageDecoder(AlphaOption alphaOption, GammaAndColorProfileOp tion colorOptions, size_t maxDecodedBytes, ImageFrame::ColorType colorType)
37 : ImageDecoder(alphaOption, colorOptions, maxDecodedBytes) 37 : ImageDecoder(alphaOption, colorOptions, maxDecodedBytes)
38 , phaveDecodedRow(&GIFImageDecoder::haveDecodedRowIndex8)
38 , m_repetitionCount(cAnimationLoopOnce) 39 , m_repetitionCount(cAnimationLoopOnce)
40 , m_colorMode(colorType)
41 , m_forceN32Decoding(false)
39 { 42 {
40 } 43 }
41 44
42 GIFImageDecoder::~GIFImageDecoder() 45 GIFImageDecoder::~GIFImageDecoder()
43 { 46 {
44 } 47 }
45 48
46 void GIFImageDecoder::onSetData(SharedBuffer* data) 49 void GIFImageDecoder::onSetData(SharedBuffer* data)
47 { 50 {
48 if (m_reader) 51 if (m_reader)
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
95 m_reader->frameContext(index)->isHeaderDefined()) ? 98 m_reader->frameContext(index)->isHeaderDefined()) ?
96 m_reader->frameContext(index)->delayTime() : 0; 99 m_reader->frameContext(index)->delayTime() : 0;
97 } 100 }
98 101
99 bool GIFImageDecoder::setFailed() 102 bool GIFImageDecoder::setFailed()
100 { 103 {
101 m_reader.clear(); 104 m_reader.clear();
102 return ImageDecoder::setFailed(); 105 return ImageDecoder::setFailed();
103 } 106 }
104 107
105 bool GIFImageDecoder::haveDecodedRow(size_t frameIndex, GIFRow::const_iterator r owBegin, size_t width, size_t rowNumber, unsigned repeatCount, bool writeTranspa rentPixels) 108 bool GIFImageDecoder::haveDecodedRowN32(size_t frameIndex, GIFRow::const_iterato r rowBegin, size_t width, size_t rowNumber, unsigned repeatCount, bool writeTran sparentPixels)
106 { 109 {
110 ASSERT(m_colorMode == ImageFrame::N32 || m_forceN32Decoding);
107 const GIFFrameContext* frameContext = m_reader->frameContext(frameIndex); 111 const GIFFrameContext* frameContext = m_reader->frameContext(frameIndex);
108 // The pixel data and coordinates supplied to us are relative to the frame's 112 // The pixel data and coordinates supplied to us are relative to the frame's
109 // origin within the entire image size, i.e. 113 // origin within the entire image size, i.e.
110 // (frameContext->xOffset, frameContext->yOffset). There is no guarantee 114 // (frameContext->xOffset, frameContext->yOffset). There is no guarantee
111 // that width == (size().width() - frameContext->xOffset), so 115 // that width == (size().width() - frameContext->xOffset), so
112 // we must ensure we don't run off the end of either the source data or the 116 // we must ensure we don't run off the end of either the source data or the
113 // row's X-coordinates. 117 // row's X-coordinates.
114 const int xBegin = frameContext->xOffset(); 118 const int xBegin = frameContext->xOffset();
115 const int yBegin = frameContext->yOffset() + rowNumber; 119 const int yBegin = frameContext->yOffset() + rowNumber;
116 const int xEnd = std::min(static_cast<int>(frameContext->xOffset() + width), size().width()); 120 const int xEnd = std::min(static_cast<int>(frameContext->xOffset() + width), size().width());
117 const int yEnd = std::min(static_cast<int>(frameContext->yOffset() + rowNumb er + repeatCount), size().height()); 121 const int yEnd = std::min(static_cast<int>(frameContext->yOffset() + rowNumb er + repeatCount), size().height());
118 if (!width || (xBegin < 0) || (yBegin < 0) || (xEnd <= xBegin) || (yEnd <= y Begin)) 122 if (!width || (xBegin < 0) || (yBegin < 0) || (xEnd <= xBegin) || (yEnd <= y Begin))
119 return true; 123 return true;
120 124
121 const GIFColorMap::Table& colorTable = frameContext->localColorMap().isDefin ed() ? frameContext->localColorMap().table() : m_reader->globalColorMap().table( ); 125 const GIFColorMap::Table& colorTable = frameContext->localColorMap().isDefin ed() ? frameContext->localColorMap().table() : m_reader->globalColorMap().table( );
122 126
123 if (colorTable.isEmpty()) 127 if (colorTable.isEmpty())
124 return true; 128 return true;
125 129
126 GIFColorMap::Table::const_iterator colorTableIter = colorTable.begin(); 130 GIFColorMap::Table::const_iterator colorTableIter = colorTable.begin();
127 131
128 // Initialize the frame if necessary.
129 ImageFrame& buffer = m_frameBufferCache[frameIndex]; 132 ImageFrame& buffer = m_frameBufferCache[frameIndex];
130 if ((buffer.status() == ImageFrame::FrameEmpty) && !initFrameBuffer(frameInd ex))
131 return false;
132
133 const size_t transparentPixel = frameContext->transparentPixel(); 133 const size_t transparentPixel = frameContext->transparentPixel();
134 GIFRow::const_iterator rowEnd = rowBegin + (xEnd - xBegin); 134 GIFRow::const_iterator rowEnd = rowBegin + (xEnd - xBegin);
135 ImageFrame::PixelData* currentAddress = buffer.getAddr(xBegin, yBegin); 135 ImageFrame::PixelData* currentAddress = buffer.getAddr(xBegin, yBegin);
136 136
137 // We may or may not need to write transparent pixels to the buffer. 137 // We may or may not need to write transparent pixels to the buffer.
138 // If we're compositing against a previous image, it's wrong, and if 138 // If we're compositing against a previous image, it's wrong, and if
139 // we're writing atop a cleared, fully transparent buffer, it's 139 // we're writing atop a cleared, fully transparent buffer, it's
140 // unnecessary; but if we're decoding an interlaced gif and 140 // unnecessary; but if we're decoding an interlaced gif and
141 // displaying it "Haeberli"-style, we must write these for passes 141 // displaying it "Haeberli"-style, we must write these for passes
142 // beyond the first, or the initial passes will "show through" the 142 // beyond the first, or the initial passes will "show through" the
(...skipping 24 matching lines...) Expand all
167 } 167 }
168 168
169 // Tell the frame to copy the row data if need be. 169 // Tell the frame to copy the row data if need be.
170 if (repeatCount > 1) 170 if (repeatCount > 1)
171 buffer.copyRowNTimes(xBegin, xEnd, yBegin, yEnd); 171 buffer.copyRowNTimes(xBegin, xEnd, yBegin, yEnd);
172 172
173 buffer.setPixelsChanged(true); 173 buffer.setPixelsChanged(true);
174 return true; 174 return true;
175 } 175 }
176 176
177 bool GIFImageDecoder::haveDecodedRowIndex8(size_t frameIndex, GIFRow::const_iter ator rowBegin, size_t width, size_t rowNumber, unsigned repeatCount, bool writeT ransparentPixels)
178 {
179 ASSERT(m_colorMode == ImageFrame::Index8 && !m_forceN32Decoding);
180 const GIFFrameContext* frameContext = m_reader->frameContext(frameIndex);
181 // The pixel data and coordinates supplied to us are relative to the frame's
182 // origin within the entire image size, i.e.
183 // (frameContext->xOffset, frameContext->yOffset). There is no guarantee
184 // that width == (size().width() - frameContext->xOffset), so
185 // we must ensure we don't run off the end of either the source data or the
186 // row's X-coordinates.
187 const int xBegin = frameContext->xOffset();
188 const int yBegin = frameContext->yOffset() + rowNumber;
189 const int xEnd = std::min(static_cast<int>(frameContext->xOffset() + width), size().width());
190 const int yEnd = std::min(static_cast<int>(frameContext->yOffset() + rowNumb er + repeatCount), size().height());
191 if (!width || (xBegin < 0) || (yBegin < 0) || (xEnd <= xBegin) || (yEnd <= y Begin))
192 return true;
193
194 const GIFColorMap::Table& colorTable = frameContext->localColorMap().isDefin ed() ? frameContext->localColorMap().table() : m_reader->globalColorMap().table( );
195
196 if (colorTable.isEmpty())
197 return true;
198
199
200 ImageFrame& buffer = m_frameBufferCache[frameIndex];
201 const size_t transparentPixel = frameContext->transparentPixel();
202 GIFRow::const_iterator rowEnd = rowBegin + (xEnd - xBegin);
203 ImageFrame::PixelData8* currentAddress = buffer.getAddr8(xBegin, yBegin);
204
205 bool opaque = true;
206 if (transparentPixel < colorTable.size()) {
207 // writeTransparentPixels is writing without check.
208 writeTransparentPixels = writeTransparentPixels || buffer.requiredPrevio usFrameIndex() == kNotFound;
209 if (writeTransparentPixels) {
210 for (; rowBegin != rowEnd;) {
211 opaque = opaque && (*rowBegin ^ transparentPixel);
212 *currentAddress++ = *rowBegin++;
213 }
214 } else {
215 for (; rowBegin != rowEnd; ++rowBegin, ++currentAddress) {
216 size_t index = *rowBegin;
217 if (index == transparentPixel) {
218 opaque = false;
219 } else {
220 *currentAddress = index;
221 }
222 }
223 }
224 } else {
225 // No transparency to deal with.
226 for (; rowBegin != rowEnd;)
227 *currentAddress++ = *rowBegin++;
228 }
229
230 m_currentBufferSawAlpha = !opaque;
231
232 // Tell the frame to copy the row data if specified.
233 if (repeatCount > 1) {
234 const int rowBytes = (xEnd - xBegin) * sizeof(uint8_t);
235 const ImageFrame::PixelData8* const startAddr = buffer.getAddr8(xBegin, yBegin);
236 for (int destY = yBegin + 1; destY < yEnd; ++destY)
237 memcpy(buffer.getAddr8(xBegin, destY), startAddr, rowBytes);
238 }
239
240 buffer.setPixelsChanged(true);
241 return true;
242 }
243
177 bool GIFImageDecoder::parseCompleted() const 244 bool GIFImageDecoder::parseCompleted() const
178 { 245 {
179 return m_reader && m_reader->parseCompleted(); 246 return m_reader && m_reader->parseCompleted();
180 } 247 }
181 248
182 bool GIFImageDecoder::frameComplete(size_t frameIndex) 249 bool GIFImageDecoder::frameComplete(size_t frameIndex)
183 { 250 {
184 // Initialize the frame if necessary. Some GIFs insert do-nothing frames, 251 // Initialize the frame if necessary. Some GIFs insert do-nothing frames,
185 // in which case we never reach haveDecodedRow() before getting here. 252 // in which case we never reach haveDecodedRow() before getting here.
186 ImageFrame& buffer = m_frameBufferCache[frameIndex]; 253 ImageFrame& buffer = m_frameBufferCache[frameIndex];
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
257 ImageFrame* buffer = &m_frameBufferCache[index]; 324 ImageFrame* buffer = &m_frameBufferCache[index];
258 const GIFFrameContext* frameContext = m_reader->frameContext(index); 325 const GIFFrameContext* frameContext = m_reader->frameContext(index);
259 buffer->setOriginalFrameRect(intersection(frameContext->frameRect(), IntRect (IntPoint(), size()))); 326 buffer->setOriginalFrameRect(intersection(frameContext->frameRect(), IntRect (IntPoint(), size())));
260 buffer->setDuration(frameContext->delayTime()); 327 buffer->setDuration(frameContext->delayTime());
261 buffer->setDisposalMethod(frameContext->disposalMethod()); 328 buffer->setDisposalMethod(frameContext->disposalMethod());
262 buffer->setRequiredPreviousFrameIndex(findRequiredPreviousFrame(index, false )); 329 buffer->setRequiredPreviousFrameIndex(findRequiredPreviousFrame(index, false ));
263 } 330 }
264 331
265 void GIFImageDecoder::decode(size_t index) 332 void GIFImageDecoder::decode(size_t index)
266 { 333 {
334 phaveDecodedRow = (m_colorMode == ImageFrame::Index8 && !m_forceN32Decoding)
335 ? (&GIFImageDecoder::haveDecodedRowIndex8)
336 : (&GIFImageDecoder::haveDecodedRowN32);
267 parse(GIFFrameCountQuery); 337 parse(GIFFrameCountQuery);
268 338
269 if (failed()) 339 if (failed())
270 return; 340 return;
271 341
272 Vector<size_t> framesToDecode; 342 Vector<size_t> framesToDecode;
273 size_t frameToDecode = index; 343 size_t frameToDecode = index;
274 do { 344 do {
275 framesToDecode.append(frameToDecode); 345 framesToDecode.append(frameToDecode);
276 frameToDecode = m_frameBufferCache[frameToDecode].requiredPreviousFrameI ndex(); 346 frameToDecode = m_frameBufferCache[frameToDecode].requiredPreviousFrameI ndex();
277 } while (frameToDecode != kNotFound && m_frameBufferCache[frameToDecode].sta tus() != ImageFrame::FrameComplete); 347 } while (frameToDecode != kNotFound && m_frameBufferCache[frameToDecode].sta tus() != ImageFrame::FrameComplete);
278 348
279 for (auto i = framesToDecode.rbegin(); i != framesToDecode.rend(); ++i) { 349 for (auto i = framesToDecode.rbegin(); i != framesToDecode.rend(); ++i) {
350 bool notSuitableForIndex8(m_forceN32Decoding);
280 if (!m_reader->decode(*i)) { 351 if (!m_reader->decode(*i)) {
281 setFailed(); 352 // Decoder asks to switch color mode as Index8 is not applicable. Tr y to decode using N32.
282 return; 353 // This happens only when transparent pixels showing previous frames or offsets are detected
354 // and table is changed.
355 if (notSuitableForIndex8 != m_forceN32Decoding) {
356 ASSERT(m_colorMode == ImageFrame::Index8);
357 clearFrameBuffer(*i);
358 // N32 decoding would continue until there is non dependent Inde x8 frame detected, see initFrameBuffer().
359 phaveDecodedRow = &GIFImageDecoder::haveDecodedRowN32;
360 if (!m_reader->decode(*i)) {
361 setFailed();
362 return;
363 }
364 } else {
365 setFailed();
366 return;
367 }
283 } 368 }
284 369
285 // We need more data to continue decoding. 370 // We need more data to continue decoding.
286 if (m_frameBufferCache[*i].status() != ImageFrame::FrameComplete) 371 if (m_frameBufferCache[*i].status() != ImageFrame::FrameComplete)
287 break; 372 break;
288 } 373 }
289 374
290 // It is also a fatal error if all data is received and we have decoded all 375 // It is also a fatal error if all data is received and we have decoded all
291 // frames available but the file is truncated. 376 // frames available but the file is truncated.
292 if (index >= m_frameBufferCache.size() - 1 && isAllDataReceived() && m_reade r && !m_reader->parseCompleted()) 377 if (index >= m_frameBufferCache.size() - 1 && isAllDataReceived() && m_reade r && !m_reader->parseCompleted())
293 setFailed(); 378 setFailed();
294 } 379 }
295 380
381 void GIFImageDecoder::setForceN32Decoding(bool value)
382 {
383 ASSERT(m_colorMode == ImageFrame::Index8);
384 m_forceN32Decoding = value;
385 phaveDecodedRow = (!value && m_colorMode == ImageFrame::Index8)
386 ? (&GIFImageDecoder::haveDecodedRowIndex8)
387 : (&GIFImageDecoder::haveDecodedRowN32);
388 }
389
296 void GIFImageDecoder::parse(GIFParseQuery query) 390 void GIFImageDecoder::parse(GIFParseQuery query)
297 { 391 {
298 if (failed()) 392 if (failed())
299 return; 393 return;
300 394
301 if (!m_reader) { 395 if (!m_reader) {
302 m_reader = adoptPtr(new GIFImageReader(this)); 396 m_reader = adoptPtr(new GIFImageReader(this));
303 m_reader->setData(m_data); 397 m_reader->setData(m_data);
304 } 398 }
305 399
306 if (!m_reader->parse(query)) 400 if (!m_reader->parse(query))
307 setFailed(); 401 setFailed();
308 } 402 }
309 403
310 bool GIFImageDecoder::initFrameBuffer(size_t frameIndex) 404 bool GIFImageDecoder::initFrameBufferN32(size_t frameIndex)
311 { 405 {
312 // Initialize the frame rect in our buffer. 406 // Initialize the frame rect in our buffer.
313 ImageFrame* const buffer = &m_frameBufferCache[frameIndex]; 407 ImageFrame* const buffer = &m_frameBufferCache[frameIndex];
314 408
315 size_t requiredPreviousFrameIndex = buffer->requiredPreviousFrameIndex(); 409 size_t requiredPreviousFrameIndex = buffer->requiredPreviousFrameIndex();
316 if (requiredPreviousFrameIndex == kNotFound) { 410 if (requiredPreviousFrameIndex == kNotFound) {
317 // This frame doesn't rely on any previous data. 411 // This frame doesn't rely on any previous data.
318 if (!buffer->setSize(size().width(), size().height())) 412 if (!buffer->setSize(size().width(), size().height()))
319 return setFailed(); 413 return setFailed();
320 } else { 414 } else {
(...skipping 14 matching lines...) Expand all
335 } 429 }
336 430
337 // Update our status to be partially complete. 431 // Update our status to be partially complete.
338 buffer->setStatus(ImageFrame::FramePartial); 432 buffer->setStatus(ImageFrame::FramePartial);
339 433
340 // Reset the alpha pixel tracker for this frame. 434 // Reset the alpha pixel tracker for this frame.
341 m_currentBufferSawAlpha = false; 435 m_currentBufferSawAlpha = false;
342 return true; 436 return true;
343 } 437 }
344 438
439 static bool framesUseSameColorTable(const GIFFrameContext& frame1, const GIFFram eContext& frame2)
440 {
441 auto frame1Local = frame1.localColorMap();
442 auto frame2Local = frame2.localColorMap();
443 bool useFrame1Local = frame1Local.isDefined();
444 bool useFrame2Local = frame2Local.isDefined();
445 if (useFrame1Local != useFrame2Local)
446 return false;
447 size_t transparent1 = frame1.transparentPixel();
448 size_t transparent2 = frame2.transparentPixel();
449 if (!useFrame1Local) {
450 // They both use global ColorMap, check if transparent pixels are the sa me.
451 ASSERT(!useFrame2Local);
452 return (transparent1 == transparent2);
453 }
454 // Both use local color maps, check if it is the same.
455 return ((frame1Local.getPosition() == frame2Local.getPosition()) && (transpa rent1 == transparent2));
456 }
457
458 // Helper method for recomputing if frame decoding has no dependency to previous frames.
459 void GIFImageDecoder::updateRequiredPreviousFrame(ImageFrame* buffer, const GIFF rameContext& frameContext)
460 {
461 ASSERT(m_colorMode == ImageFrame::Index8);
462 if (buffer->requiredPreviousFrameIndex() == kNotFound)
463 return;
464
465 bool isFullScreen = frameContext.frameRect().contains(IntRect(IntPoint(), si ze()));
466 const GIFColorMap::Table& colorTable = frameContext.localColorMap().isDefine d()
467 ? frameContext.localColorMap().table() : m_reader->globalColorMap().tabl e();
468
469 // If transparent pixel is outside color table, there is no transparent pixe l.
470 // e.g. Color table in some of the GIFs is having 40 elements and transparen tPixel set to 0xFF.
471 bool opaque = frameContext.transparentPixel() >= colorTable.size();
472
473 // If fullscreen and opaque, the frame is independent of previous frame.
474 if (isFullScreen && opaque)
475 buffer->setRequiredPreviousFrameIndex(kNotFound);
476 }
477
478 bool GIFImageDecoder::initFrameBuffer(size_t frameIndex)
479 {
480 ImageFrame* buffer = &m_frameBufferCache[frameIndex];
481 if (buffer->status() != ImageFrame::FrameEmpty)
482 return true;
483
484 if (m_colorMode == ImageFrame::N32) {
485 return initFrameBufferN32(frameIndex);
486 }
487 const GIFFrameContext* frameContext = m_reader->frameContext(frameIndex);
488 updateRequiredPreviousFrame(buffer, *frameContext);
489 size_t requiredPreviousFrameIndex = buffer->requiredPreviousFrameIndex();
490
491 if (requiredPreviousFrameIndex == kNotFound) {
492 // This frame doesn't rely on any previous data and it is OK to
493 // switch back from forced N32 to Index8.
494 setForceN32Decoding(false);
495 // phaveDecodedRow = &GIFImageDecoder::haveDecodedRowIndex8;
496 const GIFColorMap::Table& colorTable = frameContext->localColorMap().isD efined()
497 ? frameContext->localColorMap().table() : m_reader->globalColorMap() .table();
498 if (!buffer->setSizeIndex8(size().width(), size().height(), colorTable, frameContext->transparentPixel()))
499 return setFailed();
500 } else {
501 const ImageFrame* prevBuffer = &m_frameBufferCache[requiredPreviousFrame Index];
502 ASSERT(prevBuffer->status() == ImageFrame::FrameComplete);
503
504 // Preserve the last frame as the starting state for this frame.
505 bool useN32 = true;
506 if (!m_forceN32Decoding) {
507 // If color table is different from previous frame and in the same t ime, there is transparency
508 // or the frame is subrect, cannot do Index8. Otherwise, with the sa me table, no problem to continue
509 // with Index8 and start decoding from a copy of required frame.
510 if (framesUseSameColorTable(*frameContext, *(m_reader->frameContext( requiredPreviousFrameIndex)))) {
511 useN32 = false;
512 if (!buffer->copyBitmapData(*prevBuffer))
513 return setFailed();
514 ASSERT(buffer->getSkBitmap().colorType() == kIndex_8_SkColorType );
515 } else {
516 setForceN32Decoding(true);
517 useN32 = true;
518 }
519 }
520 // For unsupported Index8 and N32, next frame starts as previous frame c opy to N32.
521 if (useN32 && !buffer->copyBitmapData(*prevBuffer, ImageFrame::N32))
522 return setFailed();
523
524 if (prevBuffer->disposalMethod() == ImageFrame::DisposeOverwriteBgcolor) {
525 // We want to clear the previous frame to transparent, without
526 // affecting pixels in the image outside of the frame.
527 const IntRect& prevRect = prevBuffer->originalFrameRect();
528 ASSERT(!prevRect.contains(IntRect(IntPoint(), size())));
529 buffer->zeroFillFrameRect(prevRect);
530 }
531 }
532
533 // Update our status to be partially complete.
534 buffer->setStatus(ImageFrame::FramePartial);
535
536 // Reset the alpha pixel tracker for this frame.
537 m_currentBufferSawAlpha = false;
538 return true;
539 }
540
541 bool GIFImageDecoder::canDecodeTo(size_t index, ImageFrame::ColorType outputType )
542 {
543 if ((index >= frameCount()) || (m_colorMode == ImageFrame::N32) || failed())
544 return (outputType == m_colorMode);
545
546 // Go from one to previous until calculating if Index8 is supported.
547 size_t frameToDecode = index;
548 ImageFrame::ColorType calculatedOutput = ImageFrame::Index8;
549 while (frameToDecode != kNotFound) {
550 ImageFrame* buffer = &m_frameBufferCache[frameToDecode];
551 if (buffer->status() == ImageFrame::FrameComplete) {
552 // In this case, color type from complete frame is kept.
553 calculatedOutput = static_cast<ImageFrame::ColorType>(buffer->getSkB itmap().colorType());
554 break;
555 }
556 const GIFFrameContext* frameContext = m_reader->frameContext(frameToDeco de);
557 updateRequiredPreviousFrame(buffer, *frameContext);
558 if (buffer->requiredPreviousFrameIndex() == kNotFound)
559 break;
560 frameToDecode = m_frameBufferCache[frameToDecode].requiredPreviousFrameI ndex();
561 if (frameToDecode != kNotFound && !framesUseSameColorTable(*frameContext , *(m_reader->frameContext(frameToDecode)))) {
562 // If dependent to previous frame and they don't use the same color table, not possible to use Index8.
563 calculatedOutput = ImageFrame::N32;
564 break;
565 }
566 }
567 return (calculatedOutput == outputType);
568 }
569
345 } // namespace blink 570 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698