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

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: Comment #25 processed. Created 4 years, 11 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 10 matching lines...) Expand all
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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 "platform/image-decoders/gif/GIFImageDecoder.h" 26 #include "platform/image-decoders/gif/GIFImageDecoder.h"
27 27
28 #include <limits> 28 #include <limits>
29 #include "platform/image-decoders/gif/GIFImageReader.h" 29 #include "platform/image-decoders/gif/GIFImageReader.h"
30 #include "wtf/NotFound.h" 30 #include "wtf/NotFound.h"
31 #include "wtf/PassOwnPtr.h"
scroggo_chromium 2016/04/29 19:48:14 Unrelated change?
32 31
33 namespace blink { 32 namespace blink {
34 33
35 GIFImageDecoder::GIFImageDecoder(AlphaOption alphaOption, GammaAndColorProfileOp tion colorOptions, size_t maxDecodedBytes) 34 GIFImageDecoder::GIFImageDecoder(AlphaOption alphaOption, GammaAndColorProfileOp tion colorOptions, size_t maxDecodedBytes, ImageFrame::ColorType colorType)
36 : ImageDecoder(alphaOption, colorOptions, maxDecodedBytes) 35 : ImageDecoder(alphaOption, colorOptions, maxDecodedBytes)
37 , m_repetitionCount(cAnimationLoopOnce) 36 , m_repetitionCount(cAnimationLoopOnce)
37 , m_requestedColorMode(colorType)
38 { 38 {
39 } 39 }
40 40
41 GIFImageDecoder::~GIFImageDecoder() 41 GIFImageDecoder::~GIFImageDecoder()
42 { 42 {
43 } 43 }
44 44
45 void GIFImageDecoder::onSetData(SharedBuffer* data) 45 void GIFImageDecoder::onSetData(SharedBuffer* data)
46 { 46 {
47 if (m_reader) 47 if (m_reader)
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 m_reader->frameContext(index)->isHeaderDefined()) ? 94 m_reader->frameContext(index)->isHeaderDefined()) ?
95 m_reader->frameContext(index)->delayTime() : 0; 95 m_reader->frameContext(index)->delayTime() : 0;
96 } 96 }
97 97
98 bool GIFImageDecoder::setFailed() 98 bool GIFImageDecoder::setFailed()
99 { 99 {
100 m_reader.clear(); 100 m_reader.clear();
101 return ImageDecoder::setFailed(); 101 return ImageDecoder::setFailed();
102 } 102 }
103 103
104 bool GIFImageDecoder::haveDecodedRow(size_t frameIndex, GIFRow::const_iterator r owBegin, size_t width, size_t rowNumber, unsigned repeatCount, bool writeTranspa rentPixels) 104 static inline const GIFColorMap& getColorMap(const GIFFrameContext& frameContext , const GIFImageReader& reader)
105 { 105 {
106 const GIFFrameContext* frameContext = m_reader->frameContext(frameIndex); 106 return (frameContext.localColorMap().isDefined() ? frameContext.localColorMa p() : reader.globalColorMap());
107 }
108
109 void GIFImageDecoder::haveDecodedRow(const GIFFrameContext& frameContext, GIFRow ::const_iterator rowBegin, size_t rowNumber, unsigned repeatCount, bool writeTra nsparentPixels)
110 {
107 // The pixel data and coordinates supplied to us are relative to the frame's 111 // The pixel data and coordinates supplied to us are relative to the frame's
108 // origin within the entire image size, i.e. 112 // origin within the entire image size, i.e.
109 // (frameContext->xOffset, frameContext->yOffset). There is no guarantee 113 // (frameContext->xOffset, frameContext->yOffset). There is no guarantee
110 // that width == (size().width() - frameContext->xOffset), so 114 // that width == (size().width() - frameContext->xOffset), so
111 // we must ensure we don't run off the end of either the source data or the 115 // we must ensure we don't run off the end of either the source data or the
112 // row's X-coordinates. 116 // row's X-coordinates.
113 const int xBegin = frameContext->xOffset(); 117 const size_t width = frameContext.width();
114 const int yBegin = frameContext->yOffset() + rowNumber; 118 const int xBegin = frameContext.xOffset();
115 const int xEnd = std::min(static_cast<int>(frameContext->xOffset() + width), size().width()); 119 const int yBegin = frameContext.yOffset() + rowNumber;
116 const int yEnd = std::min(static_cast<int>(frameContext->yOffset() + rowNumb er + repeatCount), size().height()); 120 const int xEnd = std::min(static_cast<int>(xBegin + width), size().width());
121 const int yEnd = std::min(static_cast<int>(yBegin + repeatCount), size().hei ght());
117 if (!width || (xBegin < 0) || (yBegin < 0) || (xEnd <= xBegin) || (yEnd <= y Begin)) 122 if (!width || (xBegin < 0) || (yBegin < 0) || (xEnd <= xBegin) || (yEnd <= y Begin))
118 return true; 123 return;
119 124
120 const GIFColorMap::Table& colorTable = frameContext->localColorMap().isDefin ed() ? frameContext->localColorMap().table() : m_reader->globalColorMap().table( ); 125 const GIFColorTable& colorTable = getColorMap(frameContext, *m_reader).table ();
121 126
122 if (colorTable.isEmpty()) 127 if (colorTable.isEmpty())
123 return true; 128 return;
124 129
125 GIFColorMap::Table::const_iterator colorTableIter = colorTable.begin(); 130 ImageFrame& buffer = m_frameBufferCache[frameContext.frameId()];
scroggo_chromium 2016/04/29 19:48:15 As I understand it, we will now have always initia
131 GIFRow::const_iterator rowEnd = rowBegin + (xEnd - xBegin);
126 132
127 // Initialize the frame if necessary. 133 (this->*m_writeRowFunction)(frameContext, buffer, colorTable, rowBegin, rowE nd, xBegin, yBegin, writeTransparentPixels);
128 ImageFrame& buffer = m_frameBufferCache[frameIndex];
129 if ((buffer.status() == ImageFrame::FrameEmpty) && !initFrameBuffer(frameInd ex))
130 return false;
131 134
132 const size_t transparentPixel = frameContext->transparentPixel(); 135 // Tell the frame to copy the row data if need be.
133 GIFRow::const_iterator rowEnd = rowBegin + (xEnd - xBegin); 136 if (repeatCount > 1)
137 (*m_copyRowNTimesFunction)(buffer, xBegin, xEnd, yBegin, yEnd);
scroggo_chromium 2016/04/29 19:48:14 I found it weird that this method does not take N
138
139 buffer.setPixelsChanged(true);
140 }
141
142
143 void GIFImageDecoder::writeRowN32(const GIFFrameContext& frameContext, ImageFram e& buffer, const GIFColorTable& colorTable, GIFRow::const_iterator rowBegin, GIF Row::const_iterator rowEnd, int xBegin, int yBegin, bool writeTransparentPixels)
144 {
145 ASSERT(m_frameBufferCache[frameContext.frameId()].bitmap().colorType() == kN 32_SkColorType);
146
147 GIFColorTable::const_iterator colorTableIter = colorTable.begin();
148 const size_t transparentPixel = frameContext.transparentPixel();
134 ImageFrame::PixelData* currentAddress = buffer.getAddr(xBegin, yBegin); 149 ImageFrame::PixelData* currentAddress = buffer.getAddr(xBegin, yBegin);
135 150
136 // We may or may not need to write transparent pixels to the buffer. 151 // We may or may not need to write transparent pixels to the buffer.
137 // If we're compositing against a previous image, it's wrong, and if 152 // If we're compositing against a previous image, it's wrong, and if
138 // we're writing atop a cleared, fully transparent buffer, it's 153 // we're writing atop a cleared, fully transparent buffer, it's
139 // unnecessary; but if we're decoding an interlaced gif and 154 // unnecessary; but if we're decoding an interlaced gif and
140 // displaying it "Haeberli"-style, we must write these for passes 155 // displaying it "Haeberli"-style, we must write these for passes
141 // beyond the first, or the initial passes will "show through" the 156 // beyond the first, or the initial passes will "show through" the
142 // later ones. 157 // later ones.
143 // 158 //
(...skipping 13 matching lines...) Expand all
157 } 172 }
158 } else { 173 } else {
159 for (; rowBegin != rowEnd; ++rowBegin, ++currentAddress) { 174 for (; rowBegin != rowEnd; ++rowBegin, ++currentAddress) {
160 const size_t sourceValue = *rowBegin; 175 const size_t sourceValue = *rowBegin;
161 if ((sourceValue != transparentPixel) && (sourceValue < colorTable.s ize())) 176 if ((sourceValue != transparentPixel) && (sourceValue < colorTable.s ize()))
162 *currentAddress = colorTableIter[sourceValue]; 177 *currentAddress = colorTableIter[sourceValue];
163 else 178 else
164 m_currentBufferSawAlpha = true; 179 m_currentBufferSawAlpha = true;
165 } 180 }
166 } 181 }
182 }
167 183
168 // Tell the frame to copy the row data if need be. 184 void GIFImageDecoder::writeRowIndex8(const GIFFrameContext& frameContext, ImageF rame& buffer, const GIFColorTable& colorTable, GIFRow::const_iterator rowBegin, GIFRow::const_iterator rowEnd, int xBegin, int yBegin, bool writeTransparentPixe ls)
169 if (repeatCount > 1) 185 {
170 buffer.copyRowNTimes(xBegin, xEnd, yBegin, yEnd); 186 ASSERT(m_frameBufferCache[frameContext.frameId()].bitmap().colorType() == kI ndex_8_SkColorType);
171 187
172 buffer.setPixelsChanged(true); 188 const size_t transparentPixel = frameContext.transparentPixel();
173 return true; 189 ImageFrame::PixelData8* currentAddress = buffer.getAddr8(xBegin, yBegin);
190
191 bool opaque = true;
192 // writeTransparentPixels is writing without check, but calculates if there
scroggo_chromium 2016/04/29 19:48:15 What does this mean? It sure looks like if (writeT
193 // is transparency (m_currentBufferSawAlpha). If transparency was found in
194 // previous rows, no need to calculate here.
scroggo_chromium 2016/04/29 19:48:15 Would writeRowN32 benefit from this optimization?
195 writeTransparentPixels = writeTransparentPixels || buffer.requiredPreviousFr ameIndex() == kNotFound;
196 if (transparentPixel < colorTable.size() && !(writeTransparentPixels && m_cu rrentBufferSawAlpha)) {
197 if (writeTransparentPixels) {
198 while (rowBegin != rowEnd) {
199 opaque = opaque && (*rowBegin ^ transparentPixel);
200 *currentAddress++ = *rowBegin++;
201 }
202 } else {
203 for (; rowBegin != rowEnd; ++rowBegin, ++currentAddress) {
204 size_t index = *rowBegin;
205 if (index == transparentPixel) {
scroggo_chromium 2016/04/29 19:48:15 I personally prefer braces here, but the style gui
206 opaque = false;
207 } else {
208 *currentAddress = index;
209 }
210 }
211 }
212 } else {
213 // No transparency to deal with.
scroggo_chromium 2016/04/29 19:48:15 I think this comment is misleading. We're not keep
214 if (rowEnd - rowBegin == size().width()) {
215 size_t* destination = (size_t*)currentAddress;
216 const size_t* source = (const size_t*)rowBegin;
217 const size_t count = (rowEnd - rowBegin + sizeof(size_t) - 1) / size of(size_t);
218 const size_t* sourceEnd = source + count;
219 while (source != sourceEnd)
scroggo_chromium 2016/04/29 19:48:14 Why is this not a memcpy?
220 *destination++ = *source++;
221 } else {
222 while (rowBegin != rowEnd)
scroggo_chromium 2016/04/29 19:48:15 Can this be a memcpy?
223 *currentAddress++ = *rowBegin++;
224 }
225 }
226
227 if (!opaque)
228 m_currentBufferSawAlpha = true;
229 }
230
231 // Copies the pixel data at [(xBegin, yBegin), (xEnd, yEnd)) to the
scroggo_chromium 2016/04/29 19:48:15 Don't these actually copy the data from [(xBegin,
232 // same X-coordinates on each subsequent row up to but not including
233 // yEnd.
234 static void copyRowNTimesFunctionN32(ImageFrame& buffer, int xBegin, int xEnd, i nt yBegin, int yEnd)
235 {
236 const int rowBytes = (xEnd - xBegin) * sizeof(ImageFrame::PixelData);
scroggo_chromium 2016/04/29 19:48:15 I'm not sure "rowBytes" is the correct name here.
237 const ImageFrame::PixelData* const startAddr = buffer.getAddr(xBegin, yBegin );
238 for (int destY = yBegin + 1; destY < yEnd; ++destY)
239 memcpy(buffer.getAddr(xBegin, destY), startAddr, rowBytes);
240 }
241
242 static void copyRowNTimesFunctionIndex8(ImageFrame& buffer, int xBegin, int xEnd , int yBegin, int yEnd)
243 {
244 const int rowBytes = (xEnd - xBegin) * sizeof(ImageFrame::PixelData8);
245 const ImageFrame::PixelData8* const startAddr = buffer.getAddr8(xBegin, yBeg in);
246 for (int destY = yBegin + 1; destY < yEnd; ++destY)
247 memcpy(buffer.getAddr8(xBegin, destY), startAddr, rowBytes);
174 } 248 }
175 249
176 bool GIFImageDecoder::parseCompleted() const 250 bool GIFImageDecoder::parseCompleted() const
177 { 251 {
178 return m_reader && m_reader->parseCompleted(); 252 return m_reader && m_reader->parseCompleted();
179 } 253 }
180 254
181 bool GIFImageDecoder::frameComplete(size_t frameIndex) 255 bool GIFImageDecoder::frameComplete(size_t frameIndex)
182 { 256 {
183 // Initialize the frame if necessary. Some GIFs insert do-nothing frames, 257 // Initialize the frame if necessary. Some GIFs insert do-nothing frames,
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
285 if (m_frameBufferCache[*i].status() != ImageFrame::FrameComplete) 359 if (m_frameBufferCache[*i].status() != ImageFrame::FrameComplete)
286 break; 360 break;
287 } 361 }
288 362
289 // It is also a fatal error if all data is received and we have decoded all 363 // It is also a fatal error if all data is received and we have decoded all
290 // frames available but the file is truncated. 364 // frames available but the file is truncated.
291 if (index >= m_frameBufferCache.size() - 1 && isAllDataReceived() && m_reade r && !m_reader->parseCompleted()) 365 if (index >= m_frameBufferCache.size() - 1 && isAllDataReceived() && m_reade r && !m_reader->parseCompleted())
292 setFailed(); 366 setFailed();
293 } 367 }
294 368
369 void GIFImageDecoder::setupHaveDecodedRowCallbacks(bool isIndex8)
370 {
371 if (isIndex8) {
372 m_writeRowFunction = &GIFImageDecoder::writeRowIndex8;
373 m_copyRowNTimesFunction = &copyRowNTimesFunctionIndex8;
374 } else {
375 m_writeRowFunction = &GIFImageDecoder::writeRowN32;
376 m_copyRowNTimesFunction = &copyRowNTimesFunctionN32;
377 }
378 }
379
295 void GIFImageDecoder::parse(GIFParseQuery query) 380 void GIFImageDecoder::parse(GIFParseQuery query)
296 { 381 {
297 if (failed()) 382 if (failed())
298 return; 383 return;
299 384
300 if (!m_reader) { 385 if (!m_reader) {
301 m_reader = adoptPtr(new GIFImageReader(this)); 386 m_reader = adoptPtr(new GIFImageReader(this));
302 m_reader->setData(m_data); 387 m_reader->setData(m_data);
303 } 388 }
304 389
305 if (!m_reader->parse(query)) 390 if (!m_reader->parse(query))
306 setFailed(); 391 setFailed();
307 } 392 }
308 393
394 bool GIFImageDecoder::initFrameBufferFromPrevious(ImageFrame* buffer, const Imag eFrame& previousBuffer, ImageFrame::ColorType targetType, size_t transparentInde x)
395 {
396 // Preserve the last frame as the starting state for this frame.
397 if (!buffer->copyBitmapData(previousBuffer, targetType))
398 return false;
399
400 if (previousBuffer.disposalMethod() == ImageFrame::DisposeOverwriteBgcolor) {
401 // We want to clear the previous frame to transparent, without
402 // affecting pixels in the image outside of the frame.
403 const IntRect& prevRect = previousBuffer.originalFrameRect();
404 ASSERT(!prevRect.contains(IntRect(IntPoint(), size())));
405 if (targetType == ImageFrame::Index8)
406 buffer->zeroFillFrameRectIndex8(prevRect, (transparentIndex > 255) ? 255 : transparentIndex);
scroggo_chromium 2016/04/29 19:48:14 I think I've brought this up before - this looks l
407 else
408 buffer->zeroFillFrameRect(prevRect);
409 }
410 return true;
411 }
412
413 bool GIFImageDecoder::initFrameBufferN32(size_t frameIndex)
414 {
415 setupHaveDecodedRowCallbacks(false);
416
417 // Initialize the frame rect in our buffer.
418 ImageFrame* buffer = &m_frameBufferCache[frameIndex];
419
420 size_t requiredPreviousFrameIndex = buffer->requiredPreviousFrameIndex();
421 if (requiredPreviousFrameIndex == kNotFound) {
422 // This frame doesn't rely on any previous data.
scroggo_chromium 2016/04/29 19:48:15 If it does not rely on previous data, can we not s
423 if (!buffer->setSize(size().width(), size().height(), getBackgroundColor (frameIndex)))
424 return setFailed();
425 } else {
426 const ImageFrame* prevBuffer = &m_frameBufferCache[requiredPreviousFrame Index];
427 ASSERT(prevBuffer->status() == ImageFrame::FrameComplete);
428 if (!initFrameBufferFromPrevious(buffer, *prevBuffer, ImageFrame::N32))
429 return setFailed();
430 }
431
432 // Update our status to be partially complete.
433 buffer->setStatus(ImageFrame::FramePartial);
434
435 // Reset the alpha pixel tracker for this frame.
436 m_currentBufferSawAlpha = false;
437 return true;
438 }
439
440 bool GIFImageDecoder::isIndex8Applicable(const GIFFrameContext& frame, size_t re quiredPreviousFrameIndex) const
441 {
442 const GIFColorMap& colorMap = getColorMap(frame, *m_reader);
443 const bool useGlobalColorMap = !frame.localColorMap().isDefined();
444 const bool transparencySupported = colorMap.getTableSize() < 256 || frame.tr ansparentPixel() >= colorMap.getTableSize();
445
446 if (requiredPreviousFrameIndex == kNotFound) {
447 if (!transparencySupported
scroggo_chromium 2016/04/29 19:48:14 Why not switch this from: if (condition) { retu
448 && useGlobalColorMap && m_reader->backgroundIndex() >= colorMap.getT ableSize()
449 && (!isAllDataReceived() || !frame.frameRect().contains(IntRect(IntP oint(), size())))) {
450 // Background is filled with transparency or with background color -
451 // background color is used for opaque gifs.
452 // Return false when there is a need for transparency and no space
453 // in colormap for it; when colormap is opaque and full (it has 256
454 // entries) and at the same time
455 // - image is not fully received, so missing part would need to be
456 // presented as transparent, or
457 // - the frame is not fullscreen, i.e. it would be decoded to a sub
458 // rectangle of the image rectangle.
459 return false;
460 }
461 return true;
462 }
463
464 const GIFFrameContext& previousFrame(*(m_reader->frameContext(requiredPrevio usFrameIndex)));
465
466 // Skip Index8 for DisposeOverwriteBgcolor disposal method if there is no tr ansparency.
467 if (previousFrame.disposalMethod() == ImageFrame::DisposeOverwriteBgcolor && !transparencySupported)
468 return false;
469
470 // If frame shares colormap with required previous frame, it is possible to keep using Index8.
471 const GIFColorMap& previousColorMap = getColorMap(previousFrame, *m_reader);
472 return ((colorMap.getPosition() == previousColorMap.getPosition()) && (frame .transparentPixel() == previousFrame.transparentPixel()));
473 }
474
475 // Helper method to check if a previous frame dependency can be removed.
476 void GIFImageDecoder::updateRequiredPreviousFrame(ImageFrame* buffer, const GIFF rameContext& frameContext)
477 {
478 ASSERT(m_requestedColorMode == ImageFrame::Index8);
479 if (buffer->requiredPreviousFrameIndex() == kNotFound)
480 return;
481
482 bool isFullScreen = frameContext.frameRect().contains(IntRect(IntPoint(), si ze()));
483
484 // If fullscreen and opaque, the frame is independent of previous frame.
scroggo_chromium 2016/04/29 19:48:15 This comment seems a little out of place to me. Ho
485 if (!isFullScreen)
486 return;
487
488 // If transparent pixel is outside color table, there is no transparent
489 // pixel, e.g. color table in some of the GIFs has 40 elements and
490 // transparentPixel value is 0xFF.
491 if (frameContext.transparentPixel() >= getColorMap(frameContext, *m_reader). getTableSize())
492 buffer->setRequiredPreviousFrameIndex(kNotFound);
493 }
494
495 // Returns transparent index or background index.
496 unsigned GIFImageDecoder::getBackgroundIndex(const GIFFrameContext& frameContext ) const
497 {
498 const size_t background = frameContext.transparentPixel();
499 const GIFColorMap& colorMap = getColorMap(frameContext, *m_reader);
500 if (background < colorMap.getTableSize())
501 return background;
502
503 if (!frameContext.localColorMap().isDefined() && m_reader->backgroundIndex() < colorMap.getTableSize())
504 return m_reader->backgroundIndex();
505 return -1;
scroggo_chromium 2016/04/29 19:48:15 Again, I think it's weird to return -1 as an unsig
506 }
507
508 SkColor GIFImageDecoder::getBackgroundColor(size_t frameIndex) const
509 {
510 const GIFFrameContext* frameContext = m_reader->frameContext(frameIndex);
511 unsigned backgroundIndex = getBackgroundIndex(*frameContext);
512 if (frameContext->transparentPixel() == backgroundIndex)
513 return SK_ColorTRANSPARENT;
514 const GIFColorTable& table = getColorMap(*frameContext, *m_reader).table();
515 return (backgroundIndex < table.size() ? table[backgroundIndex]: SK_ColorTRA NSPARENT);
scroggo_chromium 2016/04/29 19:48:15 How does this fall back to transparent? It seems l
516 }
517
309 bool GIFImageDecoder::initFrameBuffer(size_t frameIndex) 518 bool GIFImageDecoder::initFrameBuffer(size_t frameIndex)
310 { 519 {
311 // Initialize the frame rect in our buffer. 520 ImageFrame* buffer = &m_frameBufferCache[frameIndex];
312 ImageFrame* const buffer = &m_frameBufferCache[frameIndex]; 521 if (buffer->status() != ImageFrame::FrameEmpty) {
522 // If it is partial, decode to the same bitmap.
523 setupHaveDecodedRowCallbacks(buffer->getSkBitmap().colorType() == kIndex _8_SkColorType);
524 return true;
525 }
313 526
314 size_t requiredPreviousFrameIndex = buffer->requiredPreviousFrameIndex(); 527 if (m_requestedColorMode == ImageFrame::N32) {
528 return initFrameBufferN32(frameIndex);
529 }
530 const GIFFrameContext* frameContext = m_reader->frameContext(frameIndex);
531 updateRequiredPreviousFrame(buffer, *frameContext);
532 const size_t requiredPreviousFrameIndex = buffer->requiredPreviousFrameIndex ();
533
534 bool useIndex8 = true;
315 if (requiredPreviousFrameIndex == kNotFound) { 535 if (requiredPreviousFrameIndex == kNotFound) {
316 // This frame doesn't rely on any previous data. 536 if (isIndex8Applicable(*frameContext, requiredPreviousFrameIndex)) {
317 if (!buffer->setSize(size().width(), size().height())) 537 const unsigned backgroundIndex = getBackgroundIndex(*frameContext);
318 return setFailed(); 538 if (!buffer->setSizeIndex8(
539 size().width(), size().height(),
540 getColorMap(*frameContext, *m_reader).table(), backgroundIndex,
541 backgroundIndex == frameContext->transparentPixel()))
542 return setFailed();
543 } else {
544 return initFrameBufferN32(frameIndex);
545 }
319 } else { 546 } else {
320 const ImageFrame* prevBuffer = &m_frameBufferCache[requiredPreviousFrame Index]; 547 const ImageFrame* prevBuffer = &m_frameBufferCache[requiredPreviousFrame Index];
321 ASSERT(prevBuffer->status() == ImageFrame::FrameComplete); 548 ASSERT(prevBuffer->status() == ImageFrame::FrameComplete);
322 549
323 // Preserve the last frame as the starting state for this frame. 550 // Copy the required completed frame as the starting state for this fram e.
324 if (!buffer->copyBitmapData(*prevBuffer)) 551 useIndex8 = (prevBuffer->getSkBitmap().colorType() == kIndex_8_SkColorTy pe) && isIndex8Applicable(*frameContext, requiredPreviousFrameIndex);
552 if (!initFrameBufferFromPrevious(buffer, *prevBuffer, useIndex8 ? ImageF rame::Index8 : ImageFrame::N32, frameContext->transparentPixel()))
325 return setFailed(); 553 return setFailed();
326 554 ASSERT(useIndex8 == (buffer->getSkBitmap().colorType() == kIndex_8_SkCol orType));
327 if (prevBuffer->disposalMethod() == ImageFrame::DisposeOverwriteBgcolor) {
328 // We want to clear the previous frame to transparent, without
329 // affecting pixels in the image outside of the frame.
330 const IntRect& prevRect = prevBuffer->originalFrameRect();
331 ASSERT(!prevRect.contains(IntRect(IntPoint(), size())));
332 buffer->zeroFillFrameRect(prevRect);
333 }
334 } 555 }
556 setupHaveDecodedRowCallbacks(useIndex8);
335 557
336 // Update our status to be partially complete. 558 // Update our status to be partially complete.
337 buffer->setStatus(ImageFrame::FramePartial); 559 buffer->setStatus(ImageFrame::FramePartial);
338 560
339 // Reset the alpha pixel tracker for this frame. 561 // Reset the alpha pixel tracker for this frame.
340 m_currentBufferSawAlpha = false; 562 m_currentBufferSawAlpha = false;
341 return true; 563 return true;
342 } 564 }
343 565
566 bool GIFImageDecoder::canDecodeTo(size_t index, ImageFrame::ColorType outputType )
567 {
568 if ((index >= frameCount()) || (m_requestedColorMode == ImageFrame::N32) || failed())
scroggo_chromium 2016/04/29 19:48:15 if (failed()), should this just return false? Othe
569 return (outputType == m_requestedColorMode);
570
571 // Go from one to previous to calculate if Index8 is supported.
572 size_t frameToDecode = index;
573 ImageFrame::ColorType calculatedOutput = ImageFrame::Index8;
574 while (frameToDecode != kNotFound) {
575 ImageFrame* buffer = &m_frameBufferCache[frameToDecode];
576 if (buffer->status() == ImageFrame::FrameComplete) {
577 // In this case, color type from complete frame is kept.
578 calculatedOutput = static_cast<ImageFrame::ColorType>(buffer->getSkB itmap().colorType());
579 break;
580 }
581 const GIFFrameContext* frameContext = m_reader->frameContext(frameToDeco de);
582 updateRequiredPreviousFrame(buffer, *frameContext);
583 if (!isIndex8Applicable(*frameContext, buffer->requiredPreviousFrameInde x())) {
584 calculatedOutput = ImageFrame::N32;
585 break;
586 }
587 frameToDecode = buffer->requiredPreviousFrameIndex();
588 }
589 return (calculatedOutput == outputType);
590 }
591
344 } // namespace blink 592 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698