1 /*
2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 
18 #define LOG_TAG "AImageDecoderTest"
19 
20 #include <jni.h>
21 #include <android/asset_manager.h>
22 #include <android/asset_manager_jni.h>
23 #include <android/data_space.h>
24 #include <android/bitmap.h>
25 #include <android/imagedecoder.h>
26 #include <android/rect.h>
27 
28 #include "NativeTestHelpers.h"
29 
30 #include <cstdlib>
31 #include <cstring>
32 #include <initializer_list>
33 #include <limits>
34 #include <memory>
35 #include <stdio.h>
36 #include <unistd.h>
37 #include <vector>
38 
39 #define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
40 
41 using AssetCloser = std::unique_ptr<AAsset, decltype(&AAsset_close)>;
42 using DecoderDeleter = std::unique_ptr<AImageDecoder, decltype(&AImageDecoder_delete)>;
43 
testEmptyCreate(JNIEnv * env,jclass)44 static void testEmptyCreate(JNIEnv* env, jclass) {
45     AImageDecoder* decoderPtr = nullptr;
46     for (AImageDecoder** outDecoder : { &decoderPtr, (AImageDecoder**) nullptr }) {
47         for (AAsset* asset : { nullptr }) {
48             int result = AImageDecoder_createFromAAsset(asset, outDecoder);
49             ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
50             if (outDecoder) {
51                 ASSERT_EQ(nullptr, *outDecoder);
52             }
53         }
54 
55         for (int fd : { 0, -1 }) {
56             int result = AImageDecoder_createFromFd(fd, outDecoder);
57             ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
58             if (outDecoder) {
59                 ASSERT_EQ(nullptr, *outDecoder);
60             }
61         }
62 
63         auto testEmptyBuffer = [env, outDecoder](void* buffer, size_t length) {
64             int result = AImageDecoder_createFromBuffer(buffer, length, outDecoder);
65             ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
66             if (outDecoder) {
67                 ASSERT_EQ(nullptr, *outDecoder);
68             }
69         };
70         testEmptyBuffer(nullptr, 0);
71         char buf[4];
72         testEmptyBuffer(buf, 0);
73     }
74 }
75 
openAsset(JNIEnv * env,jobject jAssets,jstring jFile,int mode)76 static AAsset* openAsset(JNIEnv* env, jobject jAssets, jstring jFile, int mode) {
77     AAssetManager* nativeManager = AAssetManager_fromJava(env, jAssets);
78     const char* file = env->GetStringUTFChars(jFile, nullptr);
79     AAsset* asset = AAssetManager_open(nativeManager, file, mode);
80     if (!asset) {
81         ALOGE("Could not open %s", file);
82     } else {
83         ALOGD("Testing %s", file);
84     }
85     env->ReleaseStringUTFChars(jFile, file);
86     return asset;
87 }
88 
testNullDecoder(JNIEnv * env,jclass,jobject jAssets,jstring jFile)89 static void testNullDecoder(JNIEnv* env, jclass, jobject jAssets, jstring jFile) {
90     AAsset* asset = openAsset(env, jAssets, jFile, AASSET_MODE_BUFFER);
91     ASSERT_NE(asset, nullptr);
92     AssetCloser assetCloser(asset, AAsset_close);
93 
94     AImageDecoder_delete(nullptr);
95 
96 #pragma clang diagnostic push
97 #pragma clang diagnostic ignored "-Wnonnull"
98     {
99         int result = AImageDecoder_createFromAAsset(asset, nullptr);
100         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
101     }
102 
103     {
104         const void* buffer = AAsset_getBuffer(asset);
105         ASSERT_NE(buffer, nullptr);
106 
107         int result = AImageDecoder_createFromBuffer(buffer, AAsset_getLength(asset), nullptr);
108         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
109     }
110 
111     {
112         off_t start, length;
113         int fd = AAsset_openFileDescriptor(asset, &start, &length);
114         ASSERT_GT(fd, 0);
115 
116         off_t offset = ::lseek(fd, start, SEEK_SET);
117         ASSERT_EQ(start, offset);
118 
119         int result = AImageDecoder_createFromFd(fd, nullptr);
120         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
121         close(fd);
122     }
123 
124     {
125         auto stride = AImageDecoder_getMinimumStride(nullptr);
126         ASSERT_EQ(0, stride);
127     }
128 
129     {
130         char buf[4];
131         int result = AImageDecoder_decodeImage(nullptr, buf, 4, 4);
132         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
133     }
134 
135     {
136         int result = AImageDecoder_setAndroidBitmapFormat(nullptr, ANDROID_BITMAP_FORMAT_RGBA_8888);
137         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
138 
139         auto format = AImageDecoderHeaderInfo_getAndroidBitmapFormat(nullptr);
140         ASSERT_EQ(ANDROID_BITMAP_FORMAT_NONE, format);
141     }
142 
143     {
144         int result = AImageDecoder_setUnpremultipliedRequired(nullptr, true);
145         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
146 
147         int alpha = AImageDecoderHeaderInfo_getAlphaFlags(nullptr);
148         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, alpha);
149     }
150 
151     ASSERT_EQ(0, AImageDecoderHeaderInfo_getWidth(nullptr));
152     ASSERT_EQ(0, AImageDecoderHeaderInfo_getHeight(nullptr));
153     ASSERT_EQ(nullptr, AImageDecoderHeaderInfo_getMimeType(nullptr));
154     ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, AImageDecoderHeaderInfo_getDataSpace(nullptr));
155 
156     {
157         int result = AImageDecoder_setTargetSize(nullptr, 1, 1);
158         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
159     }
160     {
161         ARect rect {0, 0, 10, 10};
162         int result = AImageDecoder_setCrop(nullptr, rect);
163         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
164     }
165 
166     for (ADataSpace dataSpace : { ADATASPACE_UNKNOWN, ADATASPACE_SCRGB_LINEAR, ADATASPACE_SRGB,
167                                   ADATASPACE_SCRGB, ADATASPACE_DISPLAY_P3, ADATASPACE_BT2020_PQ,
168                                   ADATASPACE_ADOBE_RGB, ADATASPACE_BT2020, ADATASPACE_BT709,
169                                   ADATASPACE_DCI_P3, ADATASPACE_SRGB_LINEAR }) {
170         int result = AImageDecoder_setDataSpace(nullptr, dataSpace);
171         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
172     }
173 
174     ASSERT_FALSE(AImageDecoder_isAnimated(nullptr));
175 
176     {
177         int result = AImageDecoder_getRepeatCount(nullptr);
178         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
179     }
180 #pragma clang diagnostic pop
181 }
182 
testInfo(JNIEnv * env,jclass,jlong imageDecoderPtr,jint width,jint height,jstring jMimeType,jboolean isF16,jint dataSpace)183 static void testInfo(JNIEnv* env, jclass, jlong imageDecoderPtr, jint width, jint height,
184                      jstring jMimeType, jboolean isF16, jint dataSpace) {
185     AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
186     ASSERT_NE(decoder, nullptr);
187     DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
188 
189     const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
190     ASSERT_NE(info, nullptr);
191     int32_t actualWidth = AImageDecoderHeaderInfo_getWidth(info);
192     ASSERT_EQ(width, actualWidth);
193     int32_t actualHeight = AImageDecoderHeaderInfo_getHeight(info);
194     ASSERT_EQ(height, actualHeight);
195 
196     const char* mimeType = env->GetStringUTFChars(jMimeType, nullptr);
197     ASSERT_NE(mimeType, nullptr);
198     ASSERT_EQ(0, strcmp(mimeType, AImageDecoderHeaderInfo_getMimeType(info)));
199     env->ReleaseStringUTFChars(jMimeType, mimeType);
200     auto format = AImageDecoderHeaderInfo_getAndroidBitmapFormat(info);
201     if (isF16) {
202         ASSERT_EQ(ANDROID_BITMAP_FORMAT_RGBA_F16, format);
203     } else {
204         ASSERT_EQ(ANDROID_BITMAP_FORMAT_RGBA_8888, format);
205     }
206 
207     ASSERT_EQ(dataSpace, AImageDecoderHeaderInfo_getDataSpace(info));
208 }
209 
openAssetNative(JNIEnv * env,jclass,jobject jAssets,jstring jFile)210 static jlong openAssetNative(JNIEnv* env, jclass, jobject jAssets, jstring jFile) {
211     // FIXME: Test the other modes? Or more to the point, pass in the mode? It
212     // seems that when we want a buffer we should use AASSET_MODE_BUFFER.
213     AAsset* asset = openAsset(env, jAssets, jFile, AASSET_MODE_UNKNOWN);
214     if (!asset) {
215         fail(env, "Failed to open native asset!");
216     }
217     return reinterpret_cast<jlong>(asset);
218 }
219 
closeAsset(JNIEnv *,jclass,jlong asset)220 static void closeAsset(JNIEnv*, jclass, jlong asset) {
221     AAsset_close(reinterpret_cast<AAsset*>(asset));
222 }
223 
createFromAsset(JNIEnv * env,jclass,jlong asset)224 static jlong createFromAsset(JNIEnv* env, jclass, jlong asset) {
225     AImageDecoder* decoder = nullptr;
226     int result = AImageDecoder_createFromAAsset(reinterpret_cast<AAsset*>(asset), &decoder);
227     if (ANDROID_IMAGE_DECODER_SUCCESS != result || !decoder) {
228         fail(env, "Failed to create AImageDecoder!");
229     }
230     return reinterpret_cast<jlong>(decoder);
231 }
232 
createFromFd(JNIEnv * env,jclass,int fd)233 static jlong createFromFd(JNIEnv* env, jclass, int fd) {
234     AImageDecoder* decoder = nullptr;
235     int result = AImageDecoder_createFromFd(fd, &decoder);
236     if (ANDROID_IMAGE_DECODER_SUCCESS != result || !decoder) {
237         fail(env, "Failed to create AImageDecoder!");
238     }
239     return reinterpret_cast<jlong>(decoder);
240 }
241 
createFromAssetFd(JNIEnv * env,jclass,jlong assetPtr)242 static jlong createFromAssetFd(JNIEnv* env, jclass, jlong assetPtr) {
243     AAsset* asset = reinterpret_cast<AAsset*>(assetPtr);
244     off_t start, length;
245     int fd = AAsset_openFileDescriptor(asset, &start, &length);
246     if (fd <= 0) {
247         fail(env, "Failed to open file descriptor!");
248         return -1;
249     }
250 
251     off_t offset = ::lseek(fd, start, SEEK_SET);
252     if (offset != start) {
253         fail(env, "Failed to seek file descriptor!");
254         return -1;
255     }
256 
257     return createFromFd(env, nullptr, fd);
258 }
259 
createFromAssetBuffer(JNIEnv * env,jclass,jlong assetPtr)260 static jlong createFromAssetBuffer(JNIEnv* env, jclass, jlong assetPtr) {
261     AAsset* asset = reinterpret_cast<AAsset*>(assetPtr);
262     const void* buffer = AAsset_getBuffer(asset);
263     if (!buffer) {
264         fail(env, "AAsset_getBuffer failed!");
265         return -1;
266     }
267 
268     AImageDecoder* decoder = nullptr;
269     int result = AImageDecoder_createFromBuffer(buffer, AAsset_getLength(asset), &decoder);
270     if (ANDROID_IMAGE_DECODER_SUCCESS != result || !decoder) {
271         fail(env, "AImageDecoder_createFromBuffer failed!");
272         return -1;
273     }
274     return reinterpret_cast<jlong>(decoder);
275 }
276 
testCreateIncomplete(JNIEnv * env,jclass,jobject jAssets,jstring jFile,jint truncatedLength)277 static void testCreateIncomplete(JNIEnv* env, jclass, jobject jAssets, jstring jFile,
278                                  jint truncatedLength) {
279     AAsset* asset = openAsset(env, jAssets, jFile, AASSET_MODE_UNKNOWN);
280     ASSERT_NE(asset, nullptr);
281     AssetCloser assetCloser(asset, AAsset_close);
282 
283     const void* buffer = AAsset_getBuffer(asset);
284     ASSERT_NE(buffer, nullptr);
285 
286     AImageDecoder* decoder;
287     int result = AImageDecoder_createFromBuffer(buffer, truncatedLength, &decoder);
288     ASSERT_EQ(ANDROID_IMAGE_DECODER_INCOMPLETE, result);
289     ASSERT_EQ(decoder, nullptr);
290 }
291 
testCreateUnsupported(JNIEnv * env,jclass,jobject jAssets,jstring jFile)292 static void testCreateUnsupported(JNIEnv* env, jclass, jobject jAssets, jstring jFile) {
293     AAsset* asset = openAsset(env, jAssets, jFile, AASSET_MODE_UNKNOWN);
294     ASSERT_NE(asset, nullptr);
295     AssetCloser assetCloser(asset, AAsset_close);
296 
297     AImageDecoder* decoder;
298     int result = AImageDecoder_createFromAAsset(asset, &decoder);
299     ASSERT_EQ(ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT, result);
300     ASSERT_EQ(decoder, nullptr);
301 }
302 
testSetFormat(JNIEnv * env,jclass,jlong imageDecoderPtr,jboolean isF16,jboolean isGray)303 static void testSetFormat(JNIEnv* env, jclass, jlong imageDecoderPtr,
304                           jboolean isF16, jboolean isGray) {
305     AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
306     DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
307 
308     const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
309     ASSERT_NE(info, nullptr);
310 
311     // Store the format so we can ensure that it doesn't change when we call
312     // AImageDecoder_setAndroidBitmapFormat.
313     const auto format = AImageDecoderHeaderInfo_getAndroidBitmapFormat(info);
314     if (isF16) {
315         ASSERT_EQ(ANDROID_BITMAP_FORMAT_RGBA_F16, format);
316     } else {
317         ASSERT_EQ(ANDROID_BITMAP_FORMAT_RGBA_8888, format);
318     }
319 
320     int result = AImageDecoder_setAndroidBitmapFormat(decoder, ANDROID_BITMAP_FORMAT_A_8);
321     if (isGray) {
322         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
323     } else {
324         ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_CONVERSION, result);
325     }
326     ASSERT_EQ(format, AImageDecoderHeaderInfo_getAndroidBitmapFormat(info));
327 
328     result = AImageDecoder_setAndroidBitmapFormat(decoder, ANDROID_BITMAP_FORMAT_RGB_565);
329     int alpha = AImageDecoderHeaderInfo_getAlphaFlags(info);
330     if (alpha == ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE) {
331         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
332     } else {
333         ASSERT_EQ(ANDROID_BITMAP_FLAGS_ALPHA_PREMUL, alpha);
334         ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_CONVERSION, result);
335     }
336     ASSERT_EQ(format, AImageDecoderHeaderInfo_getAndroidBitmapFormat(info));
337 
338     for (auto newFormat : { ANDROID_BITMAP_FORMAT_RGBA_4444, ANDROID_BITMAP_FORMAT_NONE }) {
339         result = AImageDecoder_setAndroidBitmapFormat(decoder, newFormat);
340         ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_CONVERSION, result);
341         ASSERT_EQ(format, AImageDecoderHeaderInfo_getAndroidBitmapFormat(info));
342     }
343 
344     for (auto newFormat : { ANDROID_BITMAP_FORMAT_RGBA_8888, ANDROID_BITMAP_FORMAT_RGBA_F16 }) {
345         result = AImageDecoder_setAndroidBitmapFormat(decoder, newFormat);
346         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
347         ASSERT_EQ(format, AImageDecoderHeaderInfo_getAndroidBitmapFormat(info));
348     }
349 
350     for (auto invalidFormat : { -1, 42, 67 }) {
351         result = AImageDecoder_setAndroidBitmapFormat(decoder, invalidFormat);
352         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
353         ASSERT_EQ(format, AImageDecoderHeaderInfo_getAndroidBitmapFormat(info));
354     }
355 }
356 
testSetUnpremul(JNIEnv * env,jclass,jlong imageDecoderPtr,jboolean hasAlpha)357 static void testSetUnpremul(JNIEnv* env, jclass, jlong imageDecoderPtr, jboolean hasAlpha) {
358     AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
359     DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
360 
361     const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
362     ASSERT_NE(info, nullptr);
363 
364     // Store the alpha so we can ensure that it doesn't change when we call
365     // AImageDecoder_setUnpremultipliedRequired.
366     const int alpha = AImageDecoderHeaderInfo_getAlphaFlags(info);
367     if (hasAlpha) {
368         ASSERT_EQ(ANDROID_BITMAP_FLAGS_ALPHA_PREMUL, alpha);
369     } else {
370         ASSERT_EQ(ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE, alpha);
371     }
372 
373     for (bool required : { true, false }) {
374         int result = AImageDecoder_setUnpremultipliedRequired(decoder, required);
375         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
376         ASSERT_EQ(alpha, AImageDecoderHeaderInfo_getAlphaFlags(info));
377     }
378 }
379 
bytesPerPixel(int32_t format)380 static int bytesPerPixel(int32_t format) {
381     switch (format) {
382         case ANDROID_BITMAP_FORMAT_RGBA_8888:
383             return 4;
384         case ANDROID_BITMAP_FORMAT_RGB_565:
385             return 2;
386         case ANDROID_BITMAP_FORMAT_A_8:
387             return 1;
388         case ANDROID_BITMAP_FORMAT_RGBA_F16:
389             return 8;
390         case ANDROID_BITMAP_FORMAT_NONE:
391         case ANDROID_BITMAP_FORMAT_RGBA_4444:
392         default:
393             return 0;
394     }
395 }
396 
testGetMinimumStride(JNIEnv * env,jclass,jlong imageDecoderPtr,jboolean isF16,jboolean isGray)397 static void testGetMinimumStride(JNIEnv* env, jclass, jlong imageDecoderPtr,
398                                  jboolean isF16, jboolean isGray) {
399     AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
400     DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
401 
402     const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
403     ASSERT_NE(info, nullptr);
404 
405     const int32_t width = AImageDecoderHeaderInfo_getWidth(info);
406     size_t stride = AImageDecoder_getMinimumStride(decoder);
407 
408     if (isF16) {
409         ASSERT_EQ(bytesPerPixel(ANDROID_BITMAP_FORMAT_RGBA_F16) * width, stride);
410     } else {
411         ASSERT_EQ(bytesPerPixel(ANDROID_BITMAP_FORMAT_RGBA_8888) * width, stride);
412     }
413 
414     auto setFormatAndCheckStride = [env, decoder, width, &stride](AndroidBitmapFormat format) {
415         int result = AImageDecoder_setAndroidBitmapFormat(decoder, format);
416         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
417 
418         stride = AImageDecoder_getMinimumStride(decoder);
419         ASSERT_EQ(bytesPerPixel(format) * width, stride);
420     };
421 
422     int alpha = AImageDecoderHeaderInfo_getAlphaFlags(info);
423     if (alpha == ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE) {
424         setFormatAndCheckStride(ANDROID_BITMAP_FORMAT_RGB_565);
425     }
426 
427     if (isGray) {
428         setFormatAndCheckStride(ANDROID_BITMAP_FORMAT_A_8);
429     }
430 
431     for (auto newFormat : { ANDROID_BITMAP_FORMAT_RGBA_8888, ANDROID_BITMAP_FORMAT_RGBA_F16 }) {
432         setFormatAndCheckStride(newFormat);
433     }
434 
435     for (auto badFormat : { ANDROID_BITMAP_FORMAT_RGBA_4444, ANDROID_BITMAP_FORMAT_NONE }) {
436         int result = AImageDecoder_setAndroidBitmapFormat(decoder, badFormat);
437         ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_CONVERSION, result);
438 
439         // Stride is unchanged.
440         ASSERT_EQ(stride, AImageDecoder_getMinimumStride(decoder));
441     }
442 }
443 
bitmapsEqual(size_t minStride,int height,void * pixelsA,size_t strideA,void * pixelsB,size_t strideB)444 static bool bitmapsEqual(size_t minStride, int height,
445                          void* pixelsA, size_t strideA,
446                          void* pixelsB, size_t strideB) {
447     for (int y = 0; y < height; ++y) {
448         auto* rowA = reinterpret_cast<char*>(pixelsA) + strideA * y;
449         auto* rowB = reinterpret_cast<char*>(pixelsB) + strideB * y;
450         if (memcmp(rowA, rowB, minStride) != 0) {
451             ALOGE("Bitmap mismatch on line %i", y);
452             return false;
453         }
454     }
455     return true;
456 }
457 
458 #define EXPECT_EQ(msg, a, b)    \
459     if ((a) != (b)) {           \
460         ALOGE(msg);             \
461         return false;           \
462     }
463 
464 #define EXPECT_GE(msg, a, b)    \
465     if ((a) < (b)) {            \
466         ALOGE(msg);             \
467         return false;           \
468     }
469 
bitmapsEqual(JNIEnv * env,jobject jbitmap,int32_t androidBitmapFormat,int width,int height,int alphaFlags,size_t minStride,void * pixelsA,size_t strideA)470 static bool bitmapsEqual(JNIEnv* env, jobject jbitmap, int32_t androidBitmapFormat,
471                          int width, int height, int alphaFlags, size_t minStride,
472                          void* pixelsA, size_t strideA) {
473     AndroidBitmapInfo jInfo;
474     int bitmapResult = AndroidBitmap_getInfo(env, jbitmap, &jInfo);
475     EXPECT_EQ("Failed to getInfo on Bitmap", ANDROID_BITMAP_RESULT_SUCCESS, bitmapResult);
476 
477     EXPECT_EQ("Wrong format", jInfo.format, androidBitmapFormat);
478 
479     // If the image is truly opaque, the Java Bitmap will report OPAQUE, even if
480     // the AImageDecoder requested PREMUL/UNPREMUL. In that case, it is okay for
481     // the two to disagree. We must ensure that we don't end up with one PREMUL
482     // and the other UNPREMUL, though.
483     int jAlphaFlags = jInfo.flags & ANDROID_BITMAP_FLAGS_ALPHA_MASK;
484     if (jAlphaFlags != ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE
485             && alphaFlags != ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE) {
486         EXPECT_EQ("Wrong alpha type", jAlphaFlags, alphaFlags);
487     }
488 
489     EXPECT_EQ("Wrong width", jInfo.width, width);
490     EXPECT_EQ("Wrong height", jInfo.height, height);
491 
492     EXPECT_GE("Stride too small", jInfo.stride, minStride);
493 
494     void* jPixels;
495     bitmapResult = AndroidBitmap_lockPixels(env, jbitmap, &jPixels);
496     EXPECT_EQ("Failed to lockPixels", ANDROID_BITMAP_RESULT_SUCCESS, bitmapResult);
497 
498     bool equal = bitmapsEqual(minStride, height, pixelsA, strideA, jPixels, jInfo.stride);
499 
500     bitmapResult = AndroidBitmap_unlockPixels(env, jbitmap);
501     EXPECT_EQ("Failed to unlockPixels", ANDROID_BITMAP_RESULT_SUCCESS, bitmapResult);
502 
503     return equal;
504 }
505 
testDecode(JNIEnv * env,jclass,jlong imageDecoderPtr,jint androidBitmapFormat,jboolean unpremul,jobject jbitmap)506 static void testDecode(JNIEnv* env, jclass, jlong imageDecoderPtr,
507                        jint androidBitmapFormat, jboolean unpremul, jobject jbitmap) {
508     AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
509     DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
510 
511     const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
512     ASSERT_NE(info, nullptr);
513 
514     int result;
515     int alphaFlags = AImageDecoderHeaderInfo_getAlphaFlags(info);
516     if (androidBitmapFormat == ANDROID_BITMAP_FORMAT_NONE) {
517         androidBitmapFormat = AImageDecoderHeaderInfo_getAndroidBitmapFormat(info);
518     } else {
519         result = AImageDecoder_setAndroidBitmapFormat(decoder, androidBitmapFormat);
520         if (androidBitmapFormat == ANDROID_BITMAP_FORMAT_RGB_565) {
521             if (alphaFlags != ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE) {
522                 ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_CONVERSION, result);
523 
524                 // The caller only passes down the Bitmap if it is opaque.
525                 ASSERT_EQ(nullptr, jbitmap);
526                 return;
527             }
528         }
529         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
530     }
531 
532     if (unpremul) {
533         result = AImageDecoder_setUnpremultipliedRequired(decoder, true);
534         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
535         alphaFlags = ANDROID_BITMAP_FLAGS_ALPHA_UNPREMUL;
536     }
537 
538     const int32_t width = AImageDecoderHeaderInfo_getWidth(info);
539     const int32_t height = AImageDecoderHeaderInfo_getHeight(info);
540     size_t minStride = AImageDecoder_getMinimumStride(decoder);
541 
542     size_t size = minStride * height;
543     void* pixels = malloc(size);
544 
545     {
546         // Try some invalid parameters.
547 #pragma clang diagnostic push
548 #pragma clang diagnostic ignored "-Wnonnull"
549         result = AImageDecoder_decodeImage(decoder, nullptr, minStride, size);
550         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
551 #pragma clang diagnostic pop
552 
553         result = AImageDecoder_decodeImage(decoder, pixels, minStride - 1, size);
554         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
555 
556         result = AImageDecoder_decodeImage(decoder, pixels, minStride, size - minStride);
557         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
558 
559         result = AImageDecoder_decodeImage(decoder, pixels, 0, size);
560         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
561     }
562 
563     result = AImageDecoder_decodeImage(decoder, pixels, minStride, size);
564     ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
565 
566     ASSERT_NE(jbitmap, nullptr);
567     ASSERT_TRUE(bitmapsEqual(env, jbitmap, (AndroidBitmapFormat) androidBitmapFormat,
568                              width, height, alphaFlags, minStride, pixels, minStride));
569 
570     // Setting to an invalid data space is unsupported, and has no effect on the
571     // decodes below.
572     for (int32_t dataSpace : std::initializer_list<int32_t>{ -1, ADATASPACE_UNKNOWN, 400 }) {
573         result = AImageDecoder_setDataSpace(decoder, dataSpace);
574         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
575     }
576 
577     // Used for subsequent decodes, to ensure they are identical to the
578     // original. For opaque images, this verifies that using PREMUL or UNPREMUL
579     // look the same. For all images, this verifies that decodeImage can be
580     // called multiple times.
581     auto decodeAgain = [=](bool unpremultipliedRequired) {
582         int r = AImageDecoder_setUnpremultipliedRequired(decoder, unpremultipliedRequired);
583         if (ANDROID_IMAGE_DECODER_SUCCESS != r) {
584             fail(env, "Failed to set alpha");
585             return false;
586         }
587 
588         void* otherPixels = malloc(size);
589         r = AImageDecoder_decodeImage(decoder, otherPixels, minStride, size);
590         if (ANDROID_IMAGE_DECODER_SUCCESS != r) {
591             fail(env, "Failed to decode again with different settings");
592             return false;
593         }
594 
595         if (!bitmapsEqual(minStride, height, pixels, minStride, otherPixels, minStride)) {
596             free(otherPixels);
597             fail(env, "Decoding again with different settings did not match!");
598             return false;
599         }
600         free(otherPixels);
601         return true;
602     };
603     if (alphaFlags == ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE) {
604         for (bool unpremultipliedRequired: { true, false }) {
605             if (!decodeAgain(unpremultipliedRequired)) return;
606         }
607     } else {
608         if (!decodeAgain(unpremul)) return;
609     }
610 
611     if (androidBitmapFormat == ANDROID_BITMAP_FORMAT_A_8) {
612         // Attempting to set an ADataSpace is ignored by an A_8 decode.
613         for (ADataSpace dataSpace : { ADATASPACE_DCI_P3, ADATASPACE_ADOBE_RGB }) {
614             result = AImageDecoder_setDataSpace(decoder, dataSpace);
615             ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
616             if (!decodeAgain(alphaFlags)) return;
617         }
618     }
619 
620     free(pixels);
621 }
622 
testDecodeStride(JNIEnv * env,jclass,jlong imageDecoderPtr)623 static void testDecodeStride(JNIEnv* env, jclass, jlong imageDecoderPtr) {
624     AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
625     DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
626 
627     const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
628     ASSERT_NE(info, nullptr);
629 
630     const int height = AImageDecoderHeaderInfo_getHeight(info);
631     const int origWidth = AImageDecoderHeaderInfo_getWidth(info);
632 
633     for (int width : { origWidth, origWidth / 3 }) {
634         if (width == 0) {
635             // The 1 x 1 image cannot be downscaled.
636             continue;
637         }
638         int result = AImageDecoder_setTargetSize(decoder, width, height);
639         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
640         for (AndroidBitmapFormat format : {
641             ANDROID_BITMAP_FORMAT_RGBA_8888,
642             ANDROID_BITMAP_FORMAT_RGB_565,
643             ANDROID_BITMAP_FORMAT_A_8,
644             ANDROID_BITMAP_FORMAT_RGBA_F16,
645         }) {
646             result = AImageDecoder_setAndroidBitmapFormat(decoder, format);
647             if (result != ANDROID_IMAGE_DECODER_SUCCESS) {
648                 // Not all images can be decoded to all formats. This is okay, and
649                 // we've tested that we can decode to the expected formats elsewhere.
650                 continue;
651             }
652 
653             size_t minStride = AImageDecoder_getMinimumStride(decoder);
654             void* pixels = nullptr;
655 
656             // The code in the below loop relies on minStride being used first.
657             std::vector<size_t> strides;
658             strides.push_back(minStride);
659             for (int i = 1; i <= 16; i++) {
660                 strides.push_back(i + minStride);
661             }
662             strides.push_back(minStride * 2);
663             strides.push_back(minStride * 3);
664             for (size_t stride : strides) {
665                 size_t size = stride * (height - 1) + minStride;
666                 void* decodePixels = malloc(size);
667                 result = AImageDecoder_decodeImage(decoder, decodePixels, stride, size);
668                 if ((stride - minStride) % bytesPerPixel(format) != 0) {
669                     // The stride is not pixel aligned.
670                     ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
671                     continue;
672                 }
673                 ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
674 
675                 if (pixels == nullptr) {
676                     pixels = decodePixels;
677                 } else {
678                     ASSERT_TRUE(bitmapsEqual(minStride, height, pixels, minStride, decodePixels,
679                                              stride));
680                     free(decodePixels);
681                 }
682             }
683 
684             free(pixels);
685         }
686     }
687 }
688 
testSetTargetSize(JNIEnv * env,jclass,jlong imageDecoderPtr)689 static void testSetTargetSize(JNIEnv* env, jclass, jlong imageDecoderPtr) {
690     AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
691     DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
692 
693     const size_t defaultStride = AImageDecoder_getMinimumStride(decoder);
694 
695     for (int32_t width : { -1, 0, -500 }) {
696         int result = AImageDecoder_setTargetSize(decoder, width, 100);
697         ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_SCALE, result);
698         // stride is unchanged, as the target size did not change.
699         ASSERT_EQ(defaultStride, AImageDecoder_getMinimumStride(decoder));
700     }
701 
702     for (int32_t height : { -1, 0, -300 }) {
703         int result = AImageDecoder_setTargetSize(decoder, 100, height);
704         ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_SCALE, result);
705         // stride is unchanged, as the target size did not change.
706         ASSERT_EQ(defaultStride, AImageDecoder_getMinimumStride(decoder));
707     }
708 
709     const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
710     ASSERT_NE(info, nullptr);
711     const int bpp = bytesPerPixel(AImageDecoderHeaderInfo_getAndroidBitmapFormat(info));
712 
713     for (int32_t width : { 7, 100, 275, 300 }) {
714         int result = AImageDecoder_setTargetSize(decoder, width, 100);
715         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
716 
717         size_t actualStride = AImageDecoder_getMinimumStride(decoder);
718         size_t expectedStride = bpp * width;
719         ASSERT_EQ(expectedStride, actualStride);
720     }
721 
722     // Verify that setting a large enough width to overflow 31 bits fails.
723     constexpr auto kMaxInt32 = std::numeric_limits<int32_t>::max();
724     int32_t maxWidth = kMaxInt32 / bpp;
725     for (int32_t width : { maxWidth / 2, maxWidth - 1, maxWidth }) {
726         int result = AImageDecoder_setTargetSize(decoder, width, 1);
727         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
728 
729         size_t actualStride = AImageDecoder_getMinimumStride(decoder);
730         size_t expectedStride = bpp * width;
731         ASSERT_EQ(expectedStride, actualStride);
732     }
733 
734     for (int32_t width : { maxWidth + 1, (int32_t) (maxWidth * 1.5) }) {
735         int result = AImageDecoder_setTargetSize(decoder, width, 1);
736         ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_SCALE, result);
737     }
738 
739     // A height that results in overflowing 31 bits also fails.
740     int32_t maxHeight = kMaxInt32 / defaultStride;
741     const int32_t width = AImageDecoderHeaderInfo_getWidth(info);
742     for (int32_t height : { maxHeight / 2, maxHeight - 1, maxHeight }) {
743         int result = AImageDecoder_setTargetSize(decoder, width, height);
744         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
745 
746         size_t actualStride = AImageDecoder_getMinimumStride(decoder);
747         size_t expectedStride = bpp * width;
748         ASSERT_EQ(expectedStride, actualStride);
749     }
750 
751     for (int32_t height : { maxHeight + 1, (int32_t) (maxHeight * 1.5) }) {
752         int result = AImageDecoder_setTargetSize(decoder, width, height);
753         ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_SCALE, result);
754     }
755 }
756 
757 struct SampledSizeParams {
758     AImageDecoder* decoder;
759     int sampleSize;
760     int32_t* width;
761     int32_t* height;
762 };
763 
testComputeSampledSize(JNIEnv * env,jclass,jlong imageDecoderPtr,jobject jbitmap,jint sampleSize)764 static void testComputeSampledSize(JNIEnv* env, jclass, jlong imageDecoderPtr,
765                                    jobject jbitmap, jint sampleSize) {
766     AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
767     DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
768 
769     const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
770     ASSERT_NE(info, nullptr);
771     const int32_t origWidth = AImageDecoderHeaderInfo_getWidth(info);
772     const int32_t origHeight = AImageDecoderHeaderInfo_getHeight(info);
773 
774     int32_t width, height;
775     // Test some bad parameters.
776     for (SampledSizeParams p : std::initializer_list<SampledSizeParams>{
777         { nullptr, 2, &width, &height },
778         { decoder, 0, &width, &height },
779         { decoder, -1, &width, &height },
780         { decoder, 2, nullptr, &height },
781         { decoder, 2, &width, nullptr },
782     }) {
783         int result = AImageDecoder_computeSampledSize(p.decoder, p.sampleSize, p.width, p.height);
784         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
785     }
786 
787     // Verify that width and height will never be less than one.
788     for (SampledSizeParams p : std::initializer_list<SampledSizeParams>{
789         { decoder, origWidth, &width, &height },
790         { decoder, origWidth + 5, &width, &height },
791         { decoder, origWidth * 2, &width, &height },
792         { decoder, origHeight, &width, &height },
793         { decoder, origHeight + 5, &width, &height },
794         { decoder, origHeight * 2, &width, &height },
795     }) {
796         width = height = 0;
797         int result = AImageDecoder_computeSampledSize(p.decoder, p.sampleSize, p.width, p.height);
798         if (ANDROID_IMAGE_DECODER_SUCCESS != result) {
799             fail(env, "computeSampledSize(%i) failed on image with dims %i x %i",
800                  p.sampleSize, origWidth, origHeight);
801             return;
802         }
803 
804         ASSERT_GE(width, 1);
805         ASSERT_GE(height, 1);
806     }
807 
808     // jbitmap was created with the same sampleSize. Verify that AImageDecoder
809     // computes the same output dimensions, that using those dimensions succeeds
810     // with AImageDecoder, and the output matches.
811     AndroidBitmapInfo jInfo;
812     int bitmapResult = AndroidBitmap_getInfo(env, jbitmap, &jInfo);
813     ASSERT_EQ(ANDROID_BITMAP_RESULT_SUCCESS, bitmapResult);
814 
815     width = height = 0;
816     int result = AImageDecoder_computeSampledSize(decoder, sampleSize, &width, &height);
817     ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
818 
819     if (jInfo.width != width) {
820         fail(env, "Orig image: %i x %i sampled by %i yields %i x %i expected %i x %i",
821              origWidth, origHeight, sampleSize, width, height, jInfo.width, jInfo.height);
822         return;
823     }
824     ASSERT_EQ(jInfo.width, width);
825     ASSERT_EQ(jInfo.height, height);
826     {
827 
828         ASSERT_LT(width, origWidth);
829         ASSERT_LT(height, origHeight);
830 
831         ASSERT_LT(width, origWidth / sampleSize + sampleSize);
832         ASSERT_LT(height, origHeight / sampleSize + sampleSize);
833     }
834 
835     result = AImageDecoder_setTargetSize(decoder, width, height);
836     ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
837 
838     size_t minStride = AImageDecoder_getMinimumStride(decoder);
839     size_t size = minStride * height;
840     void* pixels = malloc(size);
841     result = AImageDecoder_decodeImage(decoder, pixels, minStride, size);
842     ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
843 
844     ASSERT_TRUE(bitmapsEqual(env, jbitmap, AImageDecoderHeaderInfo_getAndroidBitmapFormat(info),
845                              width, height, AImageDecoderHeaderInfo_getAlphaFlags(info),
846                              minStride, pixels, minStride));
847     free(pixels);
848 }
849 
testDecodeScaled(JNIEnv * env,jclass,jlong imageDecoderPtr,jobject jbitmap)850 static void testDecodeScaled(JNIEnv* env, jclass, jlong imageDecoderPtr,
851                              jobject jbitmap) {
852     AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
853     DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
854 
855     AndroidBitmapInfo jInfo;
856     int bitmapResult = AndroidBitmap_getInfo(env, jbitmap, &jInfo);
857     ASSERT_EQ(ANDROID_BITMAP_RESULT_SUCCESS, bitmapResult);
858 
859     int result = AImageDecoder_setTargetSize(decoder, jInfo.width, jInfo.height);
860     ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
861 
862     size_t minStride = AImageDecoder_getMinimumStride(decoder);
863     size_t size = minStride * jInfo.height;
864     void* pixels = malloc(size);
865 
866     {
867         // Try some invalid parameters.
868 #pragma clang diagnostic push
869 #pragma clang diagnostic ignored "-Wnonnull"
870         result = AImageDecoder_decodeImage(decoder, nullptr, minStride, size);
871         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
872 #pragma clang diagnostic pop
873 
874         result = AImageDecoder_decodeImage(decoder, pixels, minStride - 1, size);
875         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
876 
877         result = AImageDecoder_decodeImage(decoder, pixels, minStride, size - minStride);
878         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
879     }
880 
881     result = AImageDecoder_decodeImage(decoder, pixels, minStride, size);
882     ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
883 
884     const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
885     ASSERT_NE(info, nullptr);
886 
887     ASSERT_NE(jbitmap, nullptr);
888     ASSERT_TRUE(bitmapsEqual(env, jbitmap, AImageDecoderHeaderInfo_getAndroidBitmapFormat(info),
889                              jInfo.width, jInfo.height, AImageDecoderHeaderInfo_getAlphaFlags(info),
890                              minStride, pixels, minStride));
891 
892     // Verify that larger strides still behave as expected.
893     for (size_t stride : { minStride * 2, minStride * 3 }) {
894         size_t size = stride * (jInfo.height - 1) + minStride;
895         void* decodePixels = malloc(size);
896         result = AImageDecoder_decodeImage(decoder, decodePixels, stride, size);
897         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
898 
899         ASSERT_TRUE(bitmapsEqual(minStride, jInfo.height, pixels, minStride, decodePixels, stride));
900         free(decodePixels);
901     }
902 
903     free(pixels);
904 }
905 
testSetCrop(JNIEnv * env,jclass,jobject jAssets,jstring jFile)906 static void testSetCrop(JNIEnv* env, jclass, jobject jAssets, jstring jFile) {
907     AAsset* asset = openAsset(env, jAssets, jFile, AASSET_MODE_UNKNOWN);
908     ASSERT_NE(asset, nullptr);
909     AssetCloser assetCloser(asset, AAsset_close);
910 
911     AImageDecoder* decoder;
912     int result = AImageDecoder_createFromAAsset(asset, &decoder);
913     ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
914     ASSERT_NE(decoder, nullptr);
915     DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
916 
917     const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
918     ASSERT_NE(info, nullptr);
919 
920     const int32_t width = AImageDecoderHeaderInfo_getWidth(info);
921     const int32_t height = AImageDecoderHeaderInfo_getHeight(info);
922     const auto format = AImageDecoderHeaderInfo_getAndroidBitmapFormat(info);
923     const size_t defaultStride = AImageDecoder_getMinimumStride(decoder);
924 
925     if (width == 1 && height == 1) {
926         // The more general crop tests do not map well to this image. Test 1 x 1
927         // specifically.
928         for (ARect invalidCrop : std::initializer_list<ARect> {
929                 { -1, 0, width, height },
930                 { 0, -1, width, height },
931                 { width, 0, 2 * width, height },
932                 { 0, height, width, 2 * height },
933                 { 1, 0, width + 1, height },
934                 { 0, 1, width, height + 1 },
935                 { 0, 0, 0, height },
936                 { 0, 0, width, 0 },
937         }) {
938             int result = AImageDecoder_setCrop(decoder, invalidCrop);
939             ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
940             ASSERT_EQ(defaultStride, AImageDecoder_getMinimumStride(decoder));
941         }
942         return;
943     }
944 
945     for (ARect invalidCrop : std::initializer_list<ARect> {
946             { -1, 0, width, height },
947             { 0, -1, width, height },
948             { width, 0, 2 * width, height },
949             { 0, height, width, 2 * height },
950             { 1, 0, width + 1, height },
951             { 0, 1, width, height + 1 },
952             { width - 1, 0, 1, height },
953             { 0, height - 1, width, 1 },
954             { 0, 0, 0, height },
955             { 0, 0, width, 0 },
956             { 1, 1, 1, 1 },
957             { width, height, 0, 0 },
958     }) {
959         int result = AImageDecoder_setCrop(decoder, invalidCrop);
960         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
961         ASSERT_EQ(defaultStride, AImageDecoder_getMinimumStride(decoder));
962     }
963 
964     for (ARect validCrop : std::initializer_list<ARect> {
965             { 0, 0, width, height },
966             { 0, 0, width / 2, height / 2},
967             { 0, 0, width / 3, height },
968             { 0, 0, width, height / 4},
969             { width / 2, 0, width, height / 2},
970             { 0, height / 2, width / 2, height },
971             { width / 2, height / 2, width, height },
972             { 1, 1, width - 1, height - 1 },
973     }) {
974         int result = AImageDecoder_setCrop(decoder, validCrop);
975         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
976         size_t actualStride = AImageDecoder_getMinimumStride(decoder);
977         size_t expectedStride = bytesPerPixel(format) * (validCrop.right - validCrop.left);
978         ASSERT_EQ(expectedStride, actualStride);
979     }
980 
981     // Reset the crop, so we can test setting a crop *after* changing the
982     // target size.
983     result = AImageDecoder_setCrop(decoder, { 0, 0, 0, 0 });
984     ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
985     ASSERT_EQ(defaultStride, AImageDecoder_getMinimumStride(decoder));
986 
987     int32_t newWidth = width / 2, newHeight = height / 2;
988     result = AImageDecoder_setTargetSize(decoder, newWidth, newHeight);
989     ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
990     const size_t halfStride = AImageDecoder_getMinimumStride(decoder);
991     {
992         size_t expectedStride = bytesPerPixel(format) * newWidth;
993         ASSERT_EQ(expectedStride, halfStride);
994     }
995 
996     // At the smaller target size, crops that were previously valid no longer
997     // are.
998     for (ARect invalidCrop : std::initializer_list<ARect> {
999             { 0, 0, width / 3, height },
1000             { 0, 0, width, height / 4},
1001             { width / 2, 0, width, height / 2},
1002             { 0, height / 2, width / 2, height },
1003             { width / 2, height / 2, width, height },
1004             { 1, 1, width - 1, height - 1 },
1005     }) {
1006         int result = AImageDecoder_setCrop(decoder, invalidCrop);
1007         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
1008         ASSERT_EQ(halfStride, AImageDecoder_getMinimumStride(decoder));
1009     }
1010 
1011     for (ARect validCrop : std::initializer_list<ARect> {
1012             { 0, 0, newWidth, newHeight },
1013             { 0, 0, newWidth / 3, newHeight },
1014             { 0, 0, newWidth, newHeight / 4},
1015             { newWidth / 2, 0, newWidth, newHeight / 2},
1016             { 0, newHeight / 2, newWidth / 2, newHeight },
1017             { newWidth / 2, newHeight / 2, newWidth, newHeight },
1018             { 1, 1, newWidth - 1, newHeight - 1 },
1019     }) {
1020         int result = AImageDecoder_setCrop(decoder, validCrop);
1021         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1022         size_t actualStride = AImageDecoder_getMinimumStride(decoder);
1023         size_t expectedStride = bytesPerPixel(format) * (validCrop.right - validCrop.left);
1024         ASSERT_EQ(expectedStride, actualStride);
1025     }
1026 
1027     newWidth = width * 2;
1028     newHeight = height * 2;
1029     result = AImageDecoder_setTargetSize(decoder, newWidth, newHeight);
1030     ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1031 
1032     for (ARect validCrop : std::initializer_list<ARect> {
1033             { width, 0, newWidth, height },
1034             { 0, height * 3 / 4, width * 4 / 3, height }
1035     }) {
1036         int result = AImageDecoder_setCrop(decoder, validCrop);
1037         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1038         size_t actualStride = AImageDecoder_getMinimumStride(decoder);
1039         size_t expectedStride = bytesPerPixel(format) * (validCrop.right - validCrop.left);
1040         ASSERT_EQ(expectedStride, actualStride);
1041     }
1042 
1043     // Reset crop and target size, so that we can verify that setting a crop and
1044     // then setting target size that will not support the crop fails.
1045     result = AImageDecoder_setCrop(decoder, { 0, 0, 0, 0 });
1046     ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1047     result = AImageDecoder_setTargetSize(decoder, width, height);
1048     ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1049     ASSERT_EQ(defaultStride, AImageDecoder_getMinimumStride(decoder));
1050 
1051     ARect crop{ width / 2, height / 2, width, height };
1052     result = AImageDecoder_setCrop(decoder, crop);
1053     ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1054     const size_t croppedStride = AImageDecoder_getMinimumStride(decoder);
1055     {
1056         size_t expectedStride = bytesPerPixel(format) * (crop.right - crop.left);
1057         ASSERT_EQ(expectedStride, croppedStride);
1058     }
1059     result = AImageDecoder_setTargetSize(decoder, width / 2, height / 2);
1060     ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_SCALE, result);
1061     ASSERT_EQ(croppedStride, AImageDecoder_getMinimumStride(decoder));
1062 }
1063 
testDecodeCrop(JNIEnv * env,jclass,jlong imageDecoderPtr,jobject jbitmap,jint targetWidth,jint targetHeight,jint left,jint top,jint right,jint bottom)1064 static void testDecodeCrop(JNIEnv* env, jclass, jlong imageDecoderPtr,
1065                            jobject jbitmap, jint targetWidth, jint targetHeight,
1066                            jint left, jint top, jint right, jint bottom) {
1067     AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
1068     DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
1069 
1070     int result;
1071     if (targetWidth != 0 && targetHeight != 0) {
1072         result = AImageDecoder_setTargetSize(decoder, targetWidth, targetHeight);
1073         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1074     }
1075 
1076     ARect rect { left, top, right, bottom };
1077     result = AImageDecoder_setCrop(decoder, rect);
1078     ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1079 
1080     const int32_t width = right - left;
1081     const int32_t height = bottom - top;
1082     size_t minStride = AImageDecoder_getMinimumStride(decoder);
1083     size_t size = minStride * height;
1084     void* pixels = malloc(size);
1085 
1086     {
1087         // Try some invalid parameters.
1088 #pragma clang diagnostic push
1089 #pragma clang diagnostic ignored "-Wnonnull"
1090         result = AImageDecoder_decodeImage(decoder, nullptr, minStride, size);
1091         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
1092 #pragma clang diagnostic pop
1093 
1094         result = AImageDecoder_decodeImage(decoder, pixels, minStride - 1, size);
1095         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
1096 
1097         result = AImageDecoder_decodeImage(decoder, pixels, minStride, size - minStride);
1098         ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
1099     }
1100 
1101     result = AImageDecoder_decodeImage(decoder, pixels, minStride, size);
1102     ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1103 
1104     const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
1105     ASSERT_NE(info, nullptr);
1106 
1107     ASSERT_NE(jbitmap, nullptr);
1108     ASSERT_TRUE(bitmapsEqual(env, jbitmap, AImageDecoderHeaderInfo_getAndroidBitmapFormat(info),
1109                              width, height, AImageDecoderHeaderInfo_getAlphaFlags(info),
1110                              minStride, pixels, minStride));
1111 
1112     // Verify that larger strides still behave as expected.
1113     for (size_t stride : { minStride * 2, minStride * 3 }) {
1114         size_t size = stride * (height - 1) + minStride;
1115         void* decodePixels = malloc(size);
1116         result = AImageDecoder_decodeImage(decoder, decodePixels, stride, size);
1117         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1118 
1119         ASSERT_TRUE(bitmapsEqual(minStride, height, pixels, minStride, decodePixels, stride));
1120         free(decodePixels);
1121     }
1122 
1123     free(pixels);
1124 }
1125 
testScalePlusUnpremul(JNIEnv * env,jclass,jlong imageDecoderPtr)1126 static void testScalePlusUnpremul(JNIEnv* env, jclass, jlong imageDecoderPtr) {
1127     AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
1128     DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
1129 
1130     const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
1131     ASSERT_NE(nullptr, info);
1132 
1133     const int32_t width = AImageDecoderHeaderInfo_getWidth(info);
1134     const int32_t height = AImageDecoderHeaderInfo_getHeight(info);
1135     const int alpha = AImageDecoderHeaderInfo_getAlphaFlags(info);
1136 
1137     if (alpha == ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE) {
1138         // Set unpremul, then scale. This succeeds for an opaque image.
1139         int result = AImageDecoder_setUnpremultipliedRequired(decoder, true);
1140         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1141 
1142         result = AImageDecoder_setTargetSize(decoder, width * 2, height * 2);
1143         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1144 
1145         result = AImageDecoder_setTargetSize(decoder, width * 2/3, height * 2/3);
1146         if (width * 2/3 == 0 || height * 2/3 == 0) {
1147             // The image that is 1x1 cannot be downscaled.
1148             ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_SCALE, result);
1149         } else {
1150             ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1151         }
1152 
1153         // Reset to the original settings to test the other order.
1154         result = AImageDecoder_setUnpremultipliedRequired(decoder, false);
1155         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1156 
1157         result = AImageDecoder_setTargetSize(decoder, width, height);
1158         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1159 
1160         // Specify scale and then unpremul.
1161         if (width * 2/3 == 0 || height * 2/3 == 0) {
1162             // The image that is 1x1 cannot be downscaled. Scale up instead.
1163             result = AImageDecoder_setTargetSize(decoder, width * 2, height * 2);
1164         } else {
1165             result = AImageDecoder_setTargetSize(decoder, width * 2/3, height * 2/3);
1166         }
1167         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1168 
1169         result = AImageDecoder_setUnpremultipliedRequired(decoder, true);
1170         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1171     } else {
1172         // Use unpremul and then scale. Setting to unpremul is successful, but
1173         // later calls to change the scale fail.
1174         int result = AImageDecoder_setUnpremultipliedRequired(decoder, true);
1175         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1176 
1177         result = AImageDecoder_setTargetSize(decoder, width * 2, height * 2);
1178         ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_SCALE, result);
1179 
1180         result = AImageDecoder_setTargetSize(decoder, width * 2/3, height * 2/3);
1181         ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_SCALE, result);
1182 
1183         // Set back to premul to verify that the opposite order also fails.
1184         result = AImageDecoder_setUnpremultipliedRequired(decoder, false);
1185         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1186 
1187         result = AImageDecoder_setTargetSize(decoder, width * 2, height * 2);
1188         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1189         result = AImageDecoder_setUnpremultipliedRequired(decoder, true);
1190         ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_CONVERSION, result);
1191 
1192         result = AImageDecoder_setTargetSize(decoder, width * 2/3, height * 2/3);
1193         ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1194         result = AImageDecoder_setUnpremultipliedRequired(decoder, true);
1195         ASSERT_EQ(ANDROID_IMAGE_DECODER_INVALID_CONVERSION, result);
1196     }
1197 }
1198 
testDecodeSetDataSpace(JNIEnv * env,jclass,jlong imageDecoderPtr,jobject jbitmap,jint dataSpace)1199 static void testDecodeSetDataSpace(JNIEnv* env, jclass, jlong imageDecoderPtr,
1200                                    jobject jbitmap, jint dataSpace) {
1201     AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
1202     DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
1203 
1204     ASSERT_EQ(dataSpace, AndroidBitmap_getDataSpace(env, jbitmap));
1205 
1206     int result = AImageDecoder_setDataSpace(decoder, dataSpace);
1207     ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1208 
1209     AndroidBitmapInfo jInfo;
1210     int bitmapResult = AndroidBitmap_getInfo(env, jbitmap, &jInfo);
1211     ASSERT_EQ(ANDROID_BITMAP_RESULT_SUCCESS, bitmapResult);
1212 
1213     result = AImageDecoder_setAndroidBitmapFormat(decoder, jInfo.format);
1214     ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1215 
1216     const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder);
1217     ASSERT_NE(info, nullptr);
1218 
1219     const int32_t width = AImageDecoderHeaderInfo_getWidth(info);
1220     const int32_t height = AImageDecoderHeaderInfo_getHeight(info);
1221     int alphaFlags = AImageDecoderHeaderInfo_getAlphaFlags(info);
1222 
1223     size_t minStride = AImageDecoder_getMinimumStride(decoder);
1224     size_t size = minStride * height;
1225     void* pixels = malloc(size);
1226 
1227     result = AImageDecoder_decodeImage(decoder, pixels, minStride, size);
1228     ASSERT_EQ(ANDROID_IMAGE_DECODER_SUCCESS, result);
1229 
1230     ASSERT_TRUE(bitmapsEqual(env, jbitmap, (AndroidBitmapFormat) jInfo.format,
1231                              width, height, alphaFlags, minStride, pixels, minStride));
1232     free(pixels);
1233 }
1234 
testIsAnimated(JNIEnv * env,jclass,jlong imageDecoderPtr,jboolean animated)1235 static void testIsAnimated(JNIEnv* env, jclass, jlong imageDecoderPtr, jboolean animated) {
1236     AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
1237     DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
1238 
1239     ASSERT_TRUE(decoder);
1240     ASSERT_EQ(animated, AImageDecoder_isAnimated(decoder));
1241 }
1242 
testRepeatCount(JNIEnv * env,jclass,jlong imageDecoderPtr,jint repeatCount)1243 static void testRepeatCount(JNIEnv* env, jclass, jlong imageDecoderPtr, jint repeatCount) {
1244     AImageDecoder* decoder = reinterpret_cast<AImageDecoder*>(imageDecoderPtr);
1245     DecoderDeleter decoderDeleter(decoder, AImageDecoder_delete);
1246 
1247     if (repeatCount == -1) { // AnimatedImageDrawable.REPEAT_INFINITE
1248         repeatCount = ANDROID_IMAGE_DECODER_INFINITE;
1249     }
1250 
1251     ASSERT_TRUE(decoder);
1252     ASSERT_EQ(repeatCount, AImageDecoder_getRepeatCount(decoder));
1253 }
1254 
1255 #define ASSET_MANAGER "Landroid/content/res/AssetManager;"
1256 #define STRING "Ljava/lang/String;"
1257 #define BITMAP "Landroid/graphics/Bitmap;"
1258 
1259 static JNINativeMethod gMethods[] = {
1260     { "nTestEmptyCreate", "()V", (void*) testEmptyCreate },
1261     { "nTestNullDecoder", "(" ASSET_MANAGER STRING ")V", (void*) testNullDecoder },
1262     { "nTestInfo", "(JII" STRING "ZI)V", (void*) testInfo },
1263     { "nOpenAsset", "(" ASSET_MANAGER STRING ")J", (void*) openAssetNative },
1264     { "nCloseAsset", "(J)V", (void*) closeAsset },
1265     { "nCreateFromAsset", "(J)J", (void*) createFromAsset },
1266     { "nCreateFromAssetFd", "(J)J", (void*) createFromAssetFd },
1267     { "nCreateFromAssetBuffer", "(J)J", (void*) createFromAssetBuffer },
1268     { "nCreateFromFd", "(I)J", (void*) createFromFd },
1269     { "nTestCreateIncomplete", "(" ASSET_MANAGER STRING "I)V", (void*) testCreateIncomplete },
1270     { "nTestCreateUnsupported", "(" ASSET_MANAGER STRING ")V", (void*) testCreateUnsupported },
1271     { "nTestSetFormat", "(JZZ)V", (void*) testSetFormat },
1272     { "nTestSetUnpremul", "(JZ)V", (void*) testSetUnpremul },
1273     { "nTestGetMinimumStride", "(JZZ)V", (void*) testGetMinimumStride },
1274     { "nTestDecode", "(JIZ" BITMAP ")V", (void*) testDecode },
1275     { "nTestDecodeStride", "(J)V", (void*) testDecodeStride },
1276     { "nTestSetTargetSize", "(J)V", (void*) testSetTargetSize },
1277     { "nTestComputeSampledSize", "(J" BITMAP "I)V", (void*) testComputeSampledSize },
1278     { "nTestDecodeScaled", "(J" BITMAP ")V", (void*) testDecodeScaled },
1279     { "nTestSetCrop", "(" ASSET_MANAGER STRING ")V", (void*) testSetCrop },
1280     { "nTestDecodeCrop", "(J" BITMAP "IIIIII)V", (void*) testDecodeCrop },
1281     { "nTestScalePlusUnpremul", "(J)V", (void*) testScalePlusUnpremul },
1282     { "nTestDecode", "(J" BITMAP "I)V", (void*) testDecodeSetDataSpace },
1283     { "nTestIsAnimated", "(JZ)V", (void*) testIsAnimated },
1284     { "nTestRepeatCount", "(JI)V", (void*) testRepeatCount },
1285 };
1286 
register_android_graphics_cts_AImageDecoderTest(JNIEnv * env)1287 int register_android_graphics_cts_AImageDecoderTest(JNIEnv* env) {
1288     jclass clazz = env->FindClass("android/graphics/cts/AImageDecoderTest");
1289     return env->RegisterNatives(clazz, gMethods,
1290             sizeof(gMethods) / sizeof(JNINativeMethod));
1291 }
1292 
1293