xref: /aosp_15_r20/external/skia/tests/NdkEncodeTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2020 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
9*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_ENABLE_NDK_IMAGES
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/codec/SkEncodedImageFormat.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBitmap.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorSpace.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageGenerator.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkStream.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/encode/SkJpegEncoder.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/encode/SkPngEncoder.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/encode/SkWebpEncoder.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMalloc.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/image/SkImageGeneratorPriv.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "tests/Test.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "tools/Resources.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "tools/ToolUtils.h"
24*c8dee2aaSAndroid Build Coastguard Worker 
25*c8dee2aaSAndroid Build Coastguard Worker #include <stdint.h>
26*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
27*c8dee2aaSAndroid Build Coastguard Worker 
28*c8dee2aaSAndroid Build Coastguard Worker static const char* kPng          = "png";
29*c8dee2aaSAndroid Build Coastguard Worker static const char* kJpeg         = "jpeg";
30*c8dee2aaSAndroid Build Coastguard Worker static const char* kWebpLossless = "webp_lossless";
31*c8dee2aaSAndroid Build Coastguard Worker static const char* kWebpLossy    = "webp_lossy";
32*c8dee2aaSAndroid Build Coastguard Worker 
33*c8dee2aaSAndroid Build Coastguard Worker namespace {
34*c8dee2aaSAndroid Build Coastguard Worker static const struct {
35*c8dee2aaSAndroid Build Coastguard Worker     SkEncodedImageFormat format;
36*c8dee2aaSAndroid Build Coastguard Worker     int                  quality;
37*c8dee2aaSAndroid Build Coastguard Worker     const char*          name;
38*c8dee2aaSAndroid Build Coastguard Worker } gRecs[] = {
39*c8dee2aaSAndroid Build Coastguard Worker     { SkEncodedImageFormat::kPNG,  100, kPng},
40*c8dee2aaSAndroid Build Coastguard Worker     { SkEncodedImageFormat::kJPEG, 100, kJpeg},
41*c8dee2aaSAndroid Build Coastguard Worker     { SkEncodedImageFormat::kWEBP, 100, kWebpLossless},
42*c8dee2aaSAndroid Build Coastguard Worker     { SkEncodedImageFormat::kWEBP,  80, kWebpLossy},
43*c8dee2aaSAndroid Build Coastguard Worker };
44*c8dee2aaSAndroid Build Coastguard Worker }
45*c8dee2aaSAndroid Build Coastguard Worker 
encode_ndk(const SkPixmap & pmap,SkEncodedImageFormat format,int quality)46*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkData> encode_ndk(const SkPixmap& pmap, SkEncodedImageFormat format, int quality) {
47*c8dee2aaSAndroid Build Coastguard Worker     SkDynamicMemoryWStream stream;
48*c8dee2aaSAndroid Build Coastguard Worker     SkDynamicMemoryWStream buf;
49*c8dee2aaSAndroid Build Coastguard Worker     switch (format) {
50*c8dee2aaSAndroid Build Coastguard Worker         case SkEncodedImageFormat::kPNG: {
51*c8dee2aaSAndroid Build Coastguard Worker             bool success = SkPngEncoder::Encode(&buf, pmap, {});
52*c8dee2aaSAndroid Build Coastguard Worker             return success ? buf.detachAsData() : nullptr;
53*c8dee2aaSAndroid Build Coastguard Worker         }
54*c8dee2aaSAndroid Build Coastguard Worker         case SkEncodedImageFormat::kJPEG: {
55*c8dee2aaSAndroid Build Coastguard Worker             SkJpegEncoder::Options opts;
56*c8dee2aaSAndroid Build Coastguard Worker             opts.fQuality = quality;
57*c8dee2aaSAndroid Build Coastguard Worker             bool success = SkJpegEncoder::Encode(&buf, pmap, opts);
58*c8dee2aaSAndroid Build Coastguard Worker             return success ? buf.detachAsData() : nullptr;
59*c8dee2aaSAndroid Build Coastguard Worker         }
60*c8dee2aaSAndroid Build Coastguard Worker         case SkEncodedImageFormat::kWEBP: {
61*c8dee2aaSAndroid Build Coastguard Worker             SkWebpEncoder::Options opts;
62*c8dee2aaSAndroid Build Coastguard Worker             opts.fQuality = quality;
63*c8dee2aaSAndroid Build Coastguard Worker             bool success = SkWebpEncoder::Encode(&buf, pmap, opts);
64*c8dee2aaSAndroid Build Coastguard Worker             return success ? buf.detachAsData() : nullptr;
65*c8dee2aaSAndroid Build Coastguard Worker         }
66*c8dee2aaSAndroid Build Coastguard Worker         default:
67*c8dee2aaSAndroid Build Coastguard Worker             SkUNREACHABLE;
68*c8dee2aaSAndroid Build Coastguard Worker     }
69*c8dee2aaSAndroid Build Coastguard Worker }
70*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(NdkEncode,r)71*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(NdkEncode, r) {
72*c8dee2aaSAndroid Build Coastguard Worker     for (auto ct : { kRGBA_8888_SkColorType,
73*c8dee2aaSAndroid Build Coastguard Worker                      kRGB_565_SkColorType,
74*c8dee2aaSAndroid Build Coastguard Worker                      kRGBA_F16_SkColorType }) {
75*c8dee2aaSAndroid Build Coastguard Worker         SkBitmap bm;
76*c8dee2aaSAndroid Build Coastguard Worker         bm.allocPixels(SkImageInfo::Make(10, 10, ct, kOpaque_SkAlphaType));
77*c8dee2aaSAndroid Build Coastguard Worker         bm.eraseColor(SK_ColorBLUE);
78*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& rec : gRecs) {
79*c8dee2aaSAndroid Build Coastguard Worker             auto encoded = encode_ndk(bm.pixmap(), rec.format, rec.quality);
80*c8dee2aaSAndroid Build Coastguard Worker             if (!encoded) {
81*c8dee2aaSAndroid Build Coastguard Worker                 ERRORF(r, "Failed to encode %s to %s\n", ToolUtils::colortype_name(ct), rec.name);
82*c8dee2aaSAndroid Build Coastguard Worker                 continue;
83*c8dee2aaSAndroid Build Coastguard Worker             }
84*c8dee2aaSAndroid Build Coastguard Worker             auto gen = SkImageGenerators::MakeFromEncoded(std::move(encoded));
85*c8dee2aaSAndroid Build Coastguard Worker             if (!gen) {
86*c8dee2aaSAndroid Build Coastguard Worker                 ERRORF(r, "Failed to decode from %s as %s\n", ToolUtils::colortype_name(ct),
87*c8dee2aaSAndroid Build Coastguard Worker                        rec.name);
88*c8dee2aaSAndroid Build Coastguard Worker                 continue;
89*c8dee2aaSAndroid Build Coastguard Worker             }
90*c8dee2aaSAndroid Build Coastguard Worker 
91*c8dee2aaSAndroid Build Coastguard Worker             if (rec.name == kPng && bm.colorType() == kRGB_565_SkColorType) {
92*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(r, gen->getInfo().colorType() == kRGB_565_SkColorType);
93*c8dee2aaSAndroid Build Coastguard Worker             } else {
94*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(r, gen->getInfo().colorType() == kN32_SkColorType);
95*c8dee2aaSAndroid Build Coastguard Worker             }
96*c8dee2aaSAndroid Build Coastguard Worker 
97*c8dee2aaSAndroid Build Coastguard Worker             SkBitmap bm2;
98*c8dee2aaSAndroid Build Coastguard Worker             bm2.allocPixels(bm.info());
99*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(r, gen->getPixels(bm2.pixmap()));
100*c8dee2aaSAndroid Build Coastguard Worker 
101*c8dee2aaSAndroid Build Coastguard Worker             for (int x = 0; x < bm.width();  x++)
102*c8dee2aaSAndroid Build Coastguard Worker             for (int y = 0; y < bm.height(); y++) {
103*c8dee2aaSAndroid Build Coastguard Worker                 SkColor orig   = bm .getColor(x, y);
104*c8dee2aaSAndroid Build Coastguard Worker                 SkColor actual = bm2.getColor(x, y);
105*c8dee2aaSAndroid Build Coastguard Worker 
106*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(r, SkColorGetA(orig) == SkColorGetA(actual));
107*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(r, SkColorGetA(orig) == 0xFF);
108*c8dee2aaSAndroid Build Coastguard Worker 
109*c8dee2aaSAndroid Build Coastguard Worker                 if (rec.name == kPng || rec.name == kWebpLossless) {
110*c8dee2aaSAndroid Build Coastguard Worker                     REPORTER_ASSERT(r, orig == actual);
111*c8dee2aaSAndroid Build Coastguard Worker                 } else {
112*c8dee2aaSAndroid Build Coastguard Worker                     int diffR = std::abs((int) SkColorGetR(orig) - (int) SkColorGetR(actual));
113*c8dee2aaSAndroid Build Coastguard Worker                     int diffG = std::abs((int) SkColorGetG(orig) - (int) SkColorGetG(actual));
114*c8dee2aaSAndroid Build Coastguard Worker                     int diffB = std::abs((int) SkColorGetB(orig) - (int) SkColorGetB(actual));
115*c8dee2aaSAndroid Build Coastguard Worker                     REPORTER_ASSERT(r, diffR <= 2 && diffG <= 1 && diffB <= 1);
116*c8dee2aaSAndroid Build Coastguard Worker                 }
117*c8dee2aaSAndroid Build Coastguard Worker             }
118*c8dee2aaSAndroid Build Coastguard Worker         }
119*c8dee2aaSAndroid Build Coastguard Worker     }
120*c8dee2aaSAndroid Build Coastguard Worker }
121*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(NdkEncode_unsupportedFormats,r)122*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(NdkEncode_unsupportedFormats, r) {
123*c8dee2aaSAndroid Build Coastguard Worker     for (auto ct : { kRGBA_8888_SkColorType,
124*c8dee2aaSAndroid Build Coastguard Worker                      kRGB_565_SkColorType,
125*c8dee2aaSAndroid Build Coastguard Worker                      kRGBA_F16_SkColorType }) {
126*c8dee2aaSAndroid Build Coastguard Worker         SkBitmap bm;
127*c8dee2aaSAndroid Build Coastguard Worker         bm.allocPixels(SkImageInfo::Make(10, 10, ct, kOpaque_SkAlphaType));
128*c8dee2aaSAndroid Build Coastguard Worker         bm.eraseColor(SK_ColorBLUE);
129*c8dee2aaSAndroid Build Coastguard Worker         for (auto format : { SkEncodedImageFormat::kBMP,
130*c8dee2aaSAndroid Build Coastguard Worker                              SkEncodedImageFormat::kGIF,
131*c8dee2aaSAndroid Build Coastguard Worker                              SkEncodedImageFormat::kICO,
132*c8dee2aaSAndroid Build Coastguard Worker                              SkEncodedImageFormat::kWBMP,
133*c8dee2aaSAndroid Build Coastguard Worker                              SkEncodedImageFormat::kPKM,
134*c8dee2aaSAndroid Build Coastguard Worker                              SkEncodedImageFormat::kKTX,
135*c8dee2aaSAndroid Build Coastguard Worker                              SkEncodedImageFormat::kASTC,
136*c8dee2aaSAndroid Build Coastguard Worker                              SkEncodedImageFormat::kDNG,
137*c8dee2aaSAndroid Build Coastguard Worker                              SkEncodedImageFormat::kHEIF }) {
138*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(r, !encode_ndk(bm.pixmap(), format, 100));
139*c8dee2aaSAndroid Build Coastguard Worker         }
140*c8dee2aaSAndroid Build Coastguard Worker     }
141*c8dee2aaSAndroid Build Coastguard Worker }
142*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(NdkEncode_badQuality,r)143*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(NdkEncode_badQuality, r) {
144*c8dee2aaSAndroid Build Coastguard Worker     for (auto ct : { kRGBA_8888_SkColorType,
145*c8dee2aaSAndroid Build Coastguard Worker                      kRGB_565_SkColorType,
146*c8dee2aaSAndroid Build Coastguard Worker                      kRGBA_F16_SkColorType }) {
147*c8dee2aaSAndroid Build Coastguard Worker         SkBitmap bm;
148*c8dee2aaSAndroid Build Coastguard Worker         bm.allocPixels(SkImageInfo::Make(10, 10, ct, kOpaque_SkAlphaType));
149*c8dee2aaSAndroid Build Coastguard Worker         bm.eraseColor(SK_ColorBLUE);
150*c8dee2aaSAndroid Build Coastguard Worker         for (auto format : { SkEncodedImageFormat::kJPEG,
151*c8dee2aaSAndroid Build Coastguard Worker                              SkEncodedImageFormat::kPNG,
152*c8dee2aaSAndroid Build Coastguard Worker                              SkEncodedImageFormat::kWEBP }) {
153*c8dee2aaSAndroid Build Coastguard Worker             for (int quality : {-1, -100, 101, 200}) {
154*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(r, !encode_ndk(bm.pixmap(), format, quality));
155*c8dee2aaSAndroid Build Coastguard Worker             }
156*c8dee2aaSAndroid Build Coastguard Worker         }
157*c8dee2aaSAndroid Build Coastguard Worker     }
158*c8dee2aaSAndroid Build Coastguard Worker }
159*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(NdkEncode_nullPixels,r)160*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(NdkEncode_nullPixels, r) {
161*c8dee2aaSAndroid Build Coastguard Worker     for (auto info : { SkImageInfo::MakeUnknown(),
162*c8dee2aaSAndroid Build Coastguard Worker                        SkImageInfo::MakeN32Premul(10, 10),
163*c8dee2aaSAndroid Build Coastguard Worker                        SkImageInfo::MakeN32Premul(0, 0)}) {
164*c8dee2aaSAndroid Build Coastguard Worker         SkPixmap pm(info, nullptr, info.minRowBytes());
165*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& rec : gRecs) {
166*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(r, !encode_ndk(pm, rec.format, rec.quality));
167*c8dee2aaSAndroid Build Coastguard Worker         }
168*c8dee2aaSAndroid Build Coastguard Worker     }
169*c8dee2aaSAndroid Build Coastguard Worker }
170*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(NdkEncode_badInfo,r)171*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(NdkEncode_badInfo, r) {
172*c8dee2aaSAndroid Build Coastguard Worker     // Allocate an arbitrary amount of memory. These infos don't have a natural
173*c8dee2aaSAndroid Build Coastguard Worker     // amount to allocate, and the encoder shouldn't touch the memory anyway.
174*c8dee2aaSAndroid Build Coastguard Worker     // But this allows us to verify that the bad info fails, even when the pixel
175*c8dee2aaSAndroid Build Coastguard Worker     // pointer is not null.
176*c8dee2aaSAndroid Build Coastguard Worker     void* pixels = sk_malloc_throw(1024);
177*c8dee2aaSAndroid Build Coastguard Worker     std::vector<SkPixmap> pixmaps{ SkPixmap(SkImageInfo::MakeN32Premul(-10, 10), pixels, 1000),
178*c8dee2aaSAndroid Build Coastguard Worker                                    SkPixmap(SkImageInfo::MakeN32Premul(10, -10), pixels, 200),
179*c8dee2aaSAndroid Build Coastguard Worker                                    SkPixmap(SkImageInfo::MakeN32Premul(10,  10), pixels, 20),
180*c8dee2aaSAndroid Build Coastguard Worker                                    SkPixmap(SkImageInfo::MakeN32Premul(10,  10), pixels, 41),
181*c8dee2aaSAndroid Build Coastguard Worker                                    SkPixmap(SkImageInfo::MakeN32Premul(10,  10), pixels, 0),
182*c8dee2aaSAndroid Build Coastguard Worker                                    SkPixmap(SkImageInfo::MakeN32Premul( 0,   0), pixels, 40)};
183*c8dee2aaSAndroid Build Coastguard Worker     if (sizeof(size_t) > sizeof(uint32_t)) {
184*c8dee2aaSAndroid Build Coastguard Worker         pixmaps.emplace_back(SkImageInfo::MakeN32Premul(10, 10),  pixels,
185*c8dee2aaSAndroid Build Coastguard Worker                              static_cast<size_t>(UINT32_MAX) + 1);
186*c8dee2aaSAndroid Build Coastguard Worker     }
187*c8dee2aaSAndroid Build Coastguard Worker     for (const auto& pm : pixmaps) {
188*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& rec : gRecs) {
189*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(r, !encode_ndk(pm, rec.format, rec.quality));
190*c8dee2aaSAndroid Build Coastguard Worker         }
191*c8dee2aaSAndroid Build Coastguard Worker     }
192*c8dee2aaSAndroid Build Coastguard Worker     free(pixels);
193*c8dee2aaSAndroid Build Coastguard Worker }
194*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(NdkEncode_unsupportedColorTypes,r)195*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(NdkEncode_unsupportedColorTypes, r) {
196*c8dee2aaSAndroid Build Coastguard Worker     for (SkColorType ct : {
197*c8dee2aaSAndroid Build Coastguard Worker         kUnknown_SkColorType,
198*c8dee2aaSAndroid Build Coastguard Worker         kAlpha_8_SkColorType,
199*c8dee2aaSAndroid Build Coastguard Worker         kARGB_4444_SkColorType,
200*c8dee2aaSAndroid Build Coastguard Worker         kRGB_888x_SkColorType,
201*c8dee2aaSAndroid Build Coastguard Worker         kBGRA_8888_SkColorType,
202*c8dee2aaSAndroid Build Coastguard Worker         kRGBA_1010102_SkColorType,
203*c8dee2aaSAndroid Build Coastguard Worker         kBGRA_1010102_SkColorType,
204*c8dee2aaSAndroid Build Coastguard Worker         kRGB_101010x_SkColorType,
205*c8dee2aaSAndroid Build Coastguard Worker         kBGR_101010x_SkColorType,
206*c8dee2aaSAndroid Build Coastguard Worker         kGray_8_SkColorType,
207*c8dee2aaSAndroid Build Coastguard Worker         kRGBA_F16Norm_SkColorType,
208*c8dee2aaSAndroid Build Coastguard Worker         kRGB_F16F16F16x_SkColorType,
209*c8dee2aaSAndroid Build Coastguard Worker         kRGBA_F32_SkColorType,
210*c8dee2aaSAndroid Build Coastguard Worker         kR8G8_unorm_SkColorType,
211*c8dee2aaSAndroid Build Coastguard Worker         kA16_float_SkColorType,
212*c8dee2aaSAndroid Build Coastguard Worker         kR16G16_float_SkColorType,
213*c8dee2aaSAndroid Build Coastguard Worker         kA16_unorm_SkColorType,
214*c8dee2aaSAndroid Build Coastguard Worker         kR16G16_unorm_SkColorType,
215*c8dee2aaSAndroid Build Coastguard Worker         kR16G16B16A16_unorm_SkColorType,
216*c8dee2aaSAndroid Build Coastguard Worker     }) {
217*c8dee2aaSAndroid Build Coastguard Worker         auto info = SkImageInfo::Make(7, 13, ct, kOpaque_SkAlphaType, SkColorSpace::MakeSRGB());
218*c8dee2aaSAndroid Build Coastguard Worker         SkBitmap bm;
219*c8dee2aaSAndroid Build Coastguard Worker         bm.allocPixels(info);
220*c8dee2aaSAndroid Build Coastguard Worker         bm.eraseColor(SK_ColorGREEN);
221*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& rec : gRecs) {
222*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(r, !encode_ndk(bm.pixmap(), rec.format, rec.quality));
223*c8dee2aaSAndroid Build Coastguard Worker         }
224*c8dee2aaSAndroid Build Coastguard Worker         if (!SkColorTypeIsAlwaysOpaque(ct)) {
225*c8dee2aaSAndroid Build Coastguard Worker             for (auto at : { kPremul_SkAlphaType, kUnpremul_SkAlphaType}) {
226*c8dee2aaSAndroid Build Coastguard Worker                 info = info.makeAlphaType(at);
227*c8dee2aaSAndroid Build Coastguard Worker                 bm.allocPixels(info);
228*c8dee2aaSAndroid Build Coastguard Worker                 bm.eraseARGB(0x7F, 0xFF, 0xFF, 0xFF);
229*c8dee2aaSAndroid Build Coastguard Worker             }
230*c8dee2aaSAndroid Build Coastguard Worker             for (const auto& rec : gRecs) {
231*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(r, !encode_ndk(bm.pixmap(), rec.format, rec.quality));
232*c8dee2aaSAndroid Build Coastguard Worker             }
233*c8dee2aaSAndroid Build Coastguard Worker         }
234*c8dee2aaSAndroid Build Coastguard Worker     }
235*c8dee2aaSAndroid Build Coastguard Worker }
236*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(NdkEncode_unsupportedAlphaTypes,r)237*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(NdkEncode_unsupportedAlphaTypes, r) {
238*c8dee2aaSAndroid Build Coastguard Worker     for (auto ct : { kRGBA_8888_SkColorType,
239*c8dee2aaSAndroid Build Coastguard Worker                      kRGB_565_SkColorType,
240*c8dee2aaSAndroid Build Coastguard Worker                      kRGBA_F16_SkColorType }) {
241*c8dee2aaSAndroid Build Coastguard Worker         for (auto at : { kUnknown_SkAlphaType, (SkAlphaType) -1}) {
242*c8dee2aaSAndroid Build Coastguard Worker             auto info = SkImageInfo::Make(10, 10, ct, at);
243*c8dee2aaSAndroid Build Coastguard Worker             size_t rowBytes = info.minRowBytes();
244*c8dee2aaSAndroid Build Coastguard Worker             void* pixels = sk_malloc_throw(info.computeByteSize(rowBytes));
245*c8dee2aaSAndroid Build Coastguard Worker             SkPixmap pm(info, pixels, rowBytes);
246*c8dee2aaSAndroid Build Coastguard Worker             for (const auto& rec : gRecs) {
247*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(r, !encode_ndk(pm, rec.format, rec.quality));
248*c8dee2aaSAndroid Build Coastguard Worker             }
249*c8dee2aaSAndroid Build Coastguard Worker             free(pixels);
250*c8dee2aaSAndroid Build Coastguard Worker         }
251*c8dee2aaSAndroid Build Coastguard Worker     }
252*c8dee2aaSAndroid Build Coastguard Worker }
253*c8dee2aaSAndroid Build Coastguard Worker 
254*c8dee2aaSAndroid Build Coastguard Worker static constexpr skcms_TransferFunction k2Dot6 = {2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
255*c8dee2aaSAndroid Build Coastguard Worker 
256*c8dee2aaSAndroid Build Coastguard Worker static constexpr skcms_Matrix3x3 kDCIP3 = {{
257*c8dee2aaSAndroid Build Coastguard Worker         {0.486143, 0.323835, 0.154234},
258*c8dee2aaSAndroid Build Coastguard Worker         {0.226676, 0.710327, 0.0629966},
259*c8dee2aaSAndroid Build Coastguard Worker         {0.000800549, 0.0432385, 0.78275},
260*c8dee2aaSAndroid Build Coastguard Worker }};
261*c8dee2aaSAndroid Build Coastguard Worker 
262*c8dee2aaSAndroid Build Coastguard Worker 
nearly_equal(float a,float b)263*c8dee2aaSAndroid Build Coastguard Worker static bool nearly_equal(float a, float b) {
264*c8dee2aaSAndroid Build Coastguard Worker     return fabs(a - b) < .002f;
265*c8dee2aaSAndroid Build Coastguard Worker }
266*c8dee2aaSAndroid Build Coastguard Worker 
nearly_equal(const skcms_TransferFunction & x,const skcms_TransferFunction & y)267*c8dee2aaSAndroid Build Coastguard Worker static bool nearly_equal(const skcms_TransferFunction& x, const skcms_TransferFunction& y) {
268*c8dee2aaSAndroid Build Coastguard Worker     return nearly_equal(x.g, y.g)
269*c8dee2aaSAndroid Build Coastguard Worker         && nearly_equal(x.a, y.a)
270*c8dee2aaSAndroid Build Coastguard Worker         && nearly_equal(x.b, y.b)
271*c8dee2aaSAndroid Build Coastguard Worker         && nearly_equal(x.c, y.c)
272*c8dee2aaSAndroid Build Coastguard Worker         && nearly_equal(x.d, y.d)
273*c8dee2aaSAndroid Build Coastguard Worker         && nearly_equal(x.e, y.e)
274*c8dee2aaSAndroid Build Coastguard Worker         && nearly_equal(x.f, y.f);
275*c8dee2aaSAndroid Build Coastguard Worker }
276*c8dee2aaSAndroid Build Coastguard Worker 
nearly_equal(const skcms_Matrix3x3 & a,const skcms_Matrix3x3 & b)277*c8dee2aaSAndroid Build Coastguard Worker static bool nearly_equal(const skcms_Matrix3x3& a, const skcms_Matrix3x3& b) {
278*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < 3; i++)
279*c8dee2aaSAndroid Build Coastguard Worker     for (int j = 0; j < 3; j++) {
280*c8dee2aaSAndroid Build Coastguard Worker         if (!nearly_equal(a.vals[i][j], b.vals[i][j])) return false;
281*c8dee2aaSAndroid Build Coastguard Worker     }
282*c8dee2aaSAndroid Build Coastguard Worker     return true;
283*c8dee2aaSAndroid Build Coastguard Worker }
284*c8dee2aaSAndroid Build Coastguard Worker 
nearly_equal(SkColorSpace * a,SkColorSpace * b)285*c8dee2aaSAndroid Build Coastguard Worker static bool nearly_equal(SkColorSpace* a, SkColorSpace* b) {
286*c8dee2aaSAndroid Build Coastguard Worker     skcms_TransferFunction fnA,     fnB;
287*c8dee2aaSAndroid Build Coastguard Worker     skcms_Matrix3x3        gamutA,  gamutB;
288*c8dee2aaSAndroid Build Coastguard Worker     return a && b && a->isNumericalTransferFn(&fnA) && a->toXYZD50(&gamutA)
289*c8dee2aaSAndroid Build Coastguard Worker                   && b->isNumericalTransferFn(&fnB) && b->toXYZD50(&gamutB)
290*c8dee2aaSAndroid Build Coastguard Worker              && nearly_equal(fnA, fnB) && nearly_equal(gamutA, gamutB);
291*c8dee2aaSAndroid Build Coastguard Worker }
292*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(NdkEncode_ColorSpace,r)293*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(NdkEncode_ColorSpace, r) {
294*c8dee2aaSAndroid Build Coastguard Worker     const struct {
295*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkColorSpace> cs;
296*c8dee2aaSAndroid Build Coastguard Worker         const char*         name;
297*c8dee2aaSAndroid Build Coastguard Worker     } colorSpaces[] = {
298*c8dee2aaSAndroid Build Coastguard Worker         { sk_sp<SkColorSpace>(nullptr),                                                 "null"    },
299*c8dee2aaSAndroid Build Coastguard Worker         { SkColorSpace::MakeSRGB(),                                                     "srgb"    },
300*c8dee2aaSAndroid Build Coastguard Worker         { SkColorSpace::MakeSRGBLinear(),                                            "srgb-linear"},
301*c8dee2aaSAndroid Build Coastguard Worker         { SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, SkNamedGamut::kSRGB),      "bt709"   },
302*c8dee2aaSAndroid Build Coastguard Worker         { SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, SkNamedGamut::kRec2020),   "rec2020" },
303*c8dee2aaSAndroid Build Coastguard Worker         { SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,    SkNamedGamut::kDisplayP3), "p3"      },
304*c8dee2aaSAndroid Build Coastguard Worker         { SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2,   SkNamedGamut::kAdobeRGB),  "adobeRGB"},
305*c8dee2aaSAndroid Build Coastguard Worker         { SkColorSpace::MakeRGB(k2Dot6,                      kDCIP3),                   "dci-p3"  },
306*c8dee2aaSAndroid Build Coastguard Worker     };
307*c8dee2aaSAndroid Build Coastguard Worker     for (const auto& colorSpace : colorSpaces) {
308*c8dee2aaSAndroid Build Coastguard Worker         for (auto ct : { kRGBA_8888_SkColorType, kRGB_565_SkColorType, kRGBA_F16_SkColorType }) {
309*c8dee2aaSAndroid Build Coastguard Worker             SkBitmap bm;
310*c8dee2aaSAndroid Build Coastguard Worker             bm.allocPixels(SkImageInfo::Make(10, 10, ct, kOpaque_SkAlphaType, colorSpace.cs));
311*c8dee2aaSAndroid Build Coastguard Worker             bm.eraseColor(SK_ColorRED);
312*c8dee2aaSAndroid Build Coastguard Worker 
313*c8dee2aaSAndroid Build Coastguard Worker             for (const auto& rec : gRecs) {
314*c8dee2aaSAndroid Build Coastguard Worker                 auto encoded = encode_ndk(bm.pixmap(), rec.format, rec.quality);
315*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(r, encoded);
316*c8dee2aaSAndroid Build Coastguard Worker                 auto gen = SkImageGenerators::MakeFromEncoded(std::move(encoded));
317*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(r, gen);
318*c8dee2aaSAndroid Build Coastguard Worker 
319*c8dee2aaSAndroid Build Coastguard Worker                 auto  expected = colorSpace.cs ? colorSpace.cs : SkColorSpace::MakeSRGB();
320*c8dee2aaSAndroid Build Coastguard Worker                 auto* actual   = gen->getInfo().colorSpace();
321*c8dee2aaSAndroid Build Coastguard Worker                 if (!nearly_equal(actual, expected.get())) {
322*c8dee2aaSAndroid Build Coastguard Worker                     const char* name = "unknown";
323*c8dee2aaSAndroid Build Coastguard Worker                     for (auto named : colorSpaces) {
324*c8dee2aaSAndroid Build Coastguard Worker                         if (nearly_equal(actual, named.cs.get())) {
325*c8dee2aaSAndroid Build Coastguard Worker                             name = named.name;
326*c8dee2aaSAndroid Build Coastguard Worker                             break;
327*c8dee2aaSAndroid Build Coastguard Worker                         }
328*c8dee2aaSAndroid Build Coastguard Worker                     }
329*c8dee2aaSAndroid Build Coastguard Worker 
330*c8dee2aaSAndroid Build Coastguard Worker                     ERRORF(r, "Mismatch: expected: %s\tactual:%s", colorSpace.name, name);
331*c8dee2aaSAndroid Build Coastguard Worker                 }
332*c8dee2aaSAndroid Build Coastguard Worker             }
333*c8dee2aaSAndroid Build Coastguard Worker         }
334*c8dee2aaSAndroid Build Coastguard Worker     }
335*c8dee2aaSAndroid Build Coastguard Worker }
336*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(NdkEncode_unsupportedColorSpace,r)337*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(NdkEncode_unsupportedColorSpace, r) {
338*c8dee2aaSAndroid Build Coastguard Worker     std::vector<sk_sp<SkColorSpace>> unsupportedCs;
339*c8dee2aaSAndroid Build Coastguard Worker     for (auto gamut : { SkNamedGamut::kSRGB, SkNamedGamut::kAdobeRGB, SkNamedGamut::kDisplayP3,
340*c8dee2aaSAndroid Build Coastguard Worker                         SkNamedGamut::kRec2020, SkNamedGamut::kXYZ }) {
341*c8dee2aaSAndroid Build Coastguard Worker         unsupportedCs.push_back(SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ, gamut));
342*c8dee2aaSAndroid Build Coastguard Worker         unsupportedCs.push_back(SkColorSpace::MakeRGB(SkNamedTransferFn::kHLG, gamut));
343*c8dee2aaSAndroid Build Coastguard Worker         unsupportedCs.push_back(SkColorSpace::MakeRGB(k2Dot6, gamut));
344*c8dee2aaSAndroid Build Coastguard Worker     }
345*c8dee2aaSAndroid Build Coastguard Worker 
346*c8dee2aaSAndroid Build Coastguard Worker     for (auto gamut : { SkNamedGamut::kSRGB, SkNamedGamut::kDisplayP3,
347*c8dee2aaSAndroid Build Coastguard Worker                         SkNamedGamut::kRec2020, SkNamedGamut::kXYZ }) {
348*c8dee2aaSAndroid Build Coastguard Worker         unsupportedCs.push_back(SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2, gamut));
349*c8dee2aaSAndroid Build Coastguard Worker     }
350*c8dee2aaSAndroid Build Coastguard Worker 
351*c8dee2aaSAndroid Build Coastguard Worker     for (auto gamut : { SkNamedGamut::kAdobeRGB, SkNamedGamut::kDisplayP3,
352*c8dee2aaSAndroid Build Coastguard Worker                         SkNamedGamut::kXYZ }) {
353*c8dee2aaSAndroid Build Coastguard Worker         unsupportedCs.push_back(SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, gamut));
354*c8dee2aaSAndroid Build Coastguard Worker     }
355*c8dee2aaSAndroid Build Coastguard Worker 
356*c8dee2aaSAndroid Build Coastguard Worker     for (auto gamut : { SkNamedGamut::kAdobeRGB, SkNamedGamut::kDisplayP3,
357*c8dee2aaSAndroid Build Coastguard Worker                         SkNamedGamut::kRec2020, SkNamedGamut::kXYZ }) {
358*c8dee2aaSAndroid Build Coastguard Worker         unsupportedCs.push_back(SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, gamut));
359*c8dee2aaSAndroid Build Coastguard Worker     }
360*c8dee2aaSAndroid Build Coastguard Worker 
361*c8dee2aaSAndroid Build Coastguard Worker     for (auto gamut : { SkNamedGamut::kAdobeRGB,
362*c8dee2aaSAndroid Build Coastguard Worker                         SkNamedGamut::kRec2020, SkNamedGamut::kXYZ }) {
363*c8dee2aaSAndroid Build Coastguard Worker         unsupportedCs.push_back(SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut));
364*c8dee2aaSAndroid Build Coastguard Worker     }
365*c8dee2aaSAndroid Build Coastguard Worker 
366*c8dee2aaSAndroid Build Coastguard Worker     for (auto fn : { SkNamedTransferFn::kSRGB, SkNamedTransferFn::k2Dot2,
367*c8dee2aaSAndroid Build Coastguard Worker                      SkNamedTransferFn::kLinear, SkNamedTransferFn::kRec2020 }) {
368*c8dee2aaSAndroid Build Coastguard Worker         unsupportedCs.push_back(SkColorSpace::MakeRGB(fn, kDCIP3));
369*c8dee2aaSAndroid Build Coastguard Worker     }
370*c8dee2aaSAndroid Build Coastguard Worker 
371*c8dee2aaSAndroid Build Coastguard Worker     for (auto unsupported : unsupportedCs) {
372*c8dee2aaSAndroid Build Coastguard Worker         for (auto ct : { kRGBA_8888_SkColorType, kRGB_565_SkColorType, kRGBA_F16_SkColorType }) {
373*c8dee2aaSAndroid Build Coastguard Worker             SkBitmap bm;
374*c8dee2aaSAndroid Build Coastguard Worker             bm.allocPixels(SkImageInfo::Make(10, 10, ct, kOpaque_SkAlphaType, unsupported));
375*c8dee2aaSAndroid Build Coastguard Worker             bm.eraseColor(SK_ColorBLUE);
376*c8dee2aaSAndroid Build Coastguard Worker 
377*c8dee2aaSAndroid Build Coastguard Worker             for (const auto& rec : gRecs) {
378*c8dee2aaSAndroid Build Coastguard Worker                 REPORTER_ASSERT(r, !encode_ndk(bm.pixmap(), rec.format, rec.quality));
379*c8dee2aaSAndroid Build Coastguard Worker             }
380*c8dee2aaSAndroid Build Coastguard Worker         }
381*c8dee2aaSAndroid Build Coastguard Worker     }
382*c8dee2aaSAndroid Build Coastguard Worker }
383*c8dee2aaSAndroid Build Coastguard Worker 
384*c8dee2aaSAndroid Build Coastguard Worker #endif // SK_ENABLE_NDK_IMAGES
385