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 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 |