chromium/third_party/blink/renderer/platform/image-decoders/png/png_image_decoder_test.cc

// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "third_party/blink/renderer/platform/image-decoders/png/png_image_decoder.h"

#include <memory>

#include "base/logging.h"
#include "base/time/time.h"
#include "png.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/image-decoders/image_decoder_test_helpers.h"
#include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
#include "third_party/skia/include/core/SkColorPriv.h"
#include "third_party/skia/include/core/SkColorSpace.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/core/SkRefCnt.h"

// web_tests/images/resources/png-animated-idat-part-of-animation.png
// is modified in multiple tests to simulate erroneous PNGs. As a reference,
// the table below shows how the file is structured.
//
// Offset | 8     33    95    133   172   210   241   279   314   352   422
// -------------------------------------------------------------------------
// Chunk  | IHDR  acTL  fcTL  IDAT  fcTL  fdAT  fcTL  fdAT  fcTL  fdAT  IEND
//
// In between the acTL and fcTL there are two other chunks, PLTE and tRNS, but
// those are not specifically used in this test suite. The same holds for a
// tEXT chunk in between the last fdAT and IEND.
//
// In the current behavior of PNG image decoders, the 4 frames are detected when
// respectively 141, 249, 322 and 430 bytes are received. The first frame should
// be detected when the IDAT has been received, and non-first frames when the
// next fcTL or IEND chunk has been received. Note that all offsets are +8,
// because a chunk is identified by byte 4-7.

namespace blink {

namespace {

std::unique_ptr<ImageDecoder> CreatePNGDecoder(
    ImageDecoder::AlphaOption alpha_option) {}

std::unique_ptr<ImageDecoder> CreatePNGDecoder() {}

std::unique_ptr<ImageDecoder> Create16BitPNGDecoder() {}

std::unique_ptr<ImageDecoder> CreatePNGDecoderWithPngData(
    const char* png_file) {}

void TestSize(const char* png_file, gfx::Size expected_size) {}

// Test whether querying for the size of the image works if we present the
// data byte by byte.
void TestSizeByteByByte(const char* png_file,
                        size_t bytes_needed_to_decode_size,
                        gfx::Size expected_size) {}

void WriteUint32(uint32_t val, png_byte* data) {}

void TestRepetitionCount(const char* png_file, int expected_repetition_count) {}

struct PublicFrameInfo {};

// This is the frame data for the following PNG image:
// web_tests/images/resources/png-animated-idat-part-of-animation.png
static PublicFrameInfo g_png_animated_frame_info[] =;

void CompareFrameWithExpectation(const PublicFrameInfo& expected,
                                 ImageDecoder* decoder,
                                 size_t index) {}

// This function removes |length| bytes at |offset|, and then calls FrameCount.
// It assumes the missing bytes should result in a failed decode because the
// parser jumps |length| bytes too far in the next chunk.
void TestMissingDataBreaksDecoding(const char* png_file,
                                   size_t offset,
                                   size_t length) {}

// Verify that a decoder with a parse error converts to a static image.
static void ExpectStatic(ImageDecoder* decoder) {}

// Decode up to the indicated fcTL offset and then provide an fcTL with the
// wrong chunk size (20 instead of 26).
void TestInvalidFctlSize(const char* png_file,
                         size_t offset_fctl,
                         size_t expected_frame_count,
                         bool should_fail) {}

// Verify that the decoder can successfully decode the first frame when
// initially only half of the frame data is received, resulting in a partially
// decoded image, and then the rest of the image data is received. Verify that
// the bitmap hashes of the two stages are different. Also verify that the final
// bitmap hash is equivalent to the hash when all data is provided at once.
//
// This verifies that the decoder correctly keeps track of where it stopped
// decoding when the image was not yet fully received.
void TestProgressiveDecodingContinuesAfterFullData(
    const char* png_file,
    size_t offset_mid_first_frame) {}

}  // Anonymous namespace

// Animated PNG Tests

TEST(AnimatedPNGTests, sizeTest) {}

TEST(AnimatedPNGTests, repetitionCountTest) {}

// Test if the decoded metdata corresponds to the defined expectations
TEST(AnimatedPNGTests, MetaDataTest) {}

TEST(AnimatedPNGTests, EmptyFrame) {}

TEST(AnimatedPNGTests, ByteByByteSizeAvailable) {}

TEST(AnimatedPNGTests, ByteByByteMetaData) {}

TEST(AnimatedPNGTests, TestRandomFrameDecode) {}

TEST(AnimatedPNGTests, TestDecodeAfterReallocation) {}

TEST(AnimatedPNGTests, ProgressiveDecode) {}

TEST(AnimatedPNGTests, ParseAndDecodeByteByByte) {}

TEST(AnimatedPNGTests, FailureDuringParsing) {}

TEST(AnimatedPNGTests, ActlErrors) {}

TEST(AnimatedPNGTests, fdatBeforeIdat) {}

TEST(AnimatedPNGTests, FrameOverflowX) {}

// This test is exactly the same as above, except it changes y_offset.
TEST(AnimatedPNGTests, FrameOverflowY) {}

TEST(AnimatedPNGTests, IdatSizeMismatch) {}

TEST(AnimatedPNGTests, EmptyFdatFails) {}

// Originally, the third frame has an offset of (1,2) and a size of (3,2). By
// changing the offset to (4,4), the frame rect is no longer within the image
// size of 5x5. This results in a failure.
TEST(AnimatedPNGTests, VerifyFrameOutsideImageSizeFails) {}

TEST(AnimatedPNGTests, ProgressiveDecodingContinuesAfterFullData) {}

TEST(AnimatedPNGTests, RandomDecodeAfterClearFrameBufferCache) {}

TEST(AnimatedPNGTests, VerifyAlphaBlending) {}

// This tests if the frame count gets set correctly when parsing FrameCount
// fails in one of the parsing queries.
//
// First, enough data is provided such that two frames should be registered.
// The decoder should at this point not be in the failed status.
//
// Then, we provide the rest of the data except for the last IEND chunk, but
// tell the decoder that this is all the data we have.  The frame count should
// be three, since one extra frame should be discovered. The fourth frame
// should *not* be registered since the reader should not be able to determine
// where the frame ends. The decoder should *not* be in the failed state since
// there are three frames which can be shown.
// Attempting to decode the third frame should fail, since the file is
// truncated.
TEST(AnimatedPNGTests, FailureMissingIendChunk) {}

// Verify that a malformatted PNG, where the IEND appears before any frame data
// (IDAT), invalidates the decoder.
TEST(AnimatedPNGTests, VerifyIENDBeforeIDATInvalidatesDecoder) {}

// All IDAT chunks must be before all fdAT chunks
TEST(AnimatedPNGTests, MixedDataChunks) {}

// Verify that erroneous values for the disposal method and alpha blending
// cause the decoder to fail.
TEST(AnimatedPNGTests, VerifyInvalidDisposalAndBlending) {}

// This test verifies that the following situation does not invalidate the
// decoder:
// - Frame 0 is decoded progressively, but there's not enough data to fully
//   decode it.
// - The rest of the image data is received.
// - Frame X, with X > 0, and X does not depend on frame 0, is decoded.
// - Frame 0 is decoded.
// This is a tricky case since the decoder resets the png struct for each frame,
// and this test verifies that it does not break the decoding of frame 0, even
// though it already started in the first call.
TEST(AnimatedPNGTests, VerifySuccessfulFirstFrameDecodeAfterLaterFrame) {}

// If the decoder attempts to decode a non-first frame which is subset and
// independent, it needs to discard its png_struct so it can use a modified
// IHDR. Test this by comparing a decode of frame 1 after frame 0 to a decode
// of frame 1 without decoding frame 0.
TEST(AnimatedPNGTests, DecodeFromIndependentFrame) {}

// If the first frame is subset from IHDR (only allowed if the first frame is
// not the default image), the decoder has to destroy the png_struct it used
// for parsing so it can use a modified IHDR.
TEST(AnimatedPNGTests, SubsetFromIHDR) {}

TEST(AnimatedPNGTests, Offset) {}

TEST(AnimatedPNGTests, ExtraChunksBeforeIHDR) {}

// Static PNG tests

TEST(StaticPNGTests, repetitionCountTest) {}

TEST(StaticPNGTests, sizeTest) {}

TEST(StaticPNGTests, MetaDataTest) {}

// circle-trns-before-plte.png is of color type 2 (PNG_COLOR_TYPE_RGB) and has
// a tRNS chunk before a PLTE chunk. The image has an opaque blue circle on a
// transparent green background.
//
// The PNG specification version 1.2 says:
//   When present, the tRNS chunk must precede the first IDAT chunk, and must
//   follow the PLTE chunk, if any.
// Therefore, in the default libpng configuration (which defines the
// PNG_READ_OPT_PLTE_SUPPORTED macro), the tRNS chunk is considered invalid and
// ignored. However, png_get_valid(png, info, PNG_INFO_tRNS) still returns a
// nonzero value, so an application may call png_set_tRNS_to_alpha(png) and
// assume libpng's output has alpha, resulting in memory errors. See
// https://github.com/glennrp/libpng/issues/482.
//
// Since Chromium chooses to undefine PNG_READ_OPT_PLTE_SUPPORTED in
// pnglibconf.h, it is not affected by this potential bug. For extra assurance,
// this test decodes this image and makes sure there are no errors.
TEST(StaticPNGTests, ColorType2TrnsBeforePlte) {}

TEST(StaticPNGTests, InvalidIHDRChunk) {}

TEST(StaticPNGTests, ProgressiveDecoding) {}

TEST(StaticPNGTests, ProgressiveDecodingContinuesAfterFullData) {}

struct PNGSample {};

static void TestHighBitDepthPNGDecoding(const PNGSample& png_sample,
                                        ImageDecoder* decoder) {}

static void FillPNGSamplesSourcePixels(Vector<PNGSample>& png_samples) {}

static Vector<PNGSample> GetPNGSamplesInfo(bool include_8bit_pngs) {}

TEST(StaticPNGTests, DecodeHighBitDepthPngToHalfFloat) {}

TEST(StaticPNGTests, ImageIsHighBitDepth) {}

TEST(PNGTests, VerifyFrameCompleteBehavior) {}

TEST(PNGTests, sizeMayOverflow) {}

TEST(PNGTests, truncated) {}

TEST(PNGTests, crbug827754) {}

TEST(PNGTests, cicp) {}

TEST(PNGTests, HDRMetadata) {}

TEST(AnimatedPNGTests, TrnsMeansAlpha) {}

TEST(PNGTests, CriticalPrivateChunkBeforeIHDR) {}

}  // namespace blink