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