Add support for Animated PNG
Update the browser accept header to state that APNG is supported. Split
the decoding of PNG images into two stages: parsing and decoding. During
parsing, chunks are handled one of three ways:
- acTL and fcTL chunks, which specify properties of an APNG are read and
the properties are stored. If they contain an error before IDAT, the image
is treated as a static PNG, as recommended by the spec . If they contain
an error after IDAT, this is a failure, since some frames may have been
decoded. CRCs are calculated and compared to their expected values.
Mismatches are considered errors.
- fdAT and IDAT chunks have their locations stored for decoding later. Any
ordering violations result in either a static image or failed image,
depending on whether IDAT has been seen yet.
- Other chunks before IDAT are passed to libpng for processing.
Each frame is decoded as if it were a complete PNG file. fdATs are converted
to IDATs (and their CRCs are ignored**) and the IHDR is modified for subset
frames. The rowAvailable callback positions subset frames properly within the
full image buffer. For a static PNG or the first frame decoded (assuming its
size matches IHDR) the png struct used during parsing is reused. Otherwise,
a new png struct is created for the duration of the decode.
Follow the APNG spec as closely as possible and use the APNG test page  as
a guide for intended behavior. All of the valid APNG on the test page work
as expected. For the invalid APNG:
- Errors that occur before IDAT show the default image, as intended
- Errors afterwards are typically treated as failures (see Future work, below)
- The final three images draw incorrectly. They have incorrectly sized IDATs/
fdATs. These could be respected by checking the warning that libpng sends
(in the case of extra data) or keeping track of how many rows have been seen
(in the case of too little data), although we currently ignore this for static
PNGs anyway. (crbug.com/698808)
The first frame can be decoded progressively. Other frames are not reported
until the following fcTL chunk has been reached during parse.
Add a reference test, modified from WebKit's fast/images/animated-png.html
with the following changes:
- use window.internals.advanceImageAnimation instead of waiting for a
timeout, for more reliable testing
- disable two of the images, which look the same to my eyes, but are not
identical (I suspect due to blending differences as compared to how the
reference tests were created).
Add gtests. Update progressive tests to reuse a SharedBuffer, rather than
recreating it, to reduce test run-time.
Fix a bug in ImageFrameGenerator where it called setMemoryAllocator before
setting the data, and add related tests.
Stop calling setFailed inside ImageDecoder::initFrameBuffer, return false
instead. Clients are now expected to call setFailed (update the WEBP and
GIF clients). This is safer, because setFailed may delete an object that
In WEBPImageDecoder: rename frameIsLoadedAtIndex to frameIsReceivedAtIndex,
for consistency with PNGImageDecoder.
Always call ImageFrame::setStatus last (e.g. after calling onInitFrameBuffer,
- Revert to showing the default image for failures past IDAT. This is tricky,
since the client may be holding on to previous frames, and we need to make
sure they switch to using the IDAT frame, even if it is not part of the
animation. For now, we mark the decoder as having failed. (crbug.com/699675)
** We cannot allow libpng to check the CRC since we modified the chunk. We
could check the CRC directly as a separate step.
Initial patch is a re-upload of issue 2386453003 at patchset 39
(http://crrev.com/2386453003#ps1260001) by email@example.com, which
also used https://codereview.chromium.org/1567053002/ by firstname.lastname@example.org
as a reference.
48 files changed