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

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: cleanup. tableChanged was wrong - do proper check. 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 17 matching lines...) Expand all
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)
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(ImageFrame::Index8)
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);
scroggo_chromium 2015/12/03 21:47:21 It's weird to me that m_colorMode might *not* be N
aleksandar.stojiljkovic 2015/12/04 00:07:35 Yes. m_colorMode holds information about what was
aleksandar.stojiljkovic 2015/12/07 19:24:22 Done.
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. 132 // Initialize the frame if necessary.
129 ImageFrame& buffer = m_frameBufferCache[frameIndex]; 133 ImageFrame& buffer = m_frameBufferCache[frameIndex];
130 if ((buffer.status() == ImageFrame::FrameEmpty) && !initFrameBuffer(frameInd ex)) 134 if (buffer.status() == ImageFrame::FrameEmpty) {
131 return false; 135 if (!initFrameBuffer(frameIndex))
136 return false;
137 // Tricky part here - decoding first row inits frame, and recognized tha t the frame doesnt require
scroggo_chromium 2015/12/03 21:47:22 This is tricky. Maybe it would be better for initF
aleksandar.stojiljkovic 2015/12/04 01:27:27 I actually plan to move init out of looping throug
aleksandar.stojiljkovic 2015/12/07 19:24:22 done (removed), init happens before outputting row
scroggo_chromium 2015/12/08 22:24:51 Yeah, I think that has to be a judgment call. Chan
138 // forced N32 decoding (. initFrameBuffer sets proper haveDecodedRow cal lback, but for this
139 // first row, we need manually to redirect.
140 // It would be much cleaner to move initFrameBuffer before calling haveD ecodedRow, but the
141 // intention here is not to change original code path.
142 if (m_colorMode == ImageFrame::Index8 && !m_forceN32Decoding)
scroggo_chromium 2015/12/03 21:47:22 IIUC, if this is true, initFrameBuffer called init
aleksandar.stojiljkovic 2015/12/04 01:27:27 yes, for every row check if initialized then initi
aleksandar.stojiljkovic 2015/12/07 19:24:21 Done.
143 return haveDecodedRowIndex8(frameIndex, rowBegin, width, rowNumber, repeatCount, writeTransparentPixels);
144 }
132 145
133 const size_t transparentPixel = frameContext->transparentPixel(); 146 const size_t transparentPixel = frameContext->transparentPixel();
134 GIFRow::const_iterator rowEnd = rowBegin + (xEnd - xBegin); 147 GIFRow::const_iterator rowEnd = rowBegin + (xEnd - xBegin);
135 ImageFrame::PixelData* currentAddress = buffer.getAddr(xBegin, yBegin); 148 ImageFrame::PixelData* currentAddress = buffer.getAddr(xBegin, yBegin);
136 149
137 // We may or may not need to write transparent pixels to the buffer. 150 // 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 151 // 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 152 // we're writing atop a cleared, fully transparent buffer, it's
140 // unnecessary; but if we're decoding an interlaced gif and 153 // unnecessary; but if we're decoding an interlaced gif and
141 // displaying it "Haeberli"-style, we must write these for passes 154 // displaying it "Haeberli"-style, we must write these for passes
142 // beyond the first, or the initial passes will "show through" the 155 // beyond the first, or the initial passes will "show through" the
143 // later ones. 156 // later ones.
144 // 157 //
145 // The loops below are almost identical. One writes a transparent pixel 158 // The loops below are almost identical. One writes a transparent pixel
146 // and one doesn't based on the value of |writeTransparentPixels|. 159 // and one doesn't based on the value of |writeTransparentPixels|.
147 // The condition check is taken out of the loop to enhance performance. 160 // The condition check is taken out of the loop to enhance performance.
148 // This optimization reduces decoding time by about 15% for a 3MB image. 161 // This optimization reduces decoding time by about 15% for a 3MB image.
149 if (writeTransparentPixels) { 162 if (writeTransparentPixels) {
150 for (; rowBegin != rowEnd; ++rowBegin, ++currentAddress) { 163 for (; rowBegin != rowEnd; ++rowBegin, ++currentAddress) {
151 const size_t sourceValue = *rowBegin; 164 const size_t sourceValue = *rowBegin;
165 // FIXME - potential optimization: extend colorTable to 256 elems, w rite 0
scroggo_chromium 2015/12/03 21:47:21 So this optimization is when the colortable is les
aleksandar.stojiljkovic 2015/12/04 01:27:27 no; i meant that for colortables of e.g. 32 elemen
aleksandar.stojiljkovic 2015/12/07 19:24:22 Done.
166 // in colortable on index transparentPixel so there would be no need to to this
167 // branching bellow. See index8 implementation.
168 // FIXME optimization: do separate branching for when there is no tr ansparentPixel
169 // (value outside colorTable.size())
152 if ((sourceValue != transparentPixel) && (sourceValue < colorTable.s ize())) { 170 if ((sourceValue != transparentPixel) && (sourceValue < colorTable.s ize())) {
153 *currentAddress = colorTableIter[sourceValue]; 171 *currentAddress = colorTableIter[sourceValue];
154 } else { 172 } else {
155 *currentAddress = 0; 173 *currentAddress = 0;
156 m_currentBufferSawAlpha = true; 174 m_currentBufferSawAlpha = true;
157 } 175 }
158 } 176 }
159 } else { 177 } else {
160 for (; rowBegin != rowEnd; ++rowBegin, ++currentAddress) { 178 for (; rowBegin != rowEnd; ++rowBegin, ++currentAddress) {
161 const size_t sourceValue = *rowBegin; 179 const size_t sourceValue = *rowBegin;
162 if ((sourceValue != transparentPixel) && (sourceValue < colorTable.s ize())) 180 if ((sourceValue != transparentPixel) && (sourceValue < colorTable.s ize()))
163 *currentAddress = colorTableIter[sourceValue]; 181 *currentAddress = colorTableIter[sourceValue];
164 else 182 else
165 m_currentBufferSawAlpha = true; 183 m_currentBufferSawAlpha = true;
166 } 184 }
167 } 185 }
168 186
169 // Tell the frame to copy the row data if need be. 187 // Tell the frame to copy the row data if need be.
170 if (repeatCount > 1) 188 if (repeatCount > 1)
171 buffer.copyRowNTimes(xBegin, xEnd, yBegin, yEnd); 189 buffer.copyRowNTimes(xBegin, xEnd, yBegin, yEnd);
172 190
173 buffer.setPixelsChanged(true); 191 buffer.setPixelsChanged(true);
174 return true; 192 return true;
175 } 193 }
176 194
195 bool GIFImageDecoder::haveDecodedRowIndex8(size_t frameIndex, GIFRow::const_iter ator rowBegin, size_t width, size_t rowNumber, unsigned repeatCount, bool writeT ransparentPixels)
scroggo_chromium 2015/12/03 21:47:21 It looks like this is largely the same as haveDeco
aleksandar.stojiljkovic 2015/12/04 01:27:27 Agree, duplication for purpose that reviewer easie
196 {
197 ASSERT(m_colorMode == ImageFrame::Index8 && !m_forceN32Decoding);
198 const GIFFrameContext* frameContext = m_reader->frameContext(frameIndex);
199 // The pixel data and coordinates supplied to us are relative to the frame's
200 // origin within the entire image size, i.e.
201 // (frameContext->xOffset, frameContext->yOffset). There is no guarantee
202 // that width == (size().width() - frameContext->xOffset), so
203 // we must ensure we don't run off the end of either the source data or the
204 // row's X-coordinates.
205 const int xBegin = frameContext->xOffset();
206 const int yBegin = frameContext->yOffset() + rowNumber;
207 const int xEnd = std::min(static_cast<int>(frameContext->xOffset() + width), size().width());
208 const int yEnd = std::min(static_cast<int>(frameContext->yOffset() + rowNumb er + repeatCount), size().height());
209 if (!width || (xBegin < 0) || (yBegin < 0) || (xEnd <= xBegin) || (yEnd <= y Begin))
210 return true;
211
212 const GIFColorMap::Table& colorTable = frameContext->localColorMap().isDefin ed() ? frameContext->localColorMap().table() : m_reader->globalColorMap().table( );
213
214 if (colorTable.isEmpty())
215 return true;
216
217
218 // Initialize the frame if necessary.
219 ImageFrame& buffer = m_frameBufferCache[frameIndex];
220 if (buffer.status() == ImageFrame::FrameEmpty) {
221 if (!initFrameBufferIndex8(frameIndex))
222 return false;
223 // Tricky part here - decoding first row inits frame, and recognised tha t the frame requires
224 // N32 decoding. initFrameBuffer sets proper haveDecodedRow callback, bu t for this
225 // first row, we need manually to redirect.
226 // It would be much cleaner to move initFrameBuffer before calling haveD ecodedRow, but the
227 // intention here is not to change original code path.
228 if (m_forceN32Decoding)
229 return haveDecodedRowN32(frameIndex, rowBegin, width, rowNumber, rep eatCount, writeTransparentPixels);
230 }
231
232 const size_t transparentPixel = frameContext->transparentPixel();
233 GIFRow::const_iterator rowEnd = rowBegin + (xEnd - xBegin);
234 ImageFrame::PixelData8* currentAddress = buffer.getAddr8(xBegin, yBegin);
235
236 bool opaque = true;
237 if (transparentPixel < colorTable.size()) {
238 // writeTransparentPixels is writing without check, suitable for paralle l uint32_t write later.
239 writeTransparentPixels = writeTransparentPixels || buffer.requiredPrevio usFrameIndex() == kNotFound;
240 if (writeTransparentPixels) {
241 for (; rowBegin != rowEnd;) {
242 opaque = opaque && (*rowBegin ^ transparentPixel);
243 *currentAddress++ = *rowBegin++;
244 }
245 } else {
246 for (; rowBegin != rowEnd; ++rowBegin, ++currentAddress) {
247 size_t index = *rowBegin;
248 if (index == transparentPixel) {
249 opaque = false;
scroggo_chromium 2015/12/03 21:47:22 Why do we not want to put index into currentAddres
aleksandar.stojiljkovic 2015/12/04 01:27:26 It is faster this way (at least for examples I use
250 } else {
251 *currentAddress = index;
252 }
253 }
254 }
255 } else {
256 // No transparency to deal with.
257 for (; rowBegin != rowEnd;)
258 *currentAddress++ = *rowBegin++;
259 }
260
261 m_currentBufferSawAlpha = !opaque;
262
263 // Tell the frame to copy the row data if specified.
264 if (repeatCount > 1) {
265 const int rowBytes = (xEnd - xBegin) * sizeof(uint8_t);
266 const ImageFrame::PixelData8* const startAddr = buffer.getAddr8(xBegin, yBegin);
267 for (int destY = yBegin + 1; destY < yEnd; ++destY)
268 memcpy(buffer.getAddr8(xBegin, destY), startAddr, rowBytes);
269 }
270
271 buffer.setPixelsChanged(true);
272 return true;
273 }
274
177 bool GIFImageDecoder::parseCompleted() const 275 bool GIFImageDecoder::parseCompleted() const
178 { 276 {
179 return m_reader && m_reader->parseCompleted(); 277 return m_reader && m_reader->parseCompleted();
180 } 278 }
181 279
182 bool GIFImageDecoder::frameComplete(size_t frameIndex) 280 bool GIFImageDecoder::frameComplete(size_t frameIndex)
183 { 281 {
184 // Initialize the frame if necessary. Some GIFs insert do-nothing frames, 282 // Initialize the frame if necessary. Some GIFs insert do-nothing frames,
185 // in which case we never reach haveDecodedRow() before getting here. 283 // in which case we never reach haveDecodedRow() before getting here.
284 // FIXME do nothing frames for Index8 are probably copy of previous frame.
scroggo_chromium 2015/12/03 21:47:21 What does this mean, and what is the FIXME? (i.e.
aleksandar.stojiljkovic 2015/12/04 01:27:27 All fine now, to be removed.
aleksandar.stojiljkovic 2015/12/07 19:24:22 Done.
186 ImageFrame& buffer = m_frameBufferCache[frameIndex]; 285 ImageFrame& buffer = m_frameBufferCache[frameIndex];
187 if ((buffer.status() == ImageFrame::FrameEmpty) && !initFrameBuffer(frameInd ex)) 286 if ((buffer.status() == ImageFrame::FrameEmpty) && !initFrameBuffer(frameInd ex))
188 return false; // initFrameBuffer() has already called setFailed(). 287 return false; // initFrameBuffer() has already called setFailed().
189 288
190 buffer.setStatus(ImageFrame::FrameComplete); 289 buffer.setStatus(ImageFrame::FrameComplete);
191 290
192 if (!m_currentBufferSawAlpha) { 291 if (!m_currentBufferSawAlpha) {
193 // The whole frame was non-transparent, so it's possible that the entire 292 // The whole frame was non-transparent, so it's possible that the entire
194 // resulting buffer was non-transparent, and we can setHasAlpha(false). 293 // resulting buffer was non-transparent, and we can setHasAlpha(false).
195 if (buffer.originalFrameRect().contains(IntRect(IntPoint(), size()))) { 294 if (buffer.originalFrameRect().contains(IntRect(IntPoint(), size()))) {
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 void GIFImageDecoder::initializeNewFrame(size_t index) 354 void GIFImageDecoder::initializeNewFrame(size_t index)
256 { 355 {
257 ImageFrame* buffer = &m_frameBufferCache[index]; 356 ImageFrame* buffer = &m_frameBufferCache[index];
258 const GIFFrameContext* frameContext = m_reader->frameContext(index); 357 const GIFFrameContext* frameContext = m_reader->frameContext(index);
259 buffer->setOriginalFrameRect(intersection(frameContext->frameRect(), IntRect (IntPoint(), size()))); 358 buffer->setOriginalFrameRect(intersection(frameContext->frameRect(), IntRect (IntPoint(), size())));
260 buffer->setDuration(frameContext->delayTime()); 359 buffer->setDuration(frameContext->delayTime());
261 buffer->setDisposalMethod(frameContext->disposalMethod()); 360 buffer->setDisposalMethod(frameContext->disposalMethod());
262 buffer->setRequiredPreviousFrameIndex(findRequiredPreviousFrame(index, false )); 361 buffer->setRequiredPreviousFrameIndex(findRequiredPreviousFrame(index, false ));
263 } 362 }
264 363
265 void GIFImageDecoder::decode(size_t index) 364 void GIFImageDecoder::decode(size_t index)
scroggo_chromium 2015/12/03 21:47:21 So IIUC, decodeTo (which you added) lets the calle
aleksandar.stojiljkovic 2015/12/04 01:27:27 decodeto wraps decode - decode() is not called dir
aleksandar.stojiljkovic 2015/12/07 19:24:22 Done - removed decodeTo method. Decoding output se
266 { 365 {
366 phaveDecodedRow = (m_colorMode == ImageFrame::Index8 && !m_forceN32Decoding)
367 ? (&GIFImageDecoder::haveDecodedRowIndex8)
368 : (&GIFImageDecoder::haveDecodedRowN32);
267 parse(GIFFrameCountQuery); 369 parse(GIFFrameCountQuery);
268 370
269 if (failed()) 371 if (failed())
270 return; 372 return;
271 373
272 Vector<size_t> framesToDecode; 374 Vector<size_t> framesToDecode;
273 size_t frameToDecode = index; 375 size_t frameToDecode = index;
274 do { 376 do {
275 framesToDecode.append(frameToDecode); 377 framesToDecode.append(frameToDecode);
276 frameToDecode = m_frameBufferCache[frameToDecode].requiredPreviousFrameI ndex(); 378 frameToDecode = m_frameBufferCache[frameToDecode].requiredPreviousFrameI ndex();
277 } while (frameToDecode != kNotFound && m_frameBufferCache[frameToDecode].sta tus() != ImageFrame::FrameComplete); 379 } while (frameToDecode != kNotFound && m_frameBufferCache[frameToDecode].sta tus() != ImageFrame::FrameComplete);
278 380
279 for (auto i = framesToDecode.rbegin(); i != framesToDecode.rend(); ++i) { 381 for (auto i = framesToDecode.rbegin(); i != framesToDecode.rend(); ++i) {
382 bool notSuitableForIndex8(m_forceN32Decoding);
280 if (!m_reader->decode(*i)) { 383 if (!m_reader->decode(*i)) {
scroggo_chromium 2015/12/03 21:47:21 So decode() may now fail for another reason (wrong
aleksandar.stojiljkovic 2015/12/04 01:27:27 it could fail for previous reasons (setFailed() ca
aleksandar.stojiljkovic 2015/12/22 15:19:55 Done. This code removed.
281 setFailed(); 384 // Decoder asks to switch color mode as Index8 is not applicable. Tr y to decode using N32.
282 return; 385 // This happens only when transparent pixels showing previous frames or offsets are detected
386 // and table is changed.
387 if (notSuitableForIndex8 != m_forceN32Decoding) {
scroggo_chromium 2015/12/03 21:47:21 So GIFImageReader::decode modified m_forceN32Decod
aleksandar.stojiljkovic 2015/12/04 01:27:27 Acknowledged.
aleksandar.stojiljkovic 2015/12/04 01:27:27 This relates to that init inside haveDecodedRow an
aleksandar.stojiljkovic 2015/12/22 15:19:55 Done. Simplified and removed m_forceN32Decoding.
388 ASSERT(m_colorMode == ImageFrame::Index8);
389 clearFrameBuffer(*i);
390 // N32 decoding would continue until there is non dependent Inde x8 frame detected, see initFrameBuffer().
391 phaveDecodedRow = &GIFImageDecoder::haveDecodedRowN32;
392 if (!m_reader->decode(*i)) {
393 setFailed();
394 return;
395 }
396 } else {
397 setFailed();
398 return;
399 }
283 } 400 }
284 401
285 // We need more data to continue decoding. 402 // We need more data to continue decoding.
286 if (m_frameBufferCache[*i].status() != ImageFrame::FrameComplete) 403 if (m_frameBufferCache[*i].status() != ImageFrame::FrameComplete)
287 break; 404 break;
288 } 405 }
289 406
290 // It is also a fatal error if all data is received and we have decoded all 407 // It is also a fatal error if all data is received and we have decoded all
291 // frames available but the file is truncated. 408 // frames available but the file is truncated.
292 if (index >= m_frameBufferCache.size() - 1 && isAllDataReceived() && m_reade r && !m_reader->parseCompleted()) 409 if (index >= m_frameBufferCache.size() - 1 && isAllDataReceived() && m_reade r && !m_reader->parseCompleted())
293 setFailed(); 410 setFailed();
294 } 411 }
295 412
413 void GIFImageDecoder::decodeTo(size_t index, ImageFrame::ColorType outputColor)
414 {
415 ASSERT(outputColor == ImageFrame::N32 || outputColor == ImageFrame::Index8);
416 ImageFrame::ColorType c = m_colorMode;
417 m_colorMode = outputColor;
418 decode(index);
419 m_colorMode = c;
420 }
421
422 bool GIFImageDecoder::canDecodeTo(size_t index, ImageFrame::ColorType outputType )
423 {
424 return ((outputType == ImageFrame::N32)
425 || (outputType == ImageFrame::Index8 && !m_forceN32Decoding));
426 }
427
428 void GIFImageDecoder::setForceN32Decoding(bool value)
429 {
430 ASSERT(m_colorMode == ImageFrame::Index8);
431 m_forceN32Decoding = value;
432 phaveDecodedRow = (!value && m_colorMode == ImageFrame::Index8)
433 ? (&GIFImageDecoder::haveDecodedRowIndex8)
434 : (&GIFImageDecoder::haveDecodedRowN32);
435 }
436
296 void GIFImageDecoder::parse(GIFParseQuery query) 437 void GIFImageDecoder::parse(GIFParseQuery query)
297 { 438 {
298 if (failed()) 439 if (failed())
299 return; 440 return;
300 441
301 if (!m_reader) { 442 if (!m_reader) {
302 m_reader = adoptPtr(new GIFImageReader(this)); 443 m_reader = adoptPtr(new GIFImageReader(this));
303 m_reader->setData(m_data); 444 m_reader->setData(m_data);
304 } 445 }
305 446
306 if (!m_reader->parse(query)) 447 if (!m_reader->parse(query))
307 setFailed(); 448 setFailed();
308 } 449 }
309 450
310 bool GIFImageDecoder::initFrameBuffer(size_t frameIndex) 451 bool GIFImageDecoder::initFrameBuffer(size_t frameIndex)
311 { 452 {
453 if (m_colorMode == ImageFrame::Index8) {
454 // Ended up here, since previous frame didn't support Index8 decoding.
455 // Try to switch back to Index( decoding.
456 return initFrameBufferIndex8(frameIndex);
457 }
312 // Initialize the frame rect in our buffer. 458 // Initialize the frame rect in our buffer.
313 ImageFrame* const buffer = &m_frameBufferCache[frameIndex]; 459 ImageFrame* const buffer = &m_frameBufferCache[frameIndex];
314 460
315 size_t requiredPreviousFrameIndex = buffer->requiredPreviousFrameIndex(); 461 size_t requiredPreviousFrameIndex = buffer->requiredPreviousFrameIndex();
316 if (requiredPreviousFrameIndex == kNotFound) { 462 if (requiredPreviousFrameIndex == kNotFound) {
317 // This frame doesn't rely on any previous data. 463 // This frame doesn't rely on any previous data.
318 if (!buffer->setSize(size().width(), size().height())) 464 if (!buffer->setSize(size().width(), size().height()))
319 return setFailed(); 465 return setFailed();
320 } else { 466 } else {
321 const ImageFrame* prevBuffer = &m_frameBufferCache[requiredPreviousFrame Index]; 467 const ImageFrame* prevBuffer = &m_frameBufferCache[requiredPreviousFrame Index];
(...skipping 13 matching lines...) Expand all
335 } 481 }
336 482
337 // Update our status to be partially complete. 483 // Update our status to be partially complete.
338 buffer->setStatus(ImageFrame::FramePartial); 484 buffer->setStatus(ImageFrame::FramePartial);
339 485
340 // Reset the alpha pixel tracker for this frame. 486 // Reset the alpha pixel tracker for this frame.
341 m_currentBufferSawAlpha = false; 487 m_currentBufferSawAlpha = false;
342 return true; 488 return true;
343 } 489 }
344 490
491 static bool framesUseSameColorTable(const GIFFrameContext *frame1, const GIFFram eContext *frame2)
scroggo_chromium 2015/12/03 21:47:22 I think these should be const references?
aleksandar.stojiljkovic 2015/12/04 01:27:27 Acknowledged.
aleksandar.stojiljkovic 2015/12/07 19:24:22 Done.
492 {
493 if (frame1->localColorMap().isDefined() ^ frame2->localColorMap().isDefined( ))
494 return false;
495 if (!frame1->localColorMap().isDefined()) {
496 // They both use global ColorMap.
scroggo_chromium 2015/12/03 21:47:22 ASSERT(!frame2->localColorMap().isDefined())?
aleksandar.stojiljkovic 2015/12/04 01:27:27 previous ^ should be resolving it, but it is compl
aleksandar.stojiljkovic 2015/12/07 19:24:22 Done.
497 return (frame1->transparentPixel() == frame1->transparentPixel());
498 }
499 if (frame1->localColorMap().getPosition() == frame2->localColorMap().getPosi tion()) {
scroggo_chromium 2015/12/03 21:47:21 This block of code is tough to follow. I think som
aleksandar.stojiljkovic 2015/12/07 19:24:22 Done.
500 if (frame1->transparentPixel() == frame2->transparentPixel()
501 || (frame1->transparentPixel() >= frame1->localColorMap().table().si ze()
502 && frame2->transparentPixel() >= frame2->localColorMap().table() .size()))
503 return true;
504 }
505 return false;
506 }
507
508 bool GIFImageDecoder::initFrameBufferIndex8(size_t frameIndex)
509 {
510 ASSERT(m_colorMode == ImageFrame::Index8);
511 // Initialize the frame rect in our buffer.
512 ImageFrame* buffer = &m_frameBufferCache[frameIndex];
513
514 const GIFFrameContext* frameContext = m_reader->frameContext(frameIndex);
515 bool isFullScreen = frameContext->frameRect().contains(IntRect(IntPoint(), s ize()));
516 const GIFColorMap::Table& colorTable = frameContext->localColorMap().isDefin ed()
517 ? frameContext->localColorMap().table() : m_reader->globalColorMap().tab le();
518
519 // Checking frameContext->transparentPixel() != kNotFound is not precise, si nce
520 // it also needs to include colortable information - if transparent pixels i s outside colortable
521 // there is no transparent pixel.
522 // e.g. Colortable in some of the GIFs is having 40 elements andtransparentP ixel set to 0xFF.
523 // This is changed here only to affect Index8 and the intention is to keep t he N32 code unchanged.
scroggo_chromium 2015/12/03 21:47:21 Are you saying that updating required previous fra
aleksandar.stojiljkovic 2015/12/04 01:27:27 Originally didn't want to change it, tried to deli
524 bool opaque = frameContext->transparentPixel() >= colorTable.size();
525
526 // The same check - if fullscreen and opaque, then previus is not required t o copy - happens in
527 // frameComplete -move it earlier so it affects also current run (not only starting from next loop).
528 if (isFullScreen && opaque)
529 buffer->setRequiredPreviousFrameIndex(kNotFound);
530
531 size_t requiredPreviousFrameIndex = buffer->requiredPreviousFrameIndex();
532
533 if (requiredPreviousFrameIndex == kNotFound) {
534 // This frame doesn't rely on any previous data.
535 // Reset not suitable and table changed information as this is full new frame.
scroggo_chromium 2015/12/03 21:47:21 What does "Reset not suitable" mean?
aleksandar.stojiljkovic 2015/12/04 01:27:27 m_forceN32Decoding can be reset to false, and resu
aleksandar.stojiljkovic 2015/12/07 19:24:22 Done.
536 // It is OK to switch back from N32 to Index8 if it was originally reque sted.
537 setForceN32Decoding(false);
538 phaveDecodedRow = &GIFImageDecoder::haveDecodedRowIndex8;
539 if (!buffer->setSizeIndex8(size().width(), size().height(), colorTable, frameContext->transparentPixel()))
aleksandar.stojiljkovic 2015/12/04 01:27:27 This call is prefilling it so that all pixels have
540 return setFailed();
541 } else {
542 const ImageFrame* prevBuffer = &m_frameBufferCache[requiredPreviousFrame Index];
543 ASSERT(prevBuffer->status() == ImageFrame::FrameComplete);
544 ASSERT(!isFullScreen || !opaque);
545
546 // Preserve the last frame as the starting state for this frame.
547 // If in Index8 mode, and colorTable is not changed nor setForceN32Decod ing set,
548 // preserve frame same way as for N32.
549 bool useN32 = true;
550 if (!m_forceN32Decoding) {
scroggo_chromium 2015/12/03 21:47:21 Wait, should we reach this method (or get this far
aleksandar.stojiljkovic 2015/12/07 19:24:22 I think it looks more logical now - initFrameBuffe
aleksandar.stojiljkovic 2015/12/22 15:19:55 Done. Simplified and removed m_forceN32Decoding.
551 // If table is changed and in the same time, there is transparency o r following frame
552 // is subrect, cannot do Index8. Otherwise, with the same table, no problem to continue
553 // with Index8 copy of dependent frame as starting point for this fr ame.
554 if (framesUseSameColorTable(frameContext, m_reader->frameContext(req uiredPreviousFrameIndex))) {
555 useN32 = false;
556 if (!buffer->copyBitmapData(*prevBuffer))
557 return setFailed();
558 ASSERT(buffer->getSkBitmap().colorType() == kIndex_8_SkColorType );
559 } else {
560 setForceN32Decoding(true);
561 useN32 = true;
562 }
563 }
564 // For unsupported Index8 and N32, next frame starts as previous frame c opy to N32.
565 if (useN32 && !buffer->copyBitmapData(*prevBuffer, ImageFrame::N32))
566 return setFailed();
567
568 if (prevBuffer->disposalMethod() == ImageFrame::DisposeOverwriteBgcolor) {
569 // We want to clear the previous frame to transparent, without
570 // affecting pixels in the image outside of the frame.
571 const IntRect& prevRect = prevBuffer->originalFrameRect();
572 ASSERT(!prevRect.contains(IntRect(IntPoint(), size())));
573 buffer->zeroFillFrameRect(prevRect);
574 }
575 }
576
577 // Update our status to be partially complete.
578 buffer->setStatus(ImageFrame::FramePartial);
579
580 // Reset the alpha pixel tracker for this frame.
581 m_currentBufferSawAlpha = false;
582 return true;
583 }
345 } // namespace blink 584 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698