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

Side by Side Diff: third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoder.cpp

Issue 2756463003: Remove opaque alpha channel special case (Closed)
Patch Set: Fix gif detecting if a frame claims to have transparency Created 3 years, 9 months 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. 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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698