From dc76d92588aedc066d9208c12fd361853369fbb5 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Mon, 10 Jun 2024 16:04:41 -0700 Subject: [PATCH 1/5] [Impeller] makes bgra10xr test more comprehensive --- lib/ui/BUILD.gn | 1 + lib/ui/painting/image_encoding_unittests.cc | 82 ++++++++++++++++++++- 2 files changed, 80 insertions(+), 3 deletions(-) diff --git a/lib/ui/BUILD.gn b/lib/ui/BUILD.gn index 1d00f1dfeba50..f512b191ae05f 100644 --- a/lib/ui/BUILD.gn +++ b/lib/ui/BUILD.gn @@ -294,6 +294,7 @@ if (enable_unittests) { "//flutter/testing", "//flutter/testing:dart", "//flutter/testing:fixture_test", + "//flutter/third_party/libpng", "//flutter/third_party/tonic", ] diff --git a/lib/ui/painting/image_encoding_unittests.cc b/lib/ui/painting/image_encoding_unittests.cc index 76c34e9629a70..b3b2adc77209c 100644 --- a/lib/ui/painting/image_encoding_unittests.cc +++ b/lib/ui/painting/image_encoding_unittests.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "png.h" + #include "flutter/lib/ui/painting/image_encoding.h" #include "flutter/lib/ui/painting/image_encoding_impl.h" @@ -45,6 +47,74 @@ class MockDlImage : public DlImage { MOCK_METHOD(size_t, GetApproximateByteSize, (), (const, override)); }; +struct PngMemoryReader { + const uint8_t* data; + size_t offset; + size_t size; +}; + +void PngMemoryRead(png_structp png_ptr, + png_bytep out_bytes, + png_size_t byte_count_to_read) { + PngMemoryReader* memory_reader = + reinterpret_cast(png_get_io_ptr(png_ptr)); + if (memory_reader->offset + byte_count_to_read > memory_reader->size) { + png_error(png_ptr, "Read error in PngMemoryRead"); + } + memcpy(out_bytes, memory_reader->data + memory_reader->offset, + byte_count_to_read); + memory_reader->offset += byte_count_to_read; +} + +std::vector ReadPngFromMemory(const uint8_t* png_data, + size_t png_size) { + png_structp png = + png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + FML_CHECK(png); + + png_infop info = png_create_info_struct(png); + FML_CHECK(info); + + if (setjmp(png_jmpbuf(png))) { + FML_CHECK(false); + } + + PngMemoryReader memory_reader = { + .data = png_data, .offset = 0, .size = png_size}; + png_set_read_fn(png, &memory_reader, PngMemoryRead); + + png_read_info(png, info); + + int width = png_get_image_width(png, info); + int height = png_get_image_height(png, info); + png_byte color_type = png_get_color_type(png, info); + png_byte bit_depth = png_get_bit_depth(png, info); + + if (bit_depth == 16) { + png_set_strip_16(png); + } + if (color_type == PNG_COLOR_TYPE_PALETTE) { + png_set_palette_to_rgb(png); + } + + png_read_update_info(png, info); + png_size_t rowbytes = png_get_rowbytes(png, info); + std::vector result(width * height); + std::vector row_pointers; + row_pointers.reserve(height); + + for (int i = 0; i < height; ++i) { + row_pointers.push_back( + reinterpret_cast(result.data() + i * width)); + } + + png_read_image(png, row_pointers.data()); + + png_destroy_read_struct(&png, &info, nullptr); + + return result; +} + } // namespace class MockSyncSwitch { @@ -482,13 +552,19 @@ TEST(ImageEncodingImpellerTest, PngEncodingBGRA10XR) { paint.setColor(SK_ColorBLUE); paint.setAntiAlias(true); - canvas->clear(SK_ColorWHITE); - canvas->drawCircle(width / 2, height / 2, 100, paint); + canvas->clear(SK_ColorRED); + canvas->drawCircle(width / 2, height / 2, 25, paint); sk_sp image = surface->makeImageSnapshot(); fml::StatusOr> png = EncodeImage(image, ImageByteFormat::kPNG); - EXPECT_TRUE(png.ok()); + ASSERT_TRUE(png.ok()); + std::vector pixels = + ReadPngFromMemory(png.value()->bytes(), png.value()->size()); + + EXPECT_EQ(pixels[0], 0xff0000ff); + int middle = 100 * 50 + 50; + EXPECT_EQ(pixels[middle], 0xffff0000); } #endif // IMPELLER_SUPPORTS_RENDERING From 56fdf2be52646a27929482af4ed7bc86717c629d Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Mon, 10 Jun 2024 16:13:09 -0700 Subject: [PATCH 2/5] made png decompression more robust --- lib/ui/painting/image_encoding_unittests.cc | 28 +++++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/lib/ui/painting/image_encoding_unittests.cc b/lib/ui/painting/image_encoding_unittests.cc index b3b2adc77209c..96302f12e0ac9 100644 --- a/lib/ui/painting/image_encoding_unittests.cc +++ b/lib/ui/painting/image_encoding_unittests.cc @@ -66,17 +66,25 @@ void PngMemoryRead(png_structp png_ptr, memory_reader->offset += byte_count_to_read; } -std::vector ReadPngFromMemory(const uint8_t* png_data, - size_t png_size) { +fml::StatusOr> ReadPngFromMemory(const uint8_t* png_data, + size_t png_size) { png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); - FML_CHECK(png); + if (!png) { + return fml::Status(fml::StatusCode::kAborted, "unknown"); + } png_infop info = png_create_info_struct(png); - FML_CHECK(info); + if (!info) { + png_destroy_read_struct(&png, nullptr, nullptr); + return fml::Status(fml::StatusCode::kAborted, "unknown"); + } + + fml::ScopedCleanupClosure png_cleanup( + [&png, &info]() { png_destroy_read_struct(&png, &info, nullptr); }); if (setjmp(png_jmpbuf(png))) { - FML_CHECK(false); + return fml::Status(fml::StatusCode::kAborted, "unknown"); } PngMemoryReader memory_reader = { @@ -110,8 +118,6 @@ std::vector ReadPngFromMemory(const uint8_t* png_data, png_read_image(png, row_pointers.data()); - png_destroy_read_struct(&png, &info, nullptr); - return result; } @@ -559,12 +565,12 @@ TEST(ImageEncodingImpellerTest, PngEncodingBGRA10XR) { fml::StatusOr> png = EncodeImage(image, ImageByteFormat::kPNG); ASSERT_TRUE(png.ok()); - std::vector pixels = + fml::StatusOr> pixels = ReadPngFromMemory(png.value()->bytes(), png.value()->size()); - - EXPECT_EQ(pixels[0], 0xff0000ff); + ASSERT_TRUE(pixels.ok()); + EXPECT_EQ(pixels.value()[0], 0xff0000ff); int middle = 100 * 50 + 50; - EXPECT_EQ(pixels[middle], 0xffff0000); + EXPECT_EQ(pixels.value()[middle], 0xffff0000); } #endif // IMPELLER_SUPPORTS_RENDERING From 14569fd18ed89f06cbed264aa0ed32a1b32c499d Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Tue, 11 Jun 2024 11:03:51 -0700 Subject: [PATCH 3/5] tidy --- lib/ui/painting/image_encoding_unittests.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/ui/painting/image_encoding_unittests.cc b/lib/ui/painting/image_encoding_unittests.cc index 96302f12e0ac9..b924764381e47 100644 --- a/lib/ui/painting/image_encoding_unittests.cc +++ b/lib/ui/painting/image_encoding_unittests.cc @@ -106,7 +106,6 @@ fml::StatusOr> ReadPngFromMemory(const uint8_t* png_data, } png_read_update_info(png, info); - png_size_t rowbytes = png_get_rowbytes(png, info); std::vector result(width * height); std::vector row_pointers; row_pointers.reserve(height); From 63e5e7ba9f0052622d9a3dc2dab3577bbeb2ced5 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Tue, 11 Jun 2024 14:35:33 -0700 Subject: [PATCH 4/5] fuchsia fix --- lib/ui/painting/image_encoding_unittests.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ui/painting/image_encoding_unittests.cc b/lib/ui/painting/image_encoding_unittests.cc index b924764381e47..769bca24e7d6a 100644 --- a/lib/ui/painting/image_encoding_unittests.cc +++ b/lib/ui/painting/image_encoding_unittests.cc @@ -53,9 +53,9 @@ struct PngMemoryReader { size_t size; }; -void PngMemoryRead(png_structp png_ptr, - png_bytep out_bytes, - png_size_t byte_count_to_read) { +[[maybe_unused]] void PngMemoryRead(png_structp png_ptr, + png_bytep out_bytes, + png_size_t byte_count_to_read) { PngMemoryReader* memory_reader = reinterpret_cast(png_get_io_ptr(png_ptr)); if (memory_reader->offset + byte_count_to_read > memory_reader->size) { From cb505371c28d07137c573a8bf39cbb4ee77597b1 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Tue, 11 Jun 2024 14:57:52 -0700 Subject: [PATCH 5/5] fuchsia fix (moved functions around) --- lib/ui/painting/image_encoding_unittests.cc | 148 ++++++++++---------- 1 file changed, 75 insertions(+), 73 deletions(-) diff --git a/lib/ui/painting/image_encoding_unittests.cc b/lib/ui/painting/image_encoding_unittests.cc index 769bca24e7d6a..82b6db2eab60a 100644 --- a/lib/ui/painting/image_encoding_unittests.cc +++ b/lib/ui/painting/image_encoding_unittests.cc @@ -47,79 +47,6 @@ class MockDlImage : public DlImage { MOCK_METHOD(size_t, GetApproximateByteSize, (), (const, override)); }; -struct PngMemoryReader { - const uint8_t* data; - size_t offset; - size_t size; -}; - -[[maybe_unused]] void PngMemoryRead(png_structp png_ptr, - png_bytep out_bytes, - png_size_t byte_count_to_read) { - PngMemoryReader* memory_reader = - reinterpret_cast(png_get_io_ptr(png_ptr)); - if (memory_reader->offset + byte_count_to_read > memory_reader->size) { - png_error(png_ptr, "Read error in PngMemoryRead"); - } - memcpy(out_bytes, memory_reader->data + memory_reader->offset, - byte_count_to_read); - memory_reader->offset += byte_count_to_read; -} - -fml::StatusOr> ReadPngFromMemory(const uint8_t* png_data, - size_t png_size) { - png_structp png = - png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); - if (!png) { - return fml::Status(fml::StatusCode::kAborted, "unknown"); - } - - png_infop info = png_create_info_struct(png); - if (!info) { - png_destroy_read_struct(&png, nullptr, nullptr); - return fml::Status(fml::StatusCode::kAborted, "unknown"); - } - - fml::ScopedCleanupClosure png_cleanup( - [&png, &info]() { png_destroy_read_struct(&png, &info, nullptr); }); - - if (setjmp(png_jmpbuf(png))) { - return fml::Status(fml::StatusCode::kAborted, "unknown"); - } - - PngMemoryReader memory_reader = { - .data = png_data, .offset = 0, .size = png_size}; - png_set_read_fn(png, &memory_reader, PngMemoryRead); - - png_read_info(png, info); - - int width = png_get_image_width(png, info); - int height = png_get_image_height(png, info); - png_byte color_type = png_get_color_type(png, info); - png_byte bit_depth = png_get_bit_depth(png, info); - - if (bit_depth == 16) { - png_set_strip_16(png); - } - if (color_type == PNG_COLOR_TYPE_PALETTE) { - png_set_palette_to_rgb(png); - } - - png_read_update_info(png, info); - std::vector result(width * height); - std::vector row_pointers; - row_pointers.reserve(height); - - for (int i = 0; i < height; ++i) { - row_pointers.push_back( - reinterpret_cast(result.data() + i * width)); - } - - png_read_image(png, row_pointers.data()); - - return result; -} - } // namespace class MockSyncSwitch { @@ -544,6 +471,81 @@ TEST(ImageEncodingImpellerTest, PngEncoding10XR) { EXPECT_TRUE(png.ok()); } +namespace { +struct PngMemoryReader { + const uint8_t* data; + size_t offset; + size_t size; +}; + +void PngMemoryRead(png_structp png_ptr, + png_bytep out_bytes, + png_size_t byte_count_to_read) { + PngMemoryReader* memory_reader = + reinterpret_cast(png_get_io_ptr(png_ptr)); + if (memory_reader->offset + byte_count_to_read > memory_reader->size) { + png_error(png_ptr, "Read error in PngMemoryRead"); + } + memcpy(out_bytes, memory_reader->data + memory_reader->offset, + byte_count_to_read); + memory_reader->offset += byte_count_to_read; +} + +fml::StatusOr> ReadPngFromMemory(const uint8_t* png_data, + size_t png_size) { + png_structp png = + png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + if (!png) { + return fml::Status(fml::StatusCode::kAborted, "unknown"); + } + + png_infop info = png_create_info_struct(png); + if (!info) { + png_destroy_read_struct(&png, nullptr, nullptr); + return fml::Status(fml::StatusCode::kAborted, "unknown"); + } + + fml::ScopedCleanupClosure png_cleanup( + [&png, &info]() { png_destroy_read_struct(&png, &info, nullptr); }); + + if (setjmp(png_jmpbuf(png))) { + return fml::Status(fml::StatusCode::kAborted, "unknown"); + } + + PngMemoryReader memory_reader = { + .data = png_data, .offset = 0, .size = png_size}; + png_set_read_fn(png, &memory_reader, PngMemoryRead); + + png_read_info(png, info); + + int width = png_get_image_width(png, info); + int height = png_get_image_height(png, info); + png_byte color_type = png_get_color_type(png, info); + png_byte bit_depth = png_get_bit_depth(png, info); + + if (bit_depth == 16) { + png_set_strip_16(png); + } + if (color_type == PNG_COLOR_TYPE_PALETTE) { + png_set_palette_to_rgb(png); + } + + png_read_update_info(png, info); + std::vector result(width * height); + std::vector row_pointers; + row_pointers.reserve(height); + + for (int i = 0; i < height; ++i) { + row_pointers.push_back( + reinterpret_cast(result.data() + i * width)); + } + + png_read_image(png, row_pointers.data()); + + return result; +} +} // namespace + TEST(ImageEncodingImpellerTest, PngEncodingBGRA10XR) { int width = 100; int height = 100;