Flutter Engine
The Flutter Engine
image_decoder_no_gl_unittests.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "flutter/lib/ui/painting/image_decoder_no_gl_unittests.h"
6
7#include "flutter/fml/endianness.h"
8
9namespace flutter {
10namespace testing {
11
12// Tests are disabled for fuchsia.
13#if defined(OS_FUCHSIA)
14#pragma GCC diagnostic ignored "-Wunreachable-code"
15#endif
16
17namespace {
18
19bool IsPngWithPLTE(const uint8_t* bytes, size_t size) {
20 constexpr std::string_view kPngMagic = "\x89PNG\x0d\x0a\x1a\x0a";
21 constexpr std::string_view kPngPlte = "PLTE";
22 constexpr uint32_t kLengthBytes = 4;
23 constexpr uint32_t kTypeBytes = 4;
24 constexpr uint32_t kCrcBytes = 4;
25
26 if (size < kPngMagic.size()) {
27 return false;
28 }
29
30 if (memcmp(bytes, kPngMagic.data(), kPngMagic.size()) != 0) {
31 return false;
32 }
33
34 const uint8_t* end = bytes + size;
35 const uint8_t* loc = bytes + kPngMagic.size();
36 while (loc + kLengthBytes + kTypeBytes <= end) {
37 uint32_t chunk_length =
38 fml::BigEndianToArch(*reinterpret_cast<const uint32_t*>(loc));
39
40 if (memcmp(loc + kLengthBytes, kPngPlte.data(), kPngPlte.size()) == 0) {
41 return true;
42 }
43
44 loc += kLengthBytes + kTypeBytes + chunk_length + kCrcBytes;
45 }
46
47 return false;
48}
49
50} // namespace
51
52float HalfToFloat(uint16_t half) {
53 switch (half) {
54 case 0x7c00:
55 return std::numeric_limits<float>::infinity();
56 case 0xfc00:
57 return -std::numeric_limits<float>::infinity();
58 }
59 bool negative = half >> 15;
60 uint16_t exponent = (half >> 10) & 0x1f;
61 uint16_t fraction = half & 0x3ff;
62 float fExponent = exponent - 15.0f;
63 float fFraction = static_cast<float>(fraction) / 1024.f;
64 float pow_value = powf(2.0f, fExponent);
65 return (negative ? -1.f : 1.f) * pow_value * (1.0f + fFraction);
66}
67
68float DecodeBGR10(uint32_t x) {
69 const float max = 1.25098f;
70 const float min = -0.752941f;
71 const float intercept = min;
72 const float slope = (max - min) / 1024.0f;
73 return (x * slope) + intercept;
74}
75
76TEST(ImageDecoderNoGLTest, ImpellerWideGamutDisplayP3) {
77#if defined(OS_FUCHSIA)
78 GTEST_SKIP() << "Fuchsia can't load the test fixtures.";
79#endif
80 auto data = flutter::testing::OpenFixtureAsSkData("DisplayP3Logo.png");
82 ASSERT_TRUE(image != nullptr);
83 ASSERT_EQ(SkISize::Make(100, 100), image->dimensions());
84
86 std::shared_ptr<ImageGenerator> generator =
88 ASSERT_TRUE(generator);
89
90 auto descriptor = fml::MakeRefCounted<ImageDescriptor>(std::move(data),
91 std::move(generator));
92
93 ASSERT_FALSE(
94 IsPngWithPLTE(descriptor->data()->bytes(), descriptor->data()->size()));
95
96#if IMPELLER_SUPPORTS_RENDERING
97 std::shared_ptr<impeller::Allocator> allocator =
98 std::make_shared<impeller::TestImpellerAllocator>();
99 std::optional<DecompressResult> wide_result =
101 descriptor.get(), SkISize::Make(100, 100), {100, 100},
102 /*supports_wide_gamut=*/true, allocator);
103 ASSERT_TRUE(wide_result.has_value());
104 ASSERT_EQ(wide_result->image_info.colorType(), kRGBA_F16_SkColorType);
105 ASSERT_TRUE(wide_result->image_info.colorSpace()->isSRGB());
106
107 const SkPixmap& wide_pixmap = wide_result->sk_bitmap->pixmap();
108 const uint16_t* half_ptr = static_cast<const uint16_t*>(wide_pixmap.addr());
109 bool found_deep_red = false;
110 for (int i = 0; i < wide_pixmap.width() * wide_pixmap.height(); ++i) {
111 float red = HalfToFloat(*half_ptr++);
112 float green = HalfToFloat(*half_ptr++);
113 float blue = HalfToFloat(*half_ptr++);
114 half_ptr++; // alpha
115 if (fabsf(red - 1.0931f) < 0.01f && fabsf(green - -0.2268f) < 0.01f &&
116 fabsf(blue - -0.1501f) < 0.01f) {
117 found_deep_red = true;
118 break;
119 }
120 }
121
122 ASSERT_TRUE(found_deep_red);
123 std::optional<DecompressResult> narrow_result =
125 descriptor.get(), SkISize::Make(100, 100), {100, 100},
126 /*supports_wide_gamut=*/false, allocator);
127
128 ASSERT_TRUE(narrow_result.has_value());
129 ASSERT_EQ(narrow_result->image_info.colorType(), kRGBA_8888_SkColorType);
130#endif // IMPELLER_SUPPORTS_RENDERING
131}
132
133TEST(ImageDecoderNoGLTest, ImpellerWideGamutIndexedPng) {
134#if defined(OS_FUCHSIA)
135 GTEST_SKIP() << "Fuchsia can't load the test fixtures.";
136#endif
137 auto data = flutter::testing::OpenFixtureAsSkData("WideGamutIndexed.png");
139 ASSERT_TRUE(image != nullptr);
140 ASSERT_EQ(SkISize::Make(100, 100), image->dimensions());
141
142 ImageGeneratorRegistry registry;
143 std::shared_ptr<ImageGenerator> generator =
145 ASSERT_TRUE(generator);
146
147 auto descriptor = fml::MakeRefCounted<ImageDescriptor>(std::move(data),
148 std::move(generator));
149
150 ASSERT_TRUE(
151 IsPngWithPLTE(descriptor->data()->bytes(), descriptor->data()->size()));
152
153#if IMPELLER_SUPPORTS_RENDERING
154 std::shared_ptr<impeller::Allocator> allocator =
155 std::make_shared<impeller::TestImpellerAllocator>();
156 std::optional<DecompressResult> wide_result =
158 descriptor.get(), SkISize::Make(100, 100), {100, 100},
159 /*supports_wide_gamut=*/true, allocator);
160 ASSERT_EQ(wide_result->image_info.colorType(), kBGR_101010x_XR_SkColorType);
161 ASSERT_TRUE(wide_result->image_info.colorSpace()->isSRGB());
162
163 const SkPixmap& wide_pixmap = wide_result->sk_bitmap->pixmap();
164 const uint32_t* pixel_ptr = static_cast<const uint32_t*>(wide_pixmap.addr());
165 bool found_deep_red = false;
166 for (int i = 0; i < wide_pixmap.width() * wide_pixmap.height(); ++i) {
167 uint32_t pixel = *pixel_ptr++;
168 float blue = DecodeBGR10((pixel >> 0) & 0x3ff);
169 float green = DecodeBGR10((pixel >> 10) & 0x3ff);
170 float red = DecodeBGR10((pixel >> 20) & 0x3ff);
171 if (fabsf(red - 1.0931f) < 0.01f && fabsf(green - -0.2268f) < 0.01f &&
172 fabsf(blue - -0.1501f) < 0.01f) {
173 found_deep_red = true;
174 break;
175 }
176 }
177
178 ASSERT_TRUE(found_deep_red);
179 std::optional<DecompressResult> narrow_result =
181 descriptor.get(), SkISize::Make(100, 100), {100, 100},
182 /*supports_wide_gamut=*/false, allocator);
183
184 ASSERT_TRUE(narrow_result.has_value());
185 ASSERT_EQ(narrow_result->image_info.colorType(), kRGBA_8888_SkColorType);
186#endif // IMPELLER_SUPPORTS_RENDERING
187}
188
189} // namespace testing
190} // namespace flutter
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
Definition: SkColorType.h:38
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
@ kBGR_101010x_XR_SkColorType
pixel with 10 bits each for blue, green, red; in 32-bit word, extended range
Definition: SkColorType.h:31
SkISize dimensions() const
Definition: SkImage.h:297
int width() const
Definition: SkPixmap.h:160
const void * addr() const
Definition: SkPixmap.h:153
int height() const
Definition: SkPixmap.h:166
static DecompressResult DecompressTexture(ImageDescriptor *descriptor, SkISize target_size, impeller::ISize max_texture_size, bool supports_wide_gamut, const std::shared_ptr< impeller::Allocator > &allocator)
Keeps a priority-ordered registry of image generator builders to be used when decoding images....
std::shared_ptr< ImageGenerator > CreateCompatibleGenerator(const sk_sp< SkData > &buffer)
Walks the list of image generator builders in descending priority order until a compatible ImageGener...
glong glong end
static float max(float r, float g, float b)
Definition: hsl.cpp:49
static float min(float r, float g, float b)
Definition: hsl.cpp:48
double x
SK_API sk_sp< SkImage > DeferredFromEncodedData(sk_sp< SkData > encoded, std::optional< SkAlphaType > alphaType=std::nullopt)
sk_sp< const SkImage > image
Definition: SkRecords.h:269
sk_sp< SkData > OpenFixtureAsSkData(const std::string &fixture_name)
Opens a fixture of the given file name and returns a Skia SkData holding its contents.
Definition: testing.cc:64
TEST(DisplayListComplexity, EmptyDisplayList)
float HalfToFloat(uint16_t half)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition: switches.h:41
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
constexpr T BigEndianToArch(T n)
Convert a known big endian value to match the endianness of the current architecture....
Definition: endianness.h:59
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20