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

Unified Diff: third_party/WebKit/Source/platform/image-decoders/png/PNGImageReader.cpp

Issue 2930513004: [WIP] Move ImageDecoders to SkCodec
Patch Set: Adding check for decoder creation Created 3 years, 6 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 side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/platform/image-decoders/png/PNGImageReader.cpp
diff --git a/third_party/WebKit/Source/platform/image-decoders/png/PNGImageReader.cpp b/third_party/WebKit/Source/platform/image-decoders/png/PNGImageReader.cpp
deleted file mode 100644
index 3a3268c73a202c8b843a9633cea6435f451ae2de..0000000000000000000000000000000000000000
--- a/third_party/WebKit/Source/platform/image-decoders/png/PNGImageReader.cpp
+++ /dev/null
@@ -1,690 +0,0 @@
-/*
- * Copyright (C) 2006 Apple Computer, Inc.
- * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
- *
- * Portions are Copyright (C) 2001 mozilla.org
- *
- * Other contributors:
- * Stuart Parmenter <stuart@mozilla.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Alternatively, the contents of this file may be used under the terms
- * of either the Mozilla Public License Version 1.1, found at
- * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
- * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
- * (the "GPL"), in which case the provisions of the MPL or the GPL are
- * applicable instead of those above. If you wish to allow use of your
- * version of this file only under the terms of one of those two
- * licenses (the MPL or the GPL) and not to allow others to use your
- * version of this file under the LGPL, indicate your decision by
- * deletingthe provisions above and replace them with the notice and
- * other provisions required by the MPL or the GPL, as the case may be.
- * If you do not delete the provisions above, a recipient may use your
- * version of this file under any of the LGPL, the MPL or the GPL.
- */
-
-#include "platform/image-decoders/png/PNGImageReader.h"
-
-#include <memory>
-#include "platform/image-decoders/FastSharedBufferReader.h"
-#include "platform/image-decoders/SegmentReader.h"
-#include "platform/image-decoders/png/PNGImageDecoder.h"
-#include "platform/wtf/PtrUtil.h"
-#include "zlib.h"
-
-namespace {
-
-inline blink::PNGImageDecoder* imageDecoder(png_structp png) {
- return static_cast<blink::PNGImageDecoder*>(png_get_progressive_ptr(png));
-}
-
-void PNGAPI pngHeaderAvailable(png_structp png, png_infop) {
- imageDecoder(png)->HeaderAvailable();
-}
-
-void PNGAPI pngRowAvailable(png_structp png,
- png_bytep row,
- png_uint_32 rowIndex,
- int state) {
- imageDecoder(png)->RowAvailable(row, rowIndex, state);
-}
-
-void PNGAPI pngFrameComplete(png_structp png, png_infop) {
- imageDecoder(png)->FrameComplete();
-}
-
-void PNGAPI pngFailed(png_structp png, png_const_charp) {
- longjmp(JMPBUF(png), 1);
-}
-
-} // namespace
-
-namespace blink {
-
-PNGImageReader::PNGImageReader(PNGImageDecoder* decoder, size_t initial_offset)
- : width_(0),
- height_(0),
- decoder_(decoder),
- initial_offset_(initial_offset),
- read_offset_(initial_offset),
- progressive_decode_offset_(0),
- idat_offset_(0),
- idat_is_part_of_animation_(false),
- expect_idats_(true),
- is_animated_(false),
- parsed_signature_(false),
- parsed_ihdr_(false),
- parse_completed_(false),
- reported_frame_count_(0),
- next_sequence_number_(0),
- fctl_needs_dat_chunk_(false),
- ignore_animation_(false) {
- png_ = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, pngFailed, 0);
- info_ = png_create_info_struct(png_);
- png_set_progressive_read_fn(png_, decoder_, nullptr, pngRowAvailable,
- pngFrameComplete);
-}
-
-PNGImageReader::~PNGImageReader() {
- png_destroy_read_struct(png_ ? &png_ : 0, info_ ? &info_ : 0, 0);
- DCHECK(!png_ && !info_);
-}
-
-// This method reads from the FastSharedBufferReader, starting at offset,
-// and returns |length| bytes in the form of a pointer to a const png_byte*.
-// This function is used to make it easy to access data from the reader in a
-// png friendly way, and pass it to libpng for decoding.
-//
-// Pre-conditions before using this:
-// - |reader|.size() >= |read_offset| + |length|
-// - |buffer|.size() >= |length|
-// - |length| <= |kBufferSize|
-//
-// The reason for the last two precondition is that currently the png signature
-// plus IHDR chunk (8B + 25B = 33B) is the largest chunk that is read using this
-// method. If the data is not consecutive, it is stored in |buffer|, which must
-// have the size of (at least) |length|, but there's no need for it to be larger
-// than |kBufferSize|.
-static constexpr size_t kBufferSize = 33;
-const png_byte* ReadAsConstPngBytep(const FastSharedBufferReader& reader,
- size_t read_offset,
- size_t length,
- char* buffer) {
- DCHECK(length <= kBufferSize);
- return reinterpret_cast<const png_byte*>(
- reader.GetConsecutiveData(read_offset, length, buffer));
-}
-
-bool PNGImageReader::ShouldDecodeWithNewPNG(size_t index) const {
- if (!png_)
- return true;
- const bool first_frame_decode_in_progress = progressive_decode_offset_;
- const bool frame_size_matches_ihdr =
- frame_info_[index].frame_rect == IntRect(0, 0, width_, height_);
- if (index)
- return first_frame_decode_in_progress || !frame_size_matches_ihdr;
- return !first_frame_decode_in_progress && !frame_size_matches_ihdr;
-}
-
-// Return false on a fatal error.
-bool PNGImageReader::Decode(SegmentReader& data, size_t index) {
- if (index >= frame_info_.size())
- return true;
-
- const FastSharedBufferReader reader(&data);
-
- if (!is_animated_) {
- if (setjmp(JMPBUF(png_)))
- return false;
- DCHECK_EQ(0u, index);
- progressive_decode_offset_ += ProcessData(
- reader, frame_info_[0].start_offset + progressive_decode_offset_, 0);
- return true;
- }
-
- DCHECK(is_animated_);
-
- const bool decode_with_new_png = ShouldDecodeWithNewPNG(index);
- if (decode_with_new_png) {
- ClearDecodeState(0);
- png_ = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, pngFailed, 0);
- info_ = png_create_info_struct(png_);
- png_set_progressive_read_fn(png_, decoder_, pngHeaderAvailable,
- pngRowAvailable, pngFrameComplete);
- }
-
- if (setjmp(JMPBUF(png_)))
- return false;
-
- if (decode_with_new_png)
- StartFrameDecoding(reader, index);
-
- if (!index && (!FirstFrameFullyReceived() || progressive_decode_offset_)) {
- const bool decoded_entire_frame = ProgressivelyDecodeFirstFrame(reader);
- if (!decoded_entire_frame)
- return true;
- progressive_decode_offset_ = 0;
- } else {
- DecodeFrame(reader, index);
- }
-
- static png_byte iend[12] = {0, 0, 0, 0, 'I', 'E', 'N', 'D', 174, 66, 96, 130};
- png_process_data(png_, info_, iend, 12);
- png_destroy_read_struct(&png_, &info_, 0);
- DCHECK(!png_ && !info_);
-
- return true;
-}
-
-void PNGImageReader::StartFrameDecoding(const FastSharedBufferReader& reader,
- size_t index) {
- // If the frame is the size of the whole image, just re-process all header
- // data up to the first frame.
- const IntRect& frame_rect = frame_info_[index].frame_rect;
- if (frame_rect == IntRect(0, 0, width_, height_)) {
- ProcessData(reader, initial_offset_, idat_offset_);
- return;
- }
-
- // Process the IHDR chunk, but change the width and height so it reflects
- // the frame's width and height. ImageDecoder will apply the x,y offset.
- constexpr size_t kHeaderSize = kBufferSize;
- char read_buffer[kHeaderSize];
- const png_byte* chunk =
- ReadAsConstPngBytep(reader, initial_offset_, kHeaderSize, read_buffer);
- png_byte* header = reinterpret_cast<png_byte*>(read_buffer);
- if (chunk != header)
- memcpy(header, chunk, kHeaderSize);
- png_save_uint_32(header + 16, frame_rect.Width());
- png_save_uint_32(header + 20, frame_rect.Height());
- // IHDR has been modified, so tell libpng to ignore CRC errors.
- png_set_crc_action(png_, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);
- png_process_data(png_, info_, header, kHeaderSize);
-
- // Process the rest of the header chunks.
- ProcessData(reader, initial_offset_ + kHeaderSize,
- idat_offset_ - kHeaderSize);
-}
-
-// Determine if the bytes 4 to 7 of |chunk| indicate that it is a |tag| chunk.
-// - The length of |chunk| must be >= 8
-// - The length of |tag| must be = 4
-static inline bool IsChunk(const png_byte* chunk, const char* tag) {
- return memcmp(chunk + 4, tag, 4) == 0;
-}
-
-bool PNGImageReader::ProgressivelyDecodeFirstFrame(
- const FastSharedBufferReader& reader) {
- size_t offset = frame_info_[0].start_offset;
-
- // Loop while there is enough data to do progressive decoding.
- while (reader.size() >= offset + 8) {
- char read_buffer[8];
- // At the beginning of each loop, the offset is at the start of a chunk.
- const png_byte* chunk = ReadAsConstPngBytep(reader, offset, 8, read_buffer);
- const png_uint_32 length = png_get_uint_32(chunk);
- DCHECK(length <= PNG_UINT_31_MAX);
-
- // When an fcTL or IEND chunk is encountered, the frame data has ended.
- // Return true, since all frame data is decoded.
- if (IsChunk(chunk, "fcTL") || IsChunk(chunk, "IEND"))
- return true;
-
- // If this chunk was already decoded, move on to the next.
- if (progressive_decode_offset_ >= offset + length + 12) {
- offset += length + 12;
- continue;
- }
-
- // Three scenarios are possible here:
- // 1) Some bytes of this chunk were already decoded in a previous call.
- // Continue from there.
- // 2) This is an fdAT chunk. Convert it to an IDAT chunk to decode.
- // 3) This is any other chunk. Pass it to libpng for processing.
- size_t end_offset_chunk = offset + length + 12;
-
- if (progressive_decode_offset_ >= offset + 8) {
- offset = progressive_decode_offset_;
- } else if (IsChunk(chunk, "fdAT")) {
- ProcessFdatChunkAsIdat(length);
- // Skip the sequence number.
- offset += 12;
- } else {
- png_process_data(png_, info_, const_cast<png_byte*>(chunk), 8);
- offset += 8;
- }
-
- size_t bytes_left_in_chunk = end_offset_chunk - offset;
- size_t bytes_decoded = ProcessData(reader, offset, bytes_left_in_chunk);
- progressive_decode_offset_ = offset + bytes_decoded;
- if (bytes_decoded < bytes_left_in_chunk)
- return false;
- offset += bytes_decoded;
- }
-
- return false;
-}
-
-void PNGImageReader::ProcessFdatChunkAsIdat(png_uint_32 fdat_length) {
- // An fdAT chunk is build up as follows:
- // - |length| (4B)
- // - fdAT tag (4B)
- // - sequence number (4B)
- // - frame data (|length| - 4B)
- // - CRC (4B)
- // Thus, to reformat this into an IDAT chunk, do the following:
- // - write |length| - 4 as the new length, since the sequence number
- // must be removed.
- // - change the tag to IDAT.
- // - omit the sequence number from the data part of the chunk.
- png_byte chunk_idat[] = {0, 0, 0, 0, 'I', 'D', 'A', 'T'};
- png_save_uint_32(chunk_idat, fdat_length - 4);
- // The CRC is incorrect when applied to the modified fdAT.
- png_set_crc_action(png_, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);
- png_process_data(png_, info_, chunk_idat, 8);
-}
-
-void PNGImageReader::DecodeFrame(const FastSharedBufferReader& reader,
- size_t index) {
- size_t offset = frame_info_[index].start_offset;
- size_t end_offset = offset + frame_info_[index].byte_length;
- char read_buffer[8];
-
- while (offset < end_offset) {
- const png_byte* chunk = ReadAsConstPngBytep(reader, offset, 8, read_buffer);
- const png_uint_32 length = png_get_uint_32(chunk);
- DCHECK(length <= PNG_UINT_31_MAX);
-
- if (IsChunk(chunk, "fdAT")) {
- ProcessFdatChunkAsIdat(length);
- // The frame data and the CRC span |length| bytes, so skip the
- // sequence number and process |length| bytes to decode the frame.
- ProcessData(reader, offset + 12, length);
- } else {
- png_process_data(png_, info_, const_cast<png_byte*>(chunk), 8);
- ProcessData(reader, offset + 8, length + 4);
- }
-
- offset += 12 + length;
- }
-}
-
-// Compute the CRC and compare to the stored value.
-static bool CheckCrc(const FastSharedBufferReader& reader,
- size_t chunk_start,
- size_t chunk_length) {
- constexpr size_t kSizeNeededForfcTL = 26 + 4;
- char read_buffer[kSizeNeededForfcTL];
- DCHECK(chunk_length + 4 <= kSizeNeededForfcTL);
- const png_byte* chunk = ReadAsConstPngBytep(reader, chunk_start + 4,
- chunk_length + 4, read_buffer);
-
- char crc_buffer[4];
- const png_byte* crc_position = ReadAsConstPngBytep(
- reader, chunk_start + 8 + chunk_length, 4, crc_buffer);
- png_uint_32 crc = png_get_uint_32(crc_position);
- return crc == crc32(crc32(0, Z_NULL, 0), chunk, chunk_length + 4);
-}
-
-bool PNGImageReader::CheckSequenceNumber(const png_byte* position) {
- png_uint_32 sequence = png_get_uint_32(position);
- if (sequence != next_sequence_number_ || sequence > PNG_UINT_31_MAX)
- return false;
-
- ++next_sequence_number_;
- return true;
-}
-
-// Return false if there was a fatal error; true otherwise.
-bool PNGImageReader::Parse(SegmentReader& data, ParseQuery query) {
- if (parse_completed_)
- return true;
-
- const FastSharedBufferReader reader(&data);
-
- if (!ParseSize(reader))
- return false;
-
- if (!decoder_->IsDecodedSizeAvailable())
- return true;
-
- // For non animated images (identified by no acTL chunk before the IDAT),
- // there is no need to continue parsing.
- if (!is_animated_) {
- FrameInfo frame;
- frame.start_offset = read_offset_;
- // This should never be read in this case, but initialize just in case.
- frame.byte_length = kFirstFrameIndicator;
- frame.duration = 0;
- frame.frame_rect = IntRect(0, 0, width_, height_);
- frame.disposal_method = ImageFrame::DisposalMethod::kDisposeKeep;
- frame.alpha_blend = ImageFrame::AlphaBlendSource::kBlendAtopBgcolor;
- DCHECK(frame_info_.IsEmpty());
- frame_info_.push_back(frame);
- parse_completed_ = true;
- return true;
- }
-
- if (query == ParseQuery::kSize)
- return true;
-
- DCHECK_EQ(ParseQuery::kMetaData, query);
- DCHECK(is_animated_);
-
- // Loop over the data and manually register all frames. Nothing is passed to
- // libpng for processing. A frame is registered on the next fcTL chunk or
- // when the IEND chunk is found. This ensures that only complete frames are
- // reported, unless there is an error in the stream.
- char read_buffer[kBufferSize];
- while (reader.size() >= read_offset_ + 8) {
- const png_byte* chunk =
- ReadAsConstPngBytep(reader, read_offset_, 8, read_buffer);
- const size_t length = png_get_uint_32(chunk);
- if (length > PNG_UINT_31_MAX)
- return false;
-
- const bool idat = IsChunk(chunk, "IDAT");
- if (idat && !expect_idats_)
- return false;
-
- const bool fd_at = IsChunk(chunk, "fdAT");
- if (fd_at && expect_idats_)
- return false;
-
- if (fd_at || (idat && idat_is_part_of_animation_)) {
- fctl_needs_dat_chunk_ = false;
- if (!new_frame_.start_offset) {
- // Beginning of a new frame's data.
- new_frame_.start_offset = read_offset_;
-
- if (frame_info_.IsEmpty()) {
- // This is the first frame. Report it immediately so it can be
- // decoded progressively.
- new_frame_.byte_length = kFirstFrameIndicator;
- frame_info_.push_back(new_frame_);
- }
- }
-
- if (fd_at) {
- if (reader.size() < read_offset_ + 8 + 4)
- return true;
- const png_byte* sequence_position =
- ReadAsConstPngBytep(reader, read_offset_ + 8, 4, read_buffer);
- if (!CheckSequenceNumber(sequence_position))
- return false;
- }
-
- } else if (IsChunk(chunk, "fcTL") || IsChunk(chunk, "IEND")) {
- // This marks the end of the previous frame.
- if (new_frame_.start_offset) {
- new_frame_.byte_length = read_offset_ - new_frame_.start_offset;
- if (frame_info_[0].byte_length == kFirstFrameIndicator) {
- frame_info_[0].byte_length = new_frame_.byte_length;
- } else {
- frame_info_.push_back(new_frame_);
- if (IsChunk(chunk, "fcTL")) {
- if (frame_info_.size() >= reported_frame_count_)
- return false;
- } else { // IEND
- if (frame_info_.size() != reported_frame_count_)
- return false;
- }
- }
-
- new_frame_.start_offset = 0;
- }
-
- if (reader.size() < read_offset_ + 12 + length)
- return true;
-
- if (IsChunk(chunk, "IEND")) {
- parse_completed_ = true;
- return true;
- }
-
- if (length != 26 || !CheckCrc(reader, read_offset_, length))
- return false;
-
- chunk =
- ReadAsConstPngBytep(reader, read_offset_ + 8, length, read_buffer);
- if (!ParseFrameInfo(chunk))
- return false;
-
- expect_idats_ = false;
- } else if (IsChunk(chunk, "acTL")) {
- // There should only be one acTL chunk, and it should be before the
- // IDAT chunk.
- return false;
- }
-
- read_offset_ += 12 + length;
- }
- return true;
-}
-
-// If |length| == 0, read until the stream ends. Return number of bytes
-// processed.
-size_t PNGImageReader::ProcessData(const FastSharedBufferReader& reader,
- size_t offset,
- size_t length) {
- const char* segment;
- size_t total_processed_bytes = 0;
- while (reader.size() > offset) {
- size_t segment_length = reader.GetSomeData(segment, offset);
- if (length > 0 && segment_length + total_processed_bytes > length)
- segment_length = length - total_processed_bytes;
-
- png_process_data(png_, info_,
- reinterpret_cast<png_byte*>(const_cast<char*>(segment)),
- segment_length);
- offset += segment_length;
- total_processed_bytes += segment_length;
- if (total_processed_bytes == length)
- return length;
- }
- return total_processed_bytes;
-}
-
-// Process up to the start of the IDAT with libpng.
-// Return false for a fatal error. True otherwise.
-bool PNGImageReader::ParseSize(const FastSharedBufferReader& reader) {
- if (decoder_->IsDecodedSizeAvailable())
- return true;
-
- char read_buffer[kBufferSize];
-
- if (setjmp(JMPBUF(png_)))
- return false;
-
- if (!parsed_signature_) {
- if (reader.size() < read_offset_ + 8)
- return true;
-
- const png_byte* chunk =
- ReadAsConstPngBytep(reader, read_offset_, 8, read_buffer);
- png_process_data(png_, info_, const_cast<png_byte*>(chunk), 8);
- read_offset_ += 8;
- parsed_signature_ = true;
- new_frame_.start_offset = 0;
- }
-
- // Process APNG chunks manually, pass other chunks to libpng.
- for (png_uint_32 length = 0; reader.size() >= read_offset_ + 8;
- read_offset_ += length + 12) {
- const png_byte* chunk =
- ReadAsConstPngBytep(reader, read_offset_, 8, read_buffer);
- length = png_get_uint_32(chunk);
-
- if (IsChunk(chunk, "IDAT")) {
- // Done with header chunks.
- idat_offset_ = read_offset_;
- fctl_needs_dat_chunk_ = false;
- if (ignore_animation_)
- is_animated_ = false;
- if (!is_animated_ || 1 == reported_frame_count_)
- decoder_->SetRepetitionCount(kAnimationNone);
- if (!decoder_->SetSize(width_, height_))
- return false;
- decoder_->SetColorSpace();
- decoder_->HeaderAvailable();
- return true;
- }
-
- // Wait until the entire chunk is available for parsing simplicity.
- if (reader.size() < read_offset_ + length + 12)
- break;
-
- if (IsChunk(chunk, "acTL")) {
- if (ignore_animation_)
- continue;
- if (is_animated_ || length != 8 || !parsed_ihdr_ ||
- !CheckCrc(reader, read_offset_, 8)) {
- ignore_animation_ = true;
- continue;
- }
- chunk =
- ReadAsConstPngBytep(reader, read_offset_ + 8, length, read_buffer);
- reported_frame_count_ = png_get_uint_32(chunk);
- if (!reported_frame_count_ || reported_frame_count_ > PNG_UINT_31_MAX) {
- ignore_animation_ = true;
- continue;
- }
- png_uint_32 repetition_count = png_get_uint_32(chunk + 4);
- if (repetition_count > PNG_UINT_31_MAX) {
- ignore_animation_ = true;
- continue;
- }
- is_animated_ = true;
- decoder_->SetRepetitionCount(static_cast<int>(repetition_count) - 1);
- } else if (IsChunk(chunk, "fcTL")) {
- if (ignore_animation_)
- continue;
- if (length != 26 || !parsed_ihdr_ ||
- !CheckCrc(reader, read_offset_, 26)) {
- ignore_animation_ = true;
- continue;
- }
- chunk =
- ReadAsConstPngBytep(reader, read_offset_ + 8, length, read_buffer);
- if (!ParseFrameInfo(chunk) ||
- new_frame_.frame_rect != IntRect(0, 0, width_, height_)) {
- ignore_animation_ = true;
- continue;
- }
- idat_is_part_of_animation_ = true;
- } else if (IsChunk(chunk, "fdAT")) {
- ignore_animation_ = true;
- } else {
- png_process_data(png_, info_, const_cast<png_byte*>(chunk), 8);
- ProcessData(reader, read_offset_ + 8, length + 4);
- if (IsChunk(chunk, "IHDR")) {
- parsed_ihdr_ = true;
- width_ = png_get_image_width(png_, info_);
- height_ = png_get_image_height(png_, info_);
- }
- }
- }
-
- // Not enough data to call HeaderAvailable.
- return true;
-}
-
-void PNGImageReader::ClearDecodeState(size_t index) {
- if (index)
- return;
- png_destroy_read_struct(png_ ? &png_ : nullptr, info_ ? &info_ : nullptr, 0);
- DCHECK(!png_ && !info_);
- progressive_decode_offset_ = 0;
-}
-
-const PNGImageReader::FrameInfo& PNGImageReader::GetFrameInfo(
- size_t index) const {
- DCHECK(index < frame_info_.size());
- return frame_info_[index];
-}
-
-// Extract the fcTL frame control info and store it in new_frame_. The length
-// check on the fcTL data has been done by the calling code.
-bool PNGImageReader::ParseFrameInfo(const png_byte* data) {
- if (fctl_needs_dat_chunk_)
- return false;
-
- png_uint_32 frame_width = png_get_uint_32(data + 4);
- png_uint_32 frame_height = png_get_uint_32(data + 8);
- png_uint_32 x_offset = png_get_uint_32(data + 12);
- png_uint_32 y_offset = png_get_uint_32(data + 16);
- png_uint_16 delay_numerator = png_get_uint_16(data + 20);
- png_uint_16 delay_denominator = png_get_uint_16(data + 22);
-
- if (!CheckSequenceNumber(data))
- return false;
- if (!frame_width || !frame_height)
- return false;
- if (x_offset + frame_width > width_ || y_offset + frame_height > height_)
- return false;
-
- new_frame_.frame_rect =
- IntRect(x_offset, y_offset, frame_width, frame_height);
-
- if (delay_denominator)
- new_frame_.duration = delay_numerator * 1000 / delay_denominator;
- else
- new_frame_.duration = delay_numerator * 10;
-
- enum DisposeOperations : png_byte {
- kAPNG_DISPOSE_OP_NONE = 0,
- kAPNG_DISPOSE_OP_BACKGROUND = 1,
- kAPNG_DISPOSE_OP_PREVIOUS = 2,
- };
- const png_byte& dispose_op = data[24];
- switch (dispose_op) {
- case kAPNG_DISPOSE_OP_NONE:
- new_frame_.disposal_method = ImageFrame::DisposalMethod::kDisposeKeep;
- break;
- case kAPNG_DISPOSE_OP_BACKGROUND:
- new_frame_.disposal_method =
- ImageFrame::DisposalMethod::kDisposeOverwriteBgcolor;
- break;
- case kAPNG_DISPOSE_OP_PREVIOUS:
- new_frame_.disposal_method =
- ImageFrame::DisposalMethod::kDisposeOverwritePrevious;
- break;
- default:
- return false;
- }
-
- enum BlendOperations : png_byte {
- kAPNG_BLEND_OP_SOURCE = 0,
- kAPNG_BLEND_OP_OVER = 1,
- };
- const png_byte& blend_op = data[25];
- switch (blend_op) {
- case kAPNG_BLEND_OP_SOURCE:
- new_frame_.alpha_blend = ImageFrame::AlphaBlendSource::kBlendAtopBgcolor;
- break;
- case kAPNG_BLEND_OP_OVER:
- new_frame_.alpha_blend =
- ImageFrame::AlphaBlendSource::kBlendAtopPreviousFrame;
- break;
- default:
- return false;
- }
-
- fctl_needs_dat_chunk_ = true;
- return true;
-}
-
-} // namespace blink

Powered by Google App Engine
This is Rietveld 408576698