OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |