Chromium Code Reviews| 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& color_behavior, | 44 const ColorBehavior& color_behavior, |
| 45 size_t max_decoded_bytes, | 45 size_t max_decoded_bytes, |
| 46 size_t offset) | 46 size_t offset) |
| 47 : ImageDecoder(alpha_option, color_behavior, max_decoded_bytes), | 47 : ImageDecoder(alpha_option, color_behavior, max_decoded_bytes), |
| 48 offset_(offset), | 48 offset_(offset), |
| 49 current_frame_(0), | 49 current_frame_(0), |
| 50 // It would be logical to default to kAnimationNone, but BitmapImage uses | 50 // It would be logical to default to kAnimationNone, 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 repetition_count_(kAnimationLoopOnce), | 53 repetition_count_(kAnimationLoopOnce), |
| 54 has_alpha_channel_(false), | 54 has_alpha_channel_(false) {} |
| 55 current_buffer_saw_alpha_(false) {} | |
| 56 | 55 |
| 57 PNGImageDecoder::~PNGImageDecoder() {} | 56 PNGImageDecoder::~PNGImageDecoder() {} |
| 58 | 57 |
| 59 bool PNGImageDecoder::SetFailed() { | 58 bool PNGImageDecoder::SetFailed() { |
| 60 reader_.reset(); | 59 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::kMetaData); | 64 Parse(ParseQuery::kMetaData); |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 263 | 262 |
| 264 // Tell libpng to send us rows for interlaced pngs. | 263 // Tell libpng to send us rows for interlaced pngs. |
| 265 if (interlace_type == PNG_INTERLACE_ADAM7) | 264 if (interlace_type == PNG_INTERLACE_ADAM7) |
| 266 png_set_interlace_handling(png); | 265 png_set_interlace_handling(png); |
| 267 | 266 |
| 268 // Update our info now (so we can get color channel info). | 267 // Update our info now (so we can get color channel info). |
| 269 png_read_update_info(png, info); | 268 png_read_update_info(png, info); |
| 270 | 269 |
| 271 int channels = png_get_channels(png, info); | 270 int channels = png_get_channels(png, info); |
| 272 DCHECK(channels == 3 || channels == 4); | 271 DCHECK(channels == 3 || channels == 4); |
| 273 has_alpha_channel_ = (channels == 4); | 272 has_alpha_channel_ = (channels == 4); |
|
scroggo_chromium
2017/05/31 14:27:50
if channels == 3, we know that the image is opaque
cblume
2017/05/31 21:05:29
Just checking -- you aren't pointing this out as s
scroggo_chromium
2017/06/01 12:14:07
I don't want you to change it, but I thought we mi
| |
| 274 } | 273 } |
| 275 | 274 |
| 276 void PNGImageDecoder::RowAvailable(unsigned char* row_buffer, | 275 void PNGImageDecoder::RowAvailable(unsigned char* row_buffer, |
| 277 unsigned row_index, | 276 unsigned row_index, |
| 278 int) { | 277 int) { |
| 279 if (current_frame_ >= frame_buffer_cache_.size()) | 278 if (current_frame_ >= frame_buffer_cache_.size()) |
| 280 return; | 279 return; |
| 281 | 280 |
| 282 ImageFrame& buffer = frame_buffer_cache_[current_frame_]; | 281 ImageFrame& buffer = frame_buffer_cache_[current_frame_]; |
| 283 if (buffer.GetStatus() == ImageFrame::kFrameEmpty) { | 282 if (buffer.GetStatus() == ImageFrame::kFrameEmpty) { |
| 284 png_structp png = reader_->PngPtr(); | 283 png_structp png = reader_->PngPtr(); |
| 285 if (!InitFrameBuffer(current_frame_)) { | 284 if (!InitFrameBuffer(current_frame_)) { |
| 286 longjmp(JMPBUF(png), 1); | 285 longjmp(JMPBUF(png), 1); |
| 287 return; | 286 return; |
| 288 } | 287 } |
| 289 | 288 |
| 290 DCHECK_EQ(ImageFrame::kFramePartial, buffer.GetStatus()); | 289 DCHECK_EQ(ImageFrame::kFramePartial, buffer.GetStatus()); |
| 291 | 290 |
| 292 if (PNG_INTERLACE_ADAM7 == | 291 if (PNG_INTERLACE_ADAM7 == |
| 293 png_get_interlace_type(png, reader_->InfoPtr())) { | 292 png_get_interlace_type(png, reader_->InfoPtr())) { |
| 294 unsigned color_channels = has_alpha_channel_ ? 4 : 3; | 293 unsigned color_channels = has_alpha_channel_ ? 4 : 3; |
| 295 reader_->CreateInterlaceBuffer(color_channels * Size().Area()); | 294 reader_->CreateInterlaceBuffer(color_channels * Size().Area()); |
| 296 if (!reader_->InterlaceBuffer()) { | 295 if (!reader_->InterlaceBuffer()) { |
| 297 longjmp(JMPBUF(png), 1); | 296 longjmp(JMPBUF(png), 1); |
| 298 return; | 297 return; |
| 299 } | 298 } |
| 300 } | 299 } |
| 301 | |
| 302 current_buffer_saw_alpha_ = false; | |
| 303 } | 300 } |
| 304 | 301 |
| 305 const IntRect& frame_rect = buffer.OriginalFrameRect(); | 302 const IntRect& frame_rect = buffer.OriginalFrameRect(); |
| 306 DCHECK(IntRect(IntPoint(), Size()).Contains(frame_rect)); | 303 DCHECK(IntRect(IntPoint(), Size()).Contains(frame_rect)); |
| 307 | 304 |
| 308 /* libpng comments (here to explain what follows). | 305 /* libpng comments (here to explain what follows). |
| 309 * | 306 * |
| 310 * this function is called for every row in the image. If the | 307 * this function is called for every row in the image. If the |
| 311 * image is interlacing, and you turned on the interlace handler, | 308 * image is interlacing, and you turned on the interlace handler, |
| 312 * this function will be called for every row in every pass. | 309 * this function will be called for every row in every pass. |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 380 // where R, G, and/or B are greater than A. The legacy drawing | 377 // where R, G, and/or B are greater than A. The legacy drawing |
| 381 // pipeline does not know how to handle this. | 378 // pipeline does not know how to handle this. |
| 382 if (SkColorSpaceXform* xform = ColorTransform()) { | 379 if (SkColorSpaceXform* xform = ColorTransform()) { |
| 383 SkColorSpaceXform::ColorFormat color_format = | 380 SkColorSpaceXform::ColorFormat color_format = |
| 384 SkColorSpaceXform::kRGBA_8888_ColorFormat; | 381 SkColorSpaceXform::kRGBA_8888_ColorFormat; |
| 385 xform->apply(color_format, dst_row, color_format, src_ptr, width, | 382 xform->apply(color_format, dst_row, color_format, src_ptr, width, |
| 386 kUnpremul_SkAlphaType); | 383 kUnpremul_SkAlphaType); |
| 387 src_ptr = png_bytep(dst_row); | 384 src_ptr = png_bytep(dst_row); |
| 388 } | 385 } |
| 389 | 386 |
| 390 unsigned alpha_mask = 255; | |
| 391 if (frame_buffer_cache_[current_frame_].GetAlphaBlendSource() == | 387 if (frame_buffer_cache_[current_frame_].GetAlphaBlendSource() == |
| 392 ImageFrame::kBlendAtopBgcolor) { | 388 ImageFrame::kBlendAtopBgcolor) { |
| 393 if (buffer.PremultiplyAlpha()) { | 389 if (buffer.PremultiplyAlpha()) { |
| 394 for (auto *dst_pixel = dst_row; dst_pixel < dst_row + width; | 390 for (auto *dst_pixel = dst_row; dst_pixel < dst_row + width; |
| 395 dst_pixel++, src_ptr += 4) { | 391 dst_pixel++, src_ptr += 4) { |
| 396 ImageFrame::SetRGBAPremultiply(dst_pixel, src_ptr[0], src_ptr[1], | 392 ImageFrame::SetRGBAPremultiply(dst_pixel, src_ptr[0], src_ptr[1], |
| 397 src_ptr[2], src_ptr[3]); | 393 src_ptr[2], src_ptr[3]); |
| 398 alpha_mask &= src_ptr[3]; | |
| 399 } | 394 } |
| 400 } else { | 395 } else { |
| 401 for (auto *dst_pixel = dst_row; dst_pixel < dst_row + width; | 396 for (auto *dst_pixel = dst_row; dst_pixel < dst_row + width; |
| 402 dst_pixel++, src_ptr += 4) { | 397 dst_pixel++, src_ptr += 4) { |
| 403 ImageFrame::SetRGBARaw(dst_pixel, src_ptr[0], src_ptr[1], src_ptr[2], | 398 ImageFrame::SetRGBARaw(dst_pixel, src_ptr[0], src_ptr[1], src_ptr[2], |
| 404 src_ptr[3]); | 399 src_ptr[3]); |
| 405 alpha_mask &= src_ptr[3]; | |
| 406 } | 400 } |
| 407 } | 401 } |
| 408 } else { | 402 } else { |
| 409 // Now, the blend method is ImageFrame::BlendAtopPreviousFrame. Since the | 403 // Now, the blend method is ImageFrame::BlendAtopPreviousFrame. Since the |
| 410 // frame data of the previous frame is copied at InitFrameBuffer, we can | 404 // frame data of the previous frame is copied at InitFrameBuffer, we can |
| 411 // blend the pixel of this frame, stored in |src_ptr|, over the previous | 405 // blend the pixel of this frame, stored in |src_ptr|, over the previous |
| 412 // pixel stored in |dst_pixel|. | 406 // pixel stored in |dst_pixel|. |
| 413 if (buffer.PremultiplyAlpha()) { | 407 if (buffer.PremultiplyAlpha()) { |
| 414 for (auto *dst_pixel = dst_row; dst_pixel < dst_row + width; | 408 for (auto *dst_pixel = dst_row; dst_pixel < dst_row + width; |
| 415 dst_pixel++, src_ptr += 4) { | 409 dst_pixel++, src_ptr += 4) { |
| 416 ImageFrame::BlendRGBAPremultiplied(dst_pixel, src_ptr[0], src_ptr[1], | 410 ImageFrame::BlendRGBAPremultiplied(dst_pixel, src_ptr[0], src_ptr[1], |
| 417 src_ptr[2], src_ptr[3]); | 411 src_ptr[2], src_ptr[3]); |
| 418 alpha_mask &= src_ptr[3]; | |
| 419 } | 412 } |
| 420 } else { | 413 } else { |
| 421 for (auto *dst_pixel = dst_row; dst_pixel < dst_row + width; | 414 for (auto *dst_pixel = dst_row; dst_pixel < dst_row + width; |
| 422 dst_pixel++, src_ptr += 4) { | 415 dst_pixel++, src_ptr += 4) { |
| 423 ImageFrame::BlendRGBARaw(dst_pixel, src_ptr[0], src_ptr[1], | 416 ImageFrame::BlendRGBARaw(dst_pixel, src_ptr[0], src_ptr[1], |
| 424 src_ptr[2], src_ptr[3]); | 417 src_ptr[2], src_ptr[3]); |
| 425 alpha_mask &= src_ptr[3]; | |
| 426 } | 418 } |
| 427 } | 419 } |
| 428 } | 420 } |
| 429 | |
| 430 if (alpha_mask != 255) | |
| 431 current_buffer_saw_alpha_ = true; | |
| 432 | |
| 433 } else { | 421 } else { |
| 434 for (auto *dst_pixel = dst_row; dst_pixel < dst_row + width; | 422 for (auto *dst_pixel = dst_row; dst_pixel < dst_row + width; |
| 435 src_ptr += 3, ++dst_pixel) { | 423 src_ptr += 3, ++dst_pixel) { |
| 436 ImageFrame::SetRGBARaw(dst_pixel, src_ptr[0], src_ptr[1], src_ptr[2], | 424 ImageFrame::SetRGBARaw(dst_pixel, src_ptr[0], src_ptr[1], src_ptr[2], |
| 437 255); | 425 255); |
| 438 } | 426 } |
| 439 | 427 |
| 440 // We'll apply the color space xform to opaque pixels after they have been | 428 // We'll apply the color space xform to opaque pixels after they have been |
| 441 // written to the ImageFrame, purely because SkColorSpaceXform supports | 429 // written to the ImageFrame, purely because SkColorSpaceXform supports |
| 442 // RGBA (and not RGB). | 430 // RGBA (and not RGB). |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 455 | 443 |
| 456 if (reader_->InterlaceBuffer()) | 444 if (reader_->InterlaceBuffer()) |
| 457 reader_->ClearInterlaceBuffer(); | 445 reader_->ClearInterlaceBuffer(); |
| 458 | 446 |
| 459 ImageFrame& buffer = frame_buffer_cache_[current_frame_]; | 447 ImageFrame& buffer = frame_buffer_cache_[current_frame_]; |
| 460 if (buffer.GetStatus() == ImageFrame::kFrameEmpty) { | 448 if (buffer.GetStatus() == ImageFrame::kFrameEmpty) { |
| 461 longjmp(JMPBUF(reader_->PngPtr()), 1); | 449 longjmp(JMPBUF(reader_->PngPtr()), 1); |
| 462 return; | 450 return; |
| 463 } | 451 } |
| 464 | 452 |
| 465 if (!current_buffer_saw_alpha_) | |
| 466 CorrectAlphaWhenFrameBufferSawNoAlpha(current_frame_); | |
| 467 | |
| 468 buffer.SetStatus(ImageFrame::kFrameComplete); | 453 buffer.SetStatus(ImageFrame::kFrameComplete); |
| 469 } | 454 } |
| 470 | 455 |
| 471 bool PNGImageDecoder::FrameIsCompleteAtIndex(size_t index) const { | 456 bool PNGImageDecoder::FrameIsCompleteAtIndex(size_t index) const { |
| 472 if (!IsDecodedSizeAvailable()) | 457 if (!IsDecodedSizeAvailable()) |
| 473 return false; | 458 return false; |
| 474 | 459 |
| 475 DCHECK(!Failed() && reader_); | 460 DCHECK(!Failed() && reader_); |
| 476 | 461 |
| 477 // For non-animated images, return whether the status of the frame is | 462 // For non-animated images, return whether the status of the frame is |
| 478 // ImageFrame::FrameComplete with ImageDecoder::FrameIsCompleteAtIndex. | 463 // ImageFrame::FrameComplete with ImageDecoder::FrameIsCompleteAtIndex. |
| 479 // This matches the behavior of WEBPImageDecoder. | 464 // This matches the behavior of WEBPImageDecoder. |
| 480 if (reader_->ParseCompleted() && reader_->FrameCount() == 1) | 465 if (reader_->ParseCompleted() && reader_->FrameCount() == 1) |
| 481 return ImageDecoder::FrameIsCompleteAtIndex(index); | 466 return ImageDecoder::FrameIsCompleteAtIndex(index); |
| 482 | 467 |
| 483 return reader_->FrameIsReceivedAtIndex(index); | 468 return reader_->FrameIsReceivedAtIndex(index); |
| 484 } | 469 } |
| 485 | 470 |
| 486 float PNGImageDecoder::FrameDurationAtIndex(size_t index) const { | 471 float PNGImageDecoder::FrameDurationAtIndex(size_t index) const { |
| 487 if (index < frame_buffer_cache_.size()) | 472 if (index < frame_buffer_cache_.size()) |
| 488 return frame_buffer_cache_[index].Duration(); | 473 return frame_buffer_cache_[index].Duration(); |
| 489 return 0; | 474 return 0; |
| 490 } | 475 } |
| 491 | 476 |
| 492 } // namespace blink | 477 } // namespace blink |
| OLD | NEW |