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