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