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 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
44 const ColorBehavior& colorBehavior, | 44 const ColorBehavior& colorBehavior, |
45 size_t maxDecodedBytes, | 45 size_t maxDecodedBytes, |
46 size_t offset) | 46 size_t offset) |
47 : ImageDecoder(alphaOption, colorBehavior, maxDecodedBytes), | 47 : ImageDecoder(alphaOption, colorBehavior, maxDecodedBytes), |
48 m_offset(offset), | 48 m_offset(offset), |
49 m_currentFrame(0), | 49 m_currentFrame(0), |
50 // It would be logical to default to cAnimationNone, but BitmapImage uses | 50 // It would be logical to default to cAnimationNone, but BitmapImage uses |
51 // that as a signal to never check again, meaning the actual count will | 51 // that as a signal to never check again, meaning the actual count will |
52 // never be respected. | 52 // never be respected. |
53 m_repetitionCount(cAnimationLoopOnce), | 53 m_repetitionCount(cAnimationLoopOnce), |
54 m_hasAlphaChannel(false), | 54 m_hasAlphaChannel(false) {} |
55 m_currentBufferSawAlpha(false) {} | |
56 | 55 |
57 PNGImageDecoder::~PNGImageDecoder() {} | 56 PNGImageDecoder::~PNGImageDecoder() {} |
58 | 57 |
59 bool PNGImageDecoder::setFailed() { | 58 bool PNGImageDecoder::setFailed() { |
60 m_reader.reset(); | 59 m_reader.reset(); |
61 return ImageDecoder::setFailed(); | 60 return ImageDecoder::setFailed(); |
62 } | 61 } |
63 | 62 |
64 size_t PNGImageDecoder::decodeFrameCount() { | 63 size_t PNGImageDecoder::decodeFrameCount() { |
65 parse(ParseQuery::MetaData); | 64 parse(ParseQuery::MetaData); |
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
293 | 292 |
294 if (PNG_INTERLACE_ADAM7 == | 293 if (PNG_INTERLACE_ADAM7 == |
295 png_get_interlace_type(png, m_reader->infoPtr())) { | 294 png_get_interlace_type(png, m_reader->infoPtr())) { |
296 unsigned colorChannels = m_hasAlphaChannel ? 4 : 3; | 295 unsigned colorChannels = m_hasAlphaChannel ? 4 : 3; |
297 m_reader->createInterlaceBuffer(colorChannels * size().area()); | 296 m_reader->createInterlaceBuffer(colorChannels * size().area()); |
298 if (!m_reader->interlaceBuffer()) { | 297 if (!m_reader->interlaceBuffer()) { |
299 longjmp(JMPBUF(png), 1); | 298 longjmp(JMPBUF(png), 1); |
300 return; | 299 return; |
301 } | 300 } |
302 } | 301 } |
303 | |
304 m_currentBufferSawAlpha = false; | |
305 } | 302 } |
306 | 303 |
307 const IntRect& frameRect = buffer.originalFrameRect(); | 304 const IntRect& frameRect = buffer.originalFrameRect(); |
308 DCHECK(IntRect(IntPoint(), size()).contains(frameRect)); | 305 DCHECK(IntRect(IntPoint(), size()).contains(frameRect)); |
309 | 306 |
310 /* libpng comments (here to explain what follows). | 307 /* libpng comments (here to explain what follows). |
311 * | 308 * |
312 * this function is called for every row in the image. If the | 309 * this function is called for every row in the image. If the |
313 * image is interlacing, and you turned on the interlace handler, | 310 * image is interlacing, and you turned on the interlace handler, |
314 * this function will be called for every row in every pass. | 311 * this function will be called for every row in every pass. |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
382 // where R, G, and/or B are greater than A. The legacy drawing | 379 // where R, G, and/or B are greater than A. The legacy drawing |
383 // pipeline does not know how to handle this. | 380 // pipeline does not know how to handle this. |
384 if (SkColorSpaceXform* xform = colorTransform()) { | 381 if (SkColorSpaceXform* xform = colorTransform()) { |
385 SkColorSpaceXform::ColorFormat colorFormat = | 382 SkColorSpaceXform::ColorFormat colorFormat = |
386 SkColorSpaceXform::kRGBA_8888_ColorFormat; | 383 SkColorSpaceXform::kRGBA_8888_ColorFormat; |
387 xform->apply(colorFormat, dstRow, colorFormat, srcPtr, size().width(), | 384 xform->apply(colorFormat, dstRow, colorFormat, srcPtr, size().width(), |
388 kUnpremul_SkAlphaType); | 385 kUnpremul_SkAlphaType); |
389 srcPtr = png_bytep(dstRow); | 386 srcPtr = png_bytep(dstRow); |
390 } | 387 } |
391 | 388 |
392 unsigned alphaMask = 255; | |
393 if (m_frameBufferCache[m_currentFrame].getAlphaBlendSource() == | 389 if (m_frameBufferCache[m_currentFrame].getAlphaBlendSource() == |
394 ImageFrame::BlendAtopBgcolor) { | 390 ImageFrame::BlendAtopBgcolor) { |
395 if (buffer.premultiplyAlpha()) { | 391 if (buffer.premultiplyAlpha()) { |
396 for (auto *dstPixel = dstRow; dstPixel < dstRow + width; | 392 for (auto *dstPixel = dstRow; dstPixel < dstRow + width; |
397 dstPixel++, srcPtr += 4) { | 393 dstPixel++, srcPtr += 4) { |
398 buffer.setRGBAPremultiply(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], | 394 buffer.setRGBAPremultiply(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], |
399 srcPtr[3]); | 395 srcPtr[3]); |
400 alphaMask &= srcPtr[3]; | |
401 } | 396 } |
402 } else { | 397 } else { |
403 for (auto *dstPixel = dstRow; dstPixel < dstRow + width; | 398 for (auto *dstPixel = dstRow; dstPixel < dstRow + width; |
404 dstPixel++, srcPtr += 4) { | 399 dstPixel++, srcPtr += 4) { |
405 buffer.setRGBARaw(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], | 400 buffer.setRGBARaw(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], |
406 srcPtr[3]); | 401 srcPtr[3]); |
407 alphaMask &= srcPtr[3]; | |
408 } | 402 } |
409 } | 403 } |
410 } else { | 404 } else { |
411 // Now, the blend method is ImageFrame::BlendAtopPreviousFrame. Since the | 405 // Now, the blend method is ImageFrame::BlendAtopPreviousFrame. Since the |
412 // frame data of the previous frame is copied at initFrameBuffer, we can | 406 // frame data of the previous frame is copied at initFrameBuffer, we can |
413 // blend the pixel of this frame, stored in |srcPtr|, over the previous | 407 // blend the pixel of this frame, stored in |srcPtr|, over the previous |
414 // pixel stored in |dstPixel|. | 408 // pixel stored in |dstPixel|. |
415 if (buffer.premultiplyAlpha()) { | 409 if (buffer.premultiplyAlpha()) { |
416 for (auto *dstPixel = dstRow; dstPixel < dstRow + width; | 410 for (auto *dstPixel = dstRow; dstPixel < dstRow + width; |
417 dstPixel++, srcPtr += 4) { | 411 dstPixel++, srcPtr += 4) { |
418 buffer.blendRGBAPremultiplied(dstPixel, srcPtr[0], srcPtr[1], | 412 buffer.blendRGBAPremultiplied(dstPixel, srcPtr[0], srcPtr[1], |
419 srcPtr[2], srcPtr[3]); | 413 srcPtr[2], srcPtr[3]); |
420 alphaMask &= srcPtr[3]; | |
421 } | 414 } |
422 } else { | 415 } else { |
423 for (auto *dstPixel = dstRow; dstPixel < dstRow + width; | 416 for (auto *dstPixel = dstRow; dstPixel < dstRow + width; |
424 dstPixel++, srcPtr += 4) { | 417 dstPixel++, srcPtr += 4) { |
425 buffer.blendRGBARaw(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], | 418 buffer.blendRGBARaw(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], |
426 srcPtr[3]); | 419 srcPtr[3]); |
427 alphaMask &= srcPtr[3]; | |
428 } | 420 } |
429 } | 421 } |
430 } | 422 } |
431 | |
432 if (alphaMask != 255) | |
433 m_currentBufferSawAlpha = true; | |
434 | |
435 } else { | 423 } else { |
436 for (auto *dstPixel = dstRow; dstPixel < dstRow + width; | 424 for (auto *dstPixel = dstRow; dstPixel < dstRow + width; |
437 srcPtr += 3, ++dstPixel) { | 425 srcPtr += 3, ++dstPixel) { |
438 buffer.setRGBARaw(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], 255); | 426 buffer.setRGBARaw(dstPixel, srcPtr[0], srcPtr[1], srcPtr[2], 255); |
439 } | 427 } |
440 | 428 |
441 // We'll apply the color space xform to opaque pixels after they have been | 429 // We'll apply the color space xform to opaque pixels after they have been |
442 // written to the ImageFrame, purely because SkColorSpaceXform supports | 430 // written to the ImageFrame, purely because SkColorSpaceXform supports |
443 // RGBA (and not RGB). | 431 // RGBA (and not RGB). |
444 if (SkColorSpaceXform* xform = colorTransform()) { | 432 if (SkColorSpaceXform* xform = colorTransform()) { |
(...skipping 11 matching lines...) Expand all Loading... |
456 | 444 |
457 if (m_reader->interlaceBuffer()) | 445 if (m_reader->interlaceBuffer()) |
458 m_reader->clearInterlaceBuffer(); | 446 m_reader->clearInterlaceBuffer(); |
459 | 447 |
460 ImageFrame& buffer = m_frameBufferCache[m_currentFrame]; | 448 ImageFrame& buffer = m_frameBufferCache[m_currentFrame]; |
461 if (buffer.getStatus() == ImageFrame::FrameEmpty) { | 449 if (buffer.getStatus() == ImageFrame::FrameEmpty) { |
462 longjmp(JMPBUF(m_reader->pngPtr()), 1); | 450 longjmp(JMPBUF(m_reader->pngPtr()), 1); |
463 return; | 451 return; |
464 } | 452 } |
465 | 453 |
466 if (!m_currentBufferSawAlpha) | |
467 correctAlphaWhenFrameBufferSawNoAlpha(m_currentFrame); | |
468 | |
469 buffer.setStatus(ImageFrame::FrameComplete); | 454 buffer.setStatus(ImageFrame::FrameComplete); |
470 } | 455 } |
471 | 456 |
472 bool PNGImageDecoder::frameIsCompleteAtIndex(size_t index) const { | 457 bool PNGImageDecoder::frameIsCompleteAtIndex(size_t index) const { |
473 if (!isDecodedSizeAvailable()) | 458 if (!isDecodedSizeAvailable()) |
474 return false; | 459 return false; |
475 | 460 |
476 DCHECK(!failed() && m_reader); | 461 DCHECK(!failed() && m_reader); |
477 | 462 |
478 // For non-animated images, return whether the status of the frame is | 463 // For non-animated images, return whether the status of the frame is |
479 // ImageFrame::FrameComplete with ImageDecoder::frameIsCompleteAtIndex. | 464 // ImageFrame::FrameComplete with ImageDecoder::frameIsCompleteAtIndex. |
480 // This matches the behavior of WEBPImageDecoder. | 465 // This matches the behavior of WEBPImageDecoder. |
481 if (m_reader->parseCompleted() && m_reader->frameCount() == 1) | 466 if (m_reader->parseCompleted() && m_reader->frameCount() == 1) |
482 return ImageDecoder::frameIsCompleteAtIndex(index); | 467 return ImageDecoder::frameIsCompleteAtIndex(index); |
483 | 468 |
484 return m_reader->frameIsReceivedAtIndex(index); | 469 return m_reader->frameIsReceivedAtIndex(index); |
485 } | 470 } |
486 | 471 |
487 float PNGImageDecoder::frameDurationAtIndex(size_t index) const { | 472 float PNGImageDecoder::frameDurationAtIndex(size_t index) const { |
488 if (index < m_frameBufferCache.size()) | 473 if (index < m_frameBufferCache.size()) |
489 return m_frameBufferCache[index].duration(); | 474 return m_frameBufferCache[index].duration(); |
490 return 0; | 475 return 0; |
491 } | 476 } |
492 | 477 |
493 } // namespace blink | 478 } // namespace blink |
OLD | NEW |