OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2006 Apple Computer, Inc. | 2 * Copyright (C) 2006 Apple Computer, Inc. |
3 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. | 3 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. |
4 * | 4 * |
5 * Portions are Copyright (C) 2001 mozilla.org | 5 * Portions are Copyright (C) 2001 mozilla.org |
6 * | 6 * |
7 * Other contributors: | 7 * Other contributors: |
8 * Stuart Parmenter <stuart@mozilla.com> | 8 * Stuart Parmenter <stuart@mozilla.com> |
9 * | 9 * |
10 * This library is free software; you can redistribute it and/or | 10 * This library is free software; you can redistribute it and/or |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 #include "wtf/PtrUtil.h" | 43 #include "wtf/PtrUtil.h" |
44 #include <memory> | 44 #include <memory> |
45 | 45 |
46 namespace blink { | 46 namespace blink { |
47 | 47 |
48 PNGImageDecoder::PNGImageDecoder(AlphaOption alphaOption, | 48 PNGImageDecoder::PNGImageDecoder(AlphaOption alphaOption, |
49 ColorSpaceOption colorOptions, | 49 ColorSpaceOption colorOptions, |
50 size_t maxDecodedBytes, | 50 size_t maxDecodedBytes, |
51 size_t offset) | 51 size_t offset) |
52 : ImageDecoder(alphaOption, colorOptions, maxDecodedBytes), | 52 : ImageDecoder(alphaOption, colorOptions, maxDecodedBytes), |
53 m_offset(offset) {} | 53 m_offset(offset), |
| 54 m_currentFrame(0) {} |
54 | 55 |
55 PNGImageDecoder::~PNGImageDecoder() {} | 56 PNGImageDecoder::~PNGImageDecoder() {} |
56 | 57 |
| 58 bool PNGImageDecoder::frameIsCompleteAtIndex(size_t index) const { |
| 59 if (!m_reader || failed()) |
| 60 return false; |
| 61 if (m_frameBufferCache.size() <= 1) |
| 62 return ImageDecoder::frameIsCompleteAtIndex(index); |
| 63 bool frameIsLoadedAtIndex = index < m_frameBufferCache.size(); |
| 64 return frameIsLoadedAtIndex; |
| 65 } |
| 66 |
| 67 float PNGImageDecoder::frameDurationAtIndex(size_t index) const { |
| 68 return (index < m_frameBufferCache.size()) |
| 69 ? m_frameBufferCache[index].duration() |
| 70 : 0; |
| 71 } |
| 72 |
| 73 int PNGImageDecoder::repetitionCount() const { |
| 74 return (!m_reader || failed()) ? cAnimationNone : m_reader->repetitionCount(); |
| 75 } |
| 76 |
| 77 size_t PNGImageDecoder::clearCacheExceptFrame(size_t clearExceptFrame) { |
| 78 if (clearExceptFrame >= m_frameBufferCache.size() || |
| 79 m_frameBufferCache.size() <= 1) |
| 80 return 0; |
| 81 |
| 82 size_t prevFrame = clearExceptFrame; |
| 83 if (m_frameBufferCache[prevFrame].getDisposalMethod() == |
| 84 ImageFrame::DisposeOverwritePrevious) |
| 85 prevFrame = m_frameBufferCache[prevFrame].requiredPreviousFrameIndex(); |
| 86 |
| 87 while (clearExceptFrame != kNotFound && |
| 88 m_frameBufferCache[clearExceptFrame].getStatus() != |
| 89 ImageFrame::FrameComplete) { |
| 90 clearExceptFrame = |
| 91 m_frameBufferCache[clearExceptFrame].requiredPreviousFrameIndex(); |
| 92 } |
| 93 |
| 94 size_t frameBytesCleared = 0; |
| 95 for (size_t i = 0; i < m_frameBufferCache.size(); ++i) { |
| 96 if (i != prevFrame && i != clearExceptFrame) { |
| 97 frameBytesCleared += frameBytesAtIndex(i); |
| 98 clearFrameBuffer(i); |
| 99 } |
| 100 } |
| 101 return frameBytesCleared; |
| 102 } |
| 103 |
57 inline float pngFixedToFloat(png_fixed_point x) { | 104 inline float pngFixedToFloat(png_fixed_point x) { |
58 return ((float)x) * 0.00001f; | 105 return ((float)x) * 0.00001f; |
59 } | 106 } |
60 | 107 |
61 inline sk_sp<SkColorSpace> readColorSpace(png_structp png, png_infop info) { | 108 inline sk_sp<SkColorSpace> readColorSpace(png_structp png, png_infop info) { |
62 if (png_get_valid(png, info, PNG_INFO_sRGB)) { | 109 if (png_get_valid(png, info, PNG_INFO_sRGB)) { |
63 return SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named); | 110 return SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named); |
64 } | 111 } |
65 | 112 |
66 png_charp name = nullptr; | 113 png_charp name = nullptr; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
104 // However, the current behavior matches Safari and Firefox. | 151 // However, the current behavior matches Safari and Firefox. |
105 } | 152 } |
106 } | 153 } |
107 | 154 |
108 return nullptr; | 155 return nullptr; |
109 } | 156 } |
110 | 157 |
111 void PNGImageDecoder::headerAvailable() { | 158 void PNGImageDecoder::headerAvailable() { |
112 png_structp png = m_reader->pngPtr(); | 159 png_structp png = m_reader->pngPtr(); |
113 png_infop info = m_reader->infoPtr(); | 160 png_infop info = m_reader->infoPtr(); |
114 png_uint_32 width = png_get_image_width(png, info); | 161 png_uint_32 width, height; |
115 png_uint_32 height = png_get_image_height(png, info); | |
116 | |
117 // Protect against large PNGs. See http://bugzil.la/251381 for more details. | |
118 const unsigned long maxPNGSize = 1000000UL; | |
119 if (width > maxPNGSize || height > maxPNGSize) { | |
120 longjmp(JMPBUF(png), 1); | |
121 return; | |
122 } | |
123 | |
124 // Set the image size now that the image header is available. | |
125 if (!setSize(width, height)) { | |
126 longjmp(JMPBUF(png), 1); | |
127 return; | |
128 } | |
129 | |
130 int bitDepth, colorType, interlaceType, compressionType, filterType, channels; | 162 int bitDepth, colorType, interlaceType, compressionType, filterType, channels; |
131 png_get_IHDR(png, info, &width, &height, &bitDepth, &colorType, | 163 png_get_IHDR(png, info, &width, &height, &bitDepth, &colorType, |
132 &interlaceType, &compressionType, &filterType); | 164 &interlaceType, &compressionType, &filterType); |
133 | 165 |
134 // The options we set here match what Mozilla does. | 166 // The options we set here match what Mozilla does. |
135 | 167 |
136 // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA. | 168 // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA. |
137 if (colorType == PNG_COLOR_TYPE_PALETTE || | 169 if (colorType == PNG_COLOR_TYPE_PALETTE || |
138 (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8)) | 170 (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8)) |
139 png_set_expand(png); | 171 png_set_expand(png); |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
193 // Tell libpng to send us rows for interlaced pngs. | 225 // Tell libpng to send us rows for interlaced pngs. |
194 if (interlaceType == PNG_INTERLACE_ADAM7) | 226 if (interlaceType == PNG_INTERLACE_ADAM7) |
195 png_set_interlace_handling(png); | 227 png_set_interlace_handling(png); |
196 | 228 |
197 // Update our info now. | 229 // Update our info now. |
198 png_read_update_info(png, info); | 230 png_read_update_info(png, info); |
199 channels = png_get_channels(png, info); | 231 channels = png_get_channels(png, info); |
200 ASSERT(channels == 3 || channels == 4); | 232 ASSERT(channels == 3 || channels == 4); |
201 | 233 |
202 m_reader->setHasAlpha(channels == 4); | 234 m_reader->setHasAlpha(channels == 4); |
203 | |
204 if (m_reader->decodingSizeOnly()) { | |
205 // If we only needed the size, halt the reader. | |
206 #if PNG_LIBPNG_VER_MAJOR > 1 || \ | |
207 (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 5) | |
208 // Passing '0' tells png_process_data_pause() not to cache unprocessed data. | |
209 m_reader->setReadOffset(m_reader->currentBufferSize() - | |
210 png_process_data_pause(png, 0)); | |
211 #else | |
212 m_reader->setReadOffset(m_reader->currentBufferSize() - png->buffer_size); | |
213 png->buffer_size = 0; | |
214 #endif | |
215 } | |
216 } | 235 } |
217 | 236 |
218 void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, | 237 void PNGImageDecoder::rowAvailable(unsigned char* rowBuffer, |
219 unsigned rowIndex, | 238 unsigned rowIndex, |
220 int) { | 239 int) { |
221 if (m_frameBufferCache.isEmpty()) | 240 if (m_frameBufferCache.isEmpty()) |
222 return; | 241 return; |
223 | 242 |
224 // Initialize the framebuffer if needed. | 243 // Initialize the framebuffer if needed. |
225 ImageFrame& buffer = m_frameBufferCache[0]; | 244 ImageFrame& buffer = m_frameBufferCache[m_currentFrame]; |
226 if (buffer.getStatus() == ImageFrame::FrameEmpty) { | 245 if (buffer.getStatus() == ImageFrame::FrameEmpty) { |
227 png_structp png = m_reader->pngPtr(); | 246 png_structp png = m_reader->pngPtr(); |
228 if (!buffer.setSizeAndColorSpace(size().width(), size().height(), | 247 if (!buffer.setSizeAndColorSpace(size().width(), size().height(), |
229 colorSpace())) { | 248 colorSpace())) { |
230 longjmp(JMPBUF(png), 1); | 249 longjmp(JMPBUF(png), 1); |
231 return; | 250 return; |
232 } | 251 } |
233 | 252 |
234 unsigned colorChannels = m_reader->hasAlpha() ? 4 : 3; | 253 unsigned colorChannels = m_reader->hasAlpha() ? 4 : 3; |
235 if (PNG_INTERLACE_ADAM7 == | 254 if (PNG_INTERLACE_ADAM7 == |
236 png_get_interlace_type(png, m_reader->infoPtr())) { | 255 png_get_interlace_type(png, m_reader->infoPtr()) || |
237 m_reader->createInterlaceBuffer(colorChannels * size().width() * | 256 m_currentFrame) { |
238 size().height()); | 257 if (!m_reader->interlaceBuffer()) { |
| 258 m_reader->createInterlaceBuffer(colorChannels * size().width() * |
| 259 size().height()); |
| 260 } |
239 if (!m_reader->interlaceBuffer()) { | 261 if (!m_reader->interlaceBuffer()) { |
240 longjmp(JMPBUF(png), 1); | 262 longjmp(JMPBUF(png), 1); |
241 return; | 263 return; |
242 } | 264 } |
243 } | 265 } |
244 | 266 |
245 buffer.setStatus(ImageFrame::FramePartial); | 267 buffer.setStatus(ImageFrame::FramePartial); |
246 buffer.setHasAlpha(false); | 268 buffer.setHasAlpha(false); |
247 | 269 |
248 // For PNGs, the frame always fills the entire image. | 270 if (!initFrameBuffer()) { |
249 buffer.setOriginalFrameRect(IntRect(IntPoint(), size())); | 271 longjmp(JMPBUF(png), 1); |
| 272 return; |
| 273 } |
250 } | 274 } |
251 | 275 |
252 /* libpng comments (here to explain what follows). | 276 /* libpng comments (here to explain what follows). |
253 * | 277 * |
254 * this function is called for every row in the image. If the | 278 * this function is called for every row in the image. If the |
255 * image is interlacing, and you turned on the interlace handler, | 279 * image is interlacing, and you turned on the interlace handler, |
256 * this function will be called for every row in every pass. | 280 * this function will be called for every row in every pass. |
257 * Some of these rows will not be changed from the previous pass. | 281 * Some of these rows will not be changed from the previous pass. |
258 * When the row is not changed, the new_row variable will be NULL. | 282 * When the row is not changed, the new_row variable will be NULL. |
259 * The rows and passes are called in order, so you don't really | 283 * The rows and passes are called in order, so you don't really |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
291 | 315 |
292 bool hasAlpha = m_reader->hasAlpha(); | 316 bool hasAlpha = m_reader->hasAlpha(); |
293 png_bytep row = rowBuffer; | 317 png_bytep row = rowBuffer; |
294 | 318 |
295 if (png_bytep interlaceBuffer = m_reader->interlaceBuffer()) { | 319 if (png_bytep interlaceBuffer = m_reader->interlaceBuffer()) { |
296 unsigned colorChannels = hasAlpha ? 4 : 3; | 320 unsigned colorChannels = hasAlpha ? 4 : 3; |
297 row = interlaceBuffer + (rowIndex * colorChannels * size().width()); | 321 row = interlaceBuffer + (rowIndex * colorChannels * size().width()); |
298 png_progressive_combine_row(m_reader->pngPtr(), row, rowBuffer); | 322 png_progressive_combine_row(m_reader->pngPtr(), row, rowBuffer); |
299 } | 323 } |
300 | 324 |
| 325 // Only do incremental image display for the first frame. |
| 326 if (m_currentFrame) |
| 327 return; |
| 328 |
301 // Write the decoded row pixels to the frame buffer. The repetitive | 329 // Write the decoded row pixels to the frame buffer. The repetitive |
302 // form of the row write loops is for speed. | 330 // form of the row write loops is for speed. |
303 ImageFrame::PixelData* const dstRow = buffer.getAddr(0, y); | 331 ImageFrame::PixelData* const dstRow = buffer.getAddr(0, y); |
304 unsigned alphaMask = 255; | 332 unsigned alphaMask = 255; |
305 int width = size().width(); | 333 int width = size().width(); |
306 | 334 |
307 png_bytep srcPtr = row; | 335 png_bytep srcPtr = row; |
308 if (hasAlpha) { | 336 if (hasAlpha) { |
309 // Here we apply the color space transformation to the dst space. | 337 // Here we apply the color space transformation to the dst space. |
310 // It does not really make sense to transform to a gamma-encoded | 338 // It does not really make sense to transform to a gamma-encoded |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
356 if (alphaMask != 255 && !buffer.hasAlpha()) | 384 if (alphaMask != 255 && !buffer.hasAlpha()) |
357 buffer.setHasAlpha(true); | 385 buffer.setHasAlpha(true); |
358 | 386 |
359 buffer.setPixelsChanged(true); | 387 buffer.setPixelsChanged(true); |
360 } | 388 } |
361 | 389 |
362 void PNGImageDecoder::complete() { | 390 void PNGImageDecoder::complete() { |
363 if (m_frameBufferCache.isEmpty()) | 391 if (m_frameBufferCache.isEmpty()) |
364 return; | 392 return; |
365 | 393 |
366 m_frameBufferCache[0].setStatus(ImageFrame::FrameComplete); | 394 ImageFrame& buffer = m_frameBufferCache[m_currentFrame]; |
367 } | 395 buffer.setStatus(ImageFrame::FrameComplete); |
368 | 396 |
369 inline bool isComplete(const PNGImageDecoder* decoder) { | 397 if (!m_currentFrame) |
370 return decoder->frameIsCompleteAtIndex(0); | 398 return; |
371 } | 399 |
372 | 400 const IntRect& rect = buffer.originalFrameRect(); |
373 void PNGImageDecoder::decode(bool onlySize) { | 401 bool hasAlpha = m_reader->hasAlpha(); |
| 402 unsigned colorChannels = hasAlpha ? 4 : 3; |
| 403 unsigned alphaMask = 255; |
| 404 ImageFrame::AlphaBlendSource blendMethod = buffer.getAlphaBlendSource(); |
| 405 |
| 406 if (blendMethod == ImageFrame::BlendAtopPreviousFrame && !hasAlpha) |
| 407 blendMethod = ImageFrame::BlendAtopBgcolor; |
| 408 |
| 409 png_bytep row = m_reader->interlaceBuffer(); |
| 410 for (int y = rect.y(); y < rect.maxY(); |
| 411 ++y, row += colorChannels * size().width()) { |
| 412 png_bytep srcPtr = row; |
| 413 ImageFrame::PixelData* dstRow = buffer.getAddr(rect.x(), y); |
| 414 if (hasAlpha) { |
| 415 if (SkColorSpaceXform* xform = colorTransform()) { |
| 416 SkColorSpaceXform::ColorFormat colorFormat = |
| 417 SkColorSpaceXform::kRGBA_8888_ColorFormat; |
| 418 xform->apply(colorFormat, srcPtr, colorFormat, srcPtr, rect.width(), |
| 419 kUnpremul_SkAlphaType); |
| 420 } |
| 421 |
| 422 if (blendMethod == ImageFrame::BlendAtopBgcolor) { |
| 423 if (buffer.premultiplyAlpha()) { |
| 424 for (auto *dstPixel = dstRow; dstPixel < dstRow + rect.width(); |
| 425 dstPixel++, srcPtr += 4) { |
| 426 buffer.setRGBAPremultiply(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], |
| 427 srcPtr[3]); |
| 428 alphaMask &= srcPtr[3]; |
| 429 } |
| 430 } else { |
| 431 for (auto *dstPixel = dstRow; dstPixel < dstRow + rect.width(); |
| 432 dstPixel++, srcPtr += 4) { |
| 433 buffer.setRGBARaw(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], |
| 434 srcPtr[3]); |
| 435 alphaMask &= srcPtr[3]; |
| 436 } |
| 437 } |
| 438 } else { |
| 439 if (buffer.premultiplyAlpha()) { |
| 440 for (auto *dstPixel = dstRow; dstPixel < dstRow + rect.width(); |
| 441 dstPixel++, srcPtr += 4) { |
| 442 buffer.overRGBAPremultiply(dstPixel, srcPtr[0], srcPtr[1], |
| 443 srcPtr[2], srcPtr[3]); |
| 444 alphaMask &= srcPtr[3]; |
| 445 } |
| 446 } else { |
| 447 for (auto *dstPixel = dstRow; dstPixel < dstRow + rect.width(); |
| 448 dstPixel++, srcPtr += 4) { |
| 449 buffer.overRGBARaw(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], |
| 450 srcPtr[3]); |
| 451 alphaMask &= srcPtr[3]; |
| 452 } |
| 453 } |
| 454 } |
| 455 } else { |
| 456 for (auto *dstPixel = dstRow; dstPixel < dstRow + rect.width(); |
| 457 dstPixel++, srcPtr += 3) { |
| 458 buffer.setRGBARaw(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], 255); |
| 459 } |
| 460 |
| 461 if (SkColorSpaceXform* xform = colorTransform()) { |
| 462 xform->apply(xformColorFormat(), dstRow, xformColorFormat(), dstRow, |
| 463 rect.width(), kOpaque_SkAlphaType); |
| 464 } |
| 465 } |
| 466 } |
| 467 |
| 468 if (alphaMask == 255) { |
| 469 if (buffer.originalFrameRect().contains(IntRect(IntPoint(), size()))) { |
| 470 buffer.setHasAlpha(false); |
| 471 } else { |
| 472 size_t frameIndex = m_currentFrame; |
| 473 const ImageFrame* prevBuffer = &m_frameBufferCache[--frameIndex]; |
| 474 while (frameIndex && (prevBuffer->getDisposalMethod() == |
| 475 ImageFrame::DisposeOverwritePrevious)) |
| 476 prevBuffer = &m_frameBufferCache[--frameIndex]; |
| 477 if ((prevBuffer->getDisposalMethod() == |
| 478 ImageFrame::DisposeOverwriteBgcolor) && |
| 479 !prevBuffer->hasAlpha() && |
| 480 buffer.originalFrameRect().contains(prevBuffer->originalFrameRect())) |
| 481 buffer.setHasAlpha(false); |
| 482 } |
| 483 } else if (blendMethod == ImageFrame::BlendAtopBgcolor && |
| 484 !buffer.hasAlpha()) { |
| 485 buffer.setHasAlpha(true); |
| 486 } |
| 487 } |
| 488 |
| 489 size_t PNGImageDecoder::decodeFrameCount() { |
| 490 return parse() ? m_reader->imagesCount() : m_frameBufferCache.size(); |
| 491 } |
| 492 |
| 493 void PNGImageDecoder::decode(size_t index) { |
| 494 if (!m_reader || failed()) |
| 495 return; |
| 496 |
| 497 Vector<size_t> framesToDecode; |
| 498 size_t frameToDecode = index; |
| 499 do { |
| 500 framesToDecode.append(frameToDecode); |
| 501 frameToDecode = |
| 502 m_frameBufferCache[frameToDecode].requiredPreviousFrameIndex(); |
| 503 } while (frameToDecode != kNotFound && |
| 504 m_frameBufferCache[frameToDecode].getStatus() != |
| 505 ImageFrame::FrameComplete); |
| 506 |
| 507 for (auto i = framesToDecode.rbegin(); i != framesToDecode.rend(); ++i) { |
| 508 m_currentFrame = *i; |
| 509 if (!m_reader->decode(*m_data, m_currentFrame)) { |
| 510 setFailed(); |
| 511 break; |
| 512 } |
| 513 |
| 514 // We need more data to continue decoding. |
| 515 if (m_frameBufferCache[m_currentFrame].getStatus() != |
| 516 ImageFrame::FrameComplete) |
| 517 break; |
| 518 } |
| 519 } |
| 520 |
| 521 void PNGImageDecoder::initializeNewFrame(size_t index) { |
| 522 ImageFrame* buffer = &m_frameBufferCache[index]; |
| 523 bool frameRectIsOpaque = buffer->getStatus() == ImageFrame::FrameComplete |
| 524 ? !m_reader->hasAlpha() |
| 525 : false; |
| 526 buffer->setRequiredPreviousFrameIndex( |
| 527 findRequiredPreviousFrame(index, frameRectIsOpaque)); |
| 528 const PNGImageReader::FrameInfo* frame = m_reader->frameInfo(index); |
| 529 IntRect frameRect(frame->xOffset, frame->yOffset, frame->width, |
| 530 frame->height); |
| 531 buffer->setOriginalFrameRect( |
| 532 intersection(frameRect, IntRect(IntPoint(), size()))); |
| 533 buffer->setDuration(frame->duration); |
| 534 buffer->setDisposalMethod(frame->dispose == 2 |
| 535 ? ImageFrame::DisposeOverwritePrevious |
| 536 : frame->dispose == 1 |
| 537 ? ImageFrame::DisposeOverwriteBgcolor |
| 538 : ImageFrame::DisposeKeep); |
| 539 buffer->setAlphaBlendSource(frame->blend == 1 |
| 540 ? ImageFrame::BlendAtopPreviousFrame |
| 541 : ImageFrame::BlendAtopBgcolor); |
| 542 } |
| 543 |
| 544 bool PNGImageDecoder::initFrameBuffer() { |
| 545 ImageFrame& buffer = m_frameBufferCache[m_currentFrame]; |
| 546 |
| 547 const size_t requiredPreviousFrameIndex = buffer.requiredPreviousFrameIndex(); |
| 548 if (requiredPreviousFrameIndex == kNotFound) { |
| 549 // This frame doesn't rely on any previous data. |
| 550 buffer.zeroFillPixelData(); |
| 551 if (!m_currentFrame) |
| 552 buffer.setHasAlpha(false); |
| 553 } else { |
| 554 ImageFrame& prevBuffer = m_frameBufferCache[requiredPreviousFrameIndex]; |
| 555 DCHECK(prevBuffer.getStatus() == ImageFrame::FrameComplete); |
| 556 |
| 557 // Preserve the last frame as the starting state for this frame. |
| 558 if (!buffer.takeBitmapDataIfWritable(&prevBuffer)) { |
| 559 if (!buffer.copyBitmapData(prevBuffer)) |
| 560 return setFailed(); |
| 561 } |
| 562 |
| 563 if (prevBuffer.getDisposalMethod() == ImageFrame::DisposeOverwriteBgcolor) { |
| 564 // We want to clear the previous frame to transparent, without |
| 565 // affecting pixels in the image outside of the frame. |
| 566 const IntRect& prevRect = prevBuffer.originalFrameRect(); |
| 567 DCHECK(!prevRect.contains(IntRect(IntPoint(), size()))); |
| 568 buffer.zeroFillFrameRect(prevRect); |
| 569 } |
| 570 } |
| 571 return true; |
| 572 } |
| 573 |
| 574 bool PNGImageDecoder::parse() { |
374 if (failed()) | 575 if (failed()) |
375 return; | 576 return false; |
376 | 577 |
377 if (!m_reader) | 578 if (!m_reader) |
378 m_reader = wrapUnique(new PNGImageReader(this, m_offset)); | 579 m_reader = wrapUnique(new PNGImageReader(this, m_offset)); |
379 | 580 |
380 // If we couldn't decode the image but have received all the data, decoding | 581 // If we couldn't decode the image but have received all the data, decoding |
381 // has failed. | 582 // has failed. |
382 if (!m_reader->decode(*m_data, onlySize) && isAllDataReceived()) | 583 if (!m_reader->parse(*m_data) && isAllDataReceived()) |
383 setFailed(); | 584 setFailed(); |
384 | 585 |
385 // If decoding is done or failed, we don't need the PNGImageReader anymore. | 586 if (failed()) { |
386 if (isComplete(this) || failed()) | |
387 m_reader.reset(); | 587 m_reader.reset(); |
| 588 return false; |
| 589 } |
| 590 return true; |
388 } | 591 } |
389 | 592 |
390 } // namespace blink | 593 } // namespace blink |
OLD | NEW |