1 #define LOG_TAG "Bitmap"
2 #include "Bitmap.h"
3
4 #include "GraphicBuffer.h"
5 #include "SkBitmap.h"
6 #include "SkPixelRef.h"
7 #include "SkImageEncoder.h"
8 #include "SkImageInfo.h"
9 #include "SkColor.h"
10 #include "SkColorPriv.h"
11 #include "SkColorSpace.h"
12 #include "SkColorSpaceXform.h"
13 #include "SkHalf.h"
14 #include "SkMatrix44.h"
15 #include "SkPM4f.h"
16 #include "SkPM4fPriv.h"
17 #include "GraphicsJNI.h"
18 #include "SkDither.h"
19 #include "SkUnPreMultiply.h"
20 #include "SkStream.h"
21
22 #include <binder/Parcel.h>
23 #include "android_os_Parcel.h"
24 #include "android_util_Binder.h"
25 #include "android_nio_utils.h"
26 #include "CreateJavaOutputStreamAdaptor.h"
27 #include <hwui/Paint.h>
28 #include <hwui/Bitmap.h>
29 #include <renderthread/RenderProxy.h>
30
31 #include "core_jni_helpers.h"
32
33 #include <jni.h>
34 #include <string.h>
35 #include <memory>
36 #include <string>
37
38 #define DEBUG_PARCEL 0
39 #define ASHMEM_BITMAP_MIN_SIZE (128 * (1 << 10))
40
41 static jclass gBitmap_class;
42 static jfieldID gBitmap_nativePtr;
43 static jmethodID gBitmap_constructorMethodID;
44 static jmethodID gBitmap_reinitMethodID;
45 static jmethodID gBitmap_getAllocationByteCountMethodID;
46
47 namespace android {
48
49 class BitmapWrapper {
50 public:
BitmapWrapper(Bitmap * bitmap)51 BitmapWrapper(Bitmap* bitmap)
52 : mBitmap(bitmap) { }
53
freePixels()54 void freePixels() {
55 mInfo = mBitmap->info();
56 mHasHardwareMipMap = mBitmap->hasHardwareMipMap();
57 mAllocationSize = mBitmap->getAllocationByteCount();
58 mRowBytes = mBitmap->rowBytes();
59 mGenerationId = mBitmap->getGenerationID();
60 mIsHardware = mBitmap->isHardware();
61 mBitmap.reset();
62 }
63
valid()64 bool valid() {
65 return mBitmap;
66 }
67
bitmap()68 Bitmap& bitmap() {
69 assertValid();
70 return *mBitmap;
71 }
72
assertValid()73 void assertValid() {
74 LOG_ALWAYS_FATAL_IF(!valid(), "Error, cannot access an invalid/free'd bitmap here!");
75 }
76
getSkBitmap(SkBitmap * outBitmap)77 void getSkBitmap(SkBitmap* outBitmap) {
78 assertValid();
79 mBitmap->getSkBitmap(outBitmap);
80 }
81
hasHardwareMipMap()82 bool hasHardwareMipMap() {
83 if (mBitmap) {
84 return mBitmap->hasHardwareMipMap();
85 }
86 return mHasHardwareMipMap;
87 }
88
setHasHardwareMipMap(bool hasMipMap)89 void setHasHardwareMipMap(bool hasMipMap) {
90 assertValid();
91 mBitmap->setHasHardwareMipMap(hasMipMap);
92 }
93
setAlphaType(SkAlphaType alphaType)94 void setAlphaType(SkAlphaType alphaType) {
95 assertValid();
96 mBitmap->setAlphaType(alphaType);
97 }
98
info()99 const SkImageInfo& info() {
100 if (mBitmap) {
101 return mBitmap->info();
102 }
103 return mInfo;
104 }
105
getAllocationByteCount() const106 size_t getAllocationByteCount() const {
107 if (mBitmap) {
108 return mBitmap->getAllocationByteCount();
109 }
110 return mAllocationSize;
111 }
112
rowBytes() const113 size_t rowBytes() const {
114 if (mBitmap) {
115 return mBitmap->rowBytes();
116 }
117 return mRowBytes;
118 }
119
getGenerationID() const120 uint32_t getGenerationID() const {
121 if (mBitmap) {
122 return mBitmap->getGenerationID();
123 }
124 return mGenerationId;
125 }
126
isHardware()127 bool isHardware() {
128 if (mBitmap) {
129 return mBitmap->isHardware();
130 }
131 return mIsHardware;
132 }
133
~BitmapWrapper()134 ~BitmapWrapper() { }
135
136 private:
137 sk_sp<Bitmap> mBitmap;
138 SkImageInfo mInfo;
139 bool mHasHardwareMipMap;
140 size_t mAllocationSize;
141 size_t mRowBytes;
142 uint32_t mGenerationId;
143 bool mIsHardware;
144 };
145
146 // Convenience class that does not take a global ref on the pixels, relying
147 // on the caller already having a local JNI ref
148 class LocalScopedBitmap {
149 public:
LocalScopedBitmap(jlong bitmapHandle)150 explicit LocalScopedBitmap(jlong bitmapHandle)
151 : mBitmapWrapper(reinterpret_cast<BitmapWrapper*>(bitmapHandle)) {}
152
operator ->()153 BitmapWrapper* operator->() {
154 return mBitmapWrapper;
155 }
156
pixels()157 void* pixels() {
158 return mBitmapWrapper->bitmap().pixels();
159 }
160
valid()161 bool valid() {
162 return mBitmapWrapper && mBitmapWrapper->valid();
163 }
164
165 private:
166 BitmapWrapper* mBitmapWrapper;
167 };
168
169 namespace bitmap {
170
171 // Assert that bitmap's SkAlphaType is consistent with isPremultiplied.
assert_premultiplied(const SkImageInfo & info,bool isPremultiplied)172 static void assert_premultiplied(const SkImageInfo& info, bool isPremultiplied) {
173 // kOpaque_SkAlphaType and kIgnore_SkAlphaType mean that isPremultiplied is
174 // irrelevant. This just tests to ensure that the SkAlphaType is not
175 // opposite of isPremultiplied.
176 if (isPremultiplied) {
177 SkASSERT(info.alphaType() != kUnpremul_SkAlphaType);
178 } else {
179 SkASSERT(info.alphaType() != kPremul_SkAlphaType);
180 }
181 }
182
reinitBitmap(JNIEnv * env,jobject javaBitmap,const SkImageInfo & info,bool isPremultiplied)183 void reinitBitmap(JNIEnv* env, jobject javaBitmap, const SkImageInfo& info,
184 bool isPremultiplied)
185 {
186 // The caller needs to have already set the alpha type properly, so the
187 // native SkBitmap stays in sync with the Java Bitmap.
188 assert_premultiplied(info, isPremultiplied);
189
190 env->CallVoidMethod(javaBitmap, gBitmap_reinitMethodID,
191 info.width(), info.height(), isPremultiplied);
192 }
193
getBitmapAllocationByteCount(JNIEnv * env,jobject javaBitmap)194 int getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap)
195 {
196 return env->CallIntMethod(javaBitmap, gBitmap_getAllocationByteCountMethodID);
197 }
198
createBitmap(JNIEnv * env,Bitmap * bitmap,int bitmapCreateFlags,jbyteArray ninePatchChunk,jobject ninePatchInsets,int density)199 jobject createBitmap(JNIEnv* env, Bitmap* bitmap,
200 int bitmapCreateFlags, jbyteArray ninePatchChunk, jobject ninePatchInsets,
201 int density) {
202 bool isMutable = bitmapCreateFlags & kBitmapCreateFlag_Mutable;
203 bool isPremultiplied = bitmapCreateFlags & kBitmapCreateFlag_Premultiplied;
204 // The caller needs to have already set the alpha type properly, so the
205 // native SkBitmap stays in sync with the Java Bitmap.
206 assert_premultiplied(bitmap->info(), isPremultiplied);
207 BitmapWrapper* bitmapWrapper = new BitmapWrapper(bitmap);
208 jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
209 reinterpret_cast<jlong>(bitmapWrapper), bitmap->width(), bitmap->height(), density,
210 isMutable, isPremultiplied, ninePatchChunk, ninePatchInsets);
211
212 if (env->ExceptionCheck() != 0) {
213 ALOGE("*** Uncaught exception returned from Java call!\n");
214 env->ExceptionDescribe();
215 }
216 return obj;
217 }
218
toSkBitmap(jlong bitmapHandle,SkBitmap * outBitmap)219 void toSkBitmap(jlong bitmapHandle, SkBitmap* outBitmap) {
220 LocalScopedBitmap bitmap(bitmapHandle);
221 bitmap->getSkBitmap(outBitmap);
222 }
223
toBitmap(JNIEnv * env,jobject bitmap)224 Bitmap& toBitmap(JNIEnv* env, jobject bitmap) {
225 SkASSERT(env);
226 SkASSERT(bitmap);
227 SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
228 jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
229 LocalScopedBitmap localBitmap(bitmapHandle);
230 return localBitmap->bitmap();
231 }
232
toBitmap(JNIEnv * env,jlong bitmapHandle)233 Bitmap& toBitmap(JNIEnv* env, jlong bitmapHandle) {
234 SkASSERT(env);
235 LocalScopedBitmap localBitmap(bitmapHandle);
236 return localBitmap->bitmap();
237 }
238
imageInfo(JNIEnv * env,jobject bitmap,AndroidBitmapInfo * info)239 void imageInfo(JNIEnv* env, jobject bitmap, AndroidBitmapInfo* info) {
240 SkASSERT(info);
241 SkASSERT(env);
242 SkASSERT(bitmap);
243 SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
244 jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
245 LocalScopedBitmap localBitmap(bitmapHandle);
246
247 const SkImageInfo& imageInfo = localBitmap->info();
248 info->width = imageInfo.width();
249 info->height = imageInfo.height();
250 info->stride = localBitmap->rowBytes();
251 info->flags = 0;
252 switch (imageInfo.colorType()) {
253 case kN32_SkColorType:
254 info->format = ANDROID_BITMAP_FORMAT_RGBA_8888;
255 break;
256 case kRGB_565_SkColorType:
257 info->format = ANDROID_BITMAP_FORMAT_RGB_565;
258 break;
259 case kARGB_4444_SkColorType:
260 info->format = ANDROID_BITMAP_FORMAT_RGBA_4444;
261 break;
262 case kAlpha_8_SkColorType:
263 info->format = ANDROID_BITMAP_FORMAT_A_8;
264 break;
265 default:
266 info->format = ANDROID_BITMAP_FORMAT_NONE;
267 break;
268 }
269 }
270
lockPixels(JNIEnv * env,jobject bitmap)271 void* lockPixels(JNIEnv* env, jobject bitmap) {
272 SkASSERT(env);
273 SkASSERT(bitmap);
274 SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
275 jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
276
277 LocalScopedBitmap localBitmap(bitmapHandle);
278 if (!localBitmap->valid()) return nullptr;
279
280 SkPixelRef& pixelRef = localBitmap->bitmap();
281 if (!pixelRef.pixels()) {
282 return nullptr;
283 }
284 pixelRef.ref();
285 return pixelRef.pixels();
286 }
287
unlockPixels(JNIEnv * env,jobject bitmap)288 bool unlockPixels(JNIEnv* env, jobject bitmap) {
289 SkASSERT(env);
290 SkASSERT(bitmap);
291 SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
292 jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
293
294 LocalScopedBitmap localBitmap(bitmapHandle);
295 if (!localBitmap->valid()) return false;
296
297 SkPixelRef& pixelRef = localBitmap->bitmap();
298 pixelRef.notifyPixelsChanged();
299 pixelRef.unref();
300 return true;
301 }
302
303 } // namespace bitmap
304
305 } // namespace android
306
307 using namespace android;
308 using namespace android::bitmap;
309
310 ///////////////////////////////////////////////////////////////////////////////
311 // Conversions to/from SkColor, for get/setPixels, and the create method, which
312 // is basically like setPixels
313
314 typedef void (*FromColorProc)(void* dst, const SkColor src[], int width,
315 int x, int y);
316
FromColor_F16(void * dst,const SkColor src[],int width,int,int)317 static void FromColor_F16(void* dst, const SkColor src[], int width,
318 int, int) {
319 uint64_t* d = (uint64_t*)dst;
320
321 for (int i = 0; i < width; i++) {
322 *d++ = SkColor4f::FromColor(*src++).premul().toF16();
323 }
324 }
325
FromColor_F16_Raw(void * dst,const SkColor src[],int width,int,int)326 static void FromColor_F16_Raw(void* dst, const SkColor src[], int width,
327 int, int) {
328 uint64_t* d = (uint64_t*)dst;
329
330 for (int i = 0; i < width; i++) {
331 const SkColor4f color = SkColor4f::FromColor(*src++);
332 uint16_t* scratch = reinterpret_cast<uint16_t*>(d++);
333 scratch[0] = SkFloatToHalf(color.fR);
334 scratch[1] = SkFloatToHalf(color.fG);
335 scratch[2] = SkFloatToHalf(color.fB);
336 scratch[3] = SkFloatToHalf(color.fA);
337 }
338 }
339
FromColor_D32(void * dst,const SkColor src[],int width,int,int)340 static void FromColor_D32(void* dst, const SkColor src[], int width,
341 int, int) {
342 SkPMColor* d = (SkPMColor*)dst;
343
344 for (int i = 0; i < width; i++) {
345 *d++ = SkPreMultiplyColor(*src++);
346 }
347 }
348
FromColor_D32_Raw(void * dst,const SkColor src[],int width,int,int)349 static void FromColor_D32_Raw(void* dst, const SkColor src[], int width,
350 int, int) {
351 // Needed to thwart the unreachable code detection from clang.
352 static const bool sk_color_ne_zero = SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER;
353
354 // SkColor's ordering may be different from SkPMColor
355 if (sk_color_ne_zero) {
356 memcpy(dst, src, width * sizeof(SkColor));
357 return;
358 }
359
360 // order isn't same, repack each pixel manually
361 SkPMColor* d = (SkPMColor*)dst;
362 for (int i = 0; i < width; i++) {
363 SkColor c = *src++;
364 *d++ = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
365 SkColorGetG(c), SkColorGetB(c));
366 }
367 }
368
FromColor_D565(void * dst,const SkColor src[],int width,int x,int y)369 static void FromColor_D565(void* dst, const SkColor src[], int width,
370 int x, int y) {
371 uint16_t* d = (uint16_t*)dst;
372
373 DITHER_565_SCAN(y);
374 for (int stop = x + width; x < stop; x++) {
375 SkColor c = *src++;
376 *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c),
377 DITHER_VALUE(x));
378 }
379 }
380
FromColor_D4444(void * dst,const SkColor src[],int width,int x,int y)381 static void FromColor_D4444(void* dst, const SkColor src[], int width,
382 int x, int y) {
383 SkPMColor16* d = (SkPMColor16*)dst;
384
385 DITHER_4444_SCAN(y);
386 for (int stop = x + width; x < stop; x++) {
387 SkPMColor pmc = SkPreMultiplyColor(*src++);
388 *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
389 // *d++ = SkPixel32ToPixel4444(pmc);
390 }
391 }
392
FromColor_D4444_Raw(void * dst,const SkColor src[],int width,int x,int y)393 static void FromColor_D4444_Raw(void* dst, const SkColor src[], int width,
394 int x, int y) {
395 SkPMColor16* d = (SkPMColor16*)dst;
396
397 DITHER_4444_SCAN(y);
398 for (int stop = x + width; x < stop; x++) {
399 SkColor c = *src++;
400
401 // SkPMColor is used because the ordering is ARGB32, even though the target actually premultiplied
402 SkPMColor pmc = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
403 SkColorGetG(c), SkColorGetB(c));
404 *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
405 // *d++ = SkPixel32ToPixel4444(pmc);
406 }
407 }
408
FromColor_DA8(void * dst,const SkColor src[],int width,int x,int y)409 static void FromColor_DA8(void* dst, const SkColor src[], int width, int x, int y) {
410 uint8_t* d = (uint8_t*)dst;
411
412 for (int stop = x + width; x < stop; x++) {
413 *d++ = SkColorGetA(*src++);
414 }
415 }
416
417 // can return NULL
ChooseFromColorProc(const SkBitmap & bitmap)418 static FromColorProc ChooseFromColorProc(const SkBitmap& bitmap) {
419 switch (bitmap.colorType()) {
420 case kN32_SkColorType:
421 return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D32 : FromColor_D32_Raw;
422 case kARGB_4444_SkColorType:
423 return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D4444 :
424 FromColor_D4444_Raw;
425 case kRGB_565_SkColorType:
426 return FromColor_D565;
427 case kAlpha_8_SkColorType:
428 return FromColor_DA8;
429 case kRGBA_F16_SkColorType:
430 return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_F16 : FromColor_F16_Raw;
431 default:
432 break;
433 }
434 return NULL;
435 }
436
SetPixels(JNIEnv * env,jintArray srcColors,int srcOffset,int srcStride,int x,int y,int width,int height,const SkBitmap & dstBitmap)437 bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride,
438 int x, int y, int width, int height, const SkBitmap& dstBitmap) {
439 void* dst = dstBitmap.getPixels();
440 FromColorProc proc = ChooseFromColorProc(dstBitmap);
441
442 if (NULL == dst || NULL == proc) {
443 return false;
444 }
445
446 const jint* array = env->GetIntArrayElements(srcColors, NULL);
447 const SkColor* src = (const SkColor*)array + srcOffset;
448
449 // reset to to actual choice from caller
450 dst = dstBitmap.getAddr(x, y);
451
452 SkColorSpace* colorSpace = dstBitmap.colorSpace();
453 if (dstBitmap.colorType() == kRGBA_F16_SkColorType ||
454 GraphicsJNI::isColorSpaceSRGB(colorSpace)) {
455 // now copy/convert each scanline
456 for (int y = 0; y < height; y++) {
457 proc(dst, src, width, x, y);
458 src += srcStride;
459 dst = (char*)dst + dstBitmap.rowBytes();
460 }
461 } else {
462 auto sRGB = SkColorSpace::MakeSRGB();
463 auto xform = SkColorSpaceXform::New(sRGB.get(), colorSpace);
464
465 std::unique_ptr<SkColor[]> row(new SkColor[width]);
466
467 // now copy/convert each scanline
468 for (int y = 0; y < height; y++) {
469 memcpy(row.get(), src, sizeof(SkColor) * width);
470 xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, row.get(),
471 SkColorSpaceXform::kBGRA_8888_ColorFormat, row.get(), width,
472 SkAlphaType::kUnpremul_SkAlphaType);
473
474 proc(dst, row.get(), width, x, y);
475 src += srcStride;
476 dst = (char*)dst + dstBitmap.rowBytes();
477 }
478 }
479
480 dstBitmap.notifyPixelsChanged();
481
482 env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array), JNI_ABORT);
483 return true;
484 }
485
486 //////////////////// ToColor procs
487
488 typedef void (*ToColorProc)(SkColor dst[], const void* src, int width);
489
ToColor_F16_Alpha(SkColor dst[],const void * src,int width)490 static void ToColor_F16_Alpha(SkColor dst[], const void* src, int width) {
491 SkASSERT(width > 0);
492 uint64_t* s = (uint64_t*)src;
493 do {
494 *dst++ = SkPM4f::FromF16((const uint16_t*) s++).unpremul().toSkColor();
495 } while (--width != 0);
496 }
497
ToColor_F16_Raw(SkColor dst[],const void * src,int width)498 static void ToColor_F16_Raw(SkColor dst[], const void* src, int width) {
499 SkASSERT(width > 0);
500 uint64_t* s = (uint64_t*)src;
501 do {
502 *dst++ = Sk4f_toS32(swizzle_rb(SkHalfToFloat_finite_ftz(*s++)));
503 } while (--width != 0);
504 }
505
ToColor_S32_Alpha(SkColor dst[],const void * src,int width)506 static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width) {
507 SkASSERT(width > 0);
508 const SkPMColor* s = (const SkPMColor*)src;
509 do {
510 *dst++ = SkUnPreMultiply::PMColorToColor(*s++);
511 } while (--width != 0);
512 }
513
ToColor_S32_Raw(SkColor dst[],const void * src,int width)514 static void ToColor_S32_Raw(SkColor dst[], const void* src, int width) {
515 SkASSERT(width > 0);
516 const SkPMColor* s = (const SkPMColor*)src;
517 do {
518 SkPMColor c = *s++;
519 *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
520 SkGetPackedG32(c), SkGetPackedB32(c));
521 } while (--width != 0);
522 }
523
ToColor_S32_Opaque(SkColor dst[],const void * src,int width)524 static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width) {
525 SkASSERT(width > 0);
526 const SkPMColor* s = (const SkPMColor*)src;
527 do {
528 SkPMColor c = *s++;
529 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
530 SkGetPackedB32(c));
531 } while (--width != 0);
532 }
533
ToColor_S4444_Alpha(SkColor dst[],const void * src,int width)534 static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width) {
535 SkASSERT(width > 0);
536 const SkPMColor16* s = (const SkPMColor16*)src;
537 do {
538 *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++));
539 } while (--width != 0);
540 }
541
ToColor_S4444_Raw(SkColor dst[],const void * src,int width)542 static void ToColor_S4444_Raw(SkColor dst[], const void* src, int width) {
543 SkASSERT(width > 0);
544 const SkPMColor16* s = (const SkPMColor16*)src;
545 do {
546 SkPMColor c = SkPixel4444ToPixel32(*s++);
547 *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
548 SkGetPackedG32(c), SkGetPackedB32(c));
549 } while (--width != 0);
550 }
551
ToColor_S4444_Opaque(SkColor dst[],const void * src,int width)552 static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width) {
553 SkASSERT(width > 0);
554 const SkPMColor16* s = (const SkPMColor16*)src;
555 do {
556 SkPMColor c = SkPixel4444ToPixel32(*s++);
557 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
558 SkGetPackedB32(c));
559 } while (--width != 0);
560 }
561
ToColor_S565(SkColor dst[],const void * src,int width)562 static void ToColor_S565(SkColor dst[], const void* src, int width) {
563 SkASSERT(width > 0);
564 const uint16_t* s = (const uint16_t*)src;
565 do {
566 uint16_t c = *s++;
567 *dst++ = SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c),
568 SkPacked16ToB32(c));
569 } while (--width != 0);
570 }
571
ToColor_SA8(SkColor dst[],const void * src,int width)572 static void ToColor_SA8(SkColor dst[], const void* src, int width) {
573 SkASSERT(width > 0);
574 const uint8_t* s = (const uint8_t*)src;
575 do {
576 uint8_t c = *s++;
577 *dst++ = SkColorSetARGB(c, 0, 0, 0);
578 } while (--width != 0);
579 }
580
581 // can return NULL
ChooseToColorProc(const SkBitmap & src)582 static ToColorProc ChooseToColorProc(const SkBitmap& src) {
583 switch (src.colorType()) {
584 case kN32_SkColorType:
585 switch (src.alphaType()) {
586 case kOpaque_SkAlphaType:
587 return ToColor_S32_Opaque;
588 case kPremul_SkAlphaType:
589 return ToColor_S32_Alpha;
590 case kUnpremul_SkAlphaType:
591 return ToColor_S32_Raw;
592 default:
593 return NULL;
594 }
595 case kARGB_4444_SkColorType:
596 switch (src.alphaType()) {
597 case kOpaque_SkAlphaType:
598 return ToColor_S4444_Opaque;
599 case kPremul_SkAlphaType:
600 return ToColor_S4444_Alpha;
601 case kUnpremul_SkAlphaType:
602 return ToColor_S4444_Raw;
603 default:
604 return NULL;
605 }
606 case kRGB_565_SkColorType:
607 return ToColor_S565;
608 case kAlpha_8_SkColorType:
609 return ToColor_SA8;
610 case kRGBA_F16_SkColorType:
611 switch (src.alphaType()) {
612 case kOpaque_SkAlphaType:
613 return ToColor_F16_Raw;
614 case kPremul_SkAlphaType:
615 return ToColor_F16_Alpha;
616 case kUnpremul_SkAlphaType:
617 return ToColor_F16_Raw;
618 default:
619 return NULL;
620 }
621 default:
622 break;
623 }
624 return NULL;
625 }
626
ToF16_SA8(void * dst,const void * src,int width)627 static void ToF16_SA8(void* dst, const void* src, int width) {
628 SkASSERT(width > 0);
629 uint64_t* d = (uint64_t*)dst;
630 const uint8_t* s = (const uint8_t*)src;
631
632 for (int i = 0; i < width; i++) {
633 uint8_t c = *s++;
634 SkPM4f a;
635 a.fVec[SkPM4f::R] = 0.0f;
636 a.fVec[SkPM4f::G] = 0.0f;
637 a.fVec[SkPM4f::B] = 0.0f;
638 a.fVec[SkPM4f::A] = c / 255.0f;
639 *d++ = a.toF16();
640 }
641 }
642
643 ///////////////////////////////////////////////////////////////////////////////
644 ///////////////////////////////////////////////////////////////////////////////
645
getPremulBitmapCreateFlags(bool isMutable)646 static int getPremulBitmapCreateFlags(bool isMutable) {
647 int flags = android::bitmap::kBitmapCreateFlag_Premultiplied;
648 if (isMutable) flags |= android::bitmap::kBitmapCreateFlag_Mutable;
649 return flags;
650 }
651
Bitmap_creator(JNIEnv * env,jobject,jintArray jColors,jint offset,jint stride,jint width,jint height,jint configHandle,jboolean isMutable,jfloatArray xyzD50,jobject transferParameters)652 static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
653 jint offset, jint stride, jint width, jint height,
654 jint configHandle, jboolean isMutable,
655 jfloatArray xyzD50, jobject transferParameters) {
656 SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
657 if (NULL != jColors) {
658 size_t n = env->GetArrayLength(jColors);
659 if (n < SkAbs32(stride) * (size_t)height) {
660 doThrowAIOOBE(env);
661 return NULL;
662 }
663 }
664
665 // ARGB_4444 is a deprecated format, convert automatically to 8888
666 if (colorType == kARGB_4444_SkColorType) {
667 colorType = kN32_SkColorType;
668 }
669
670 SkBitmap bitmap;
671 sk_sp<SkColorSpace> colorSpace;
672
673 if (colorType != kN32_SkColorType || xyzD50 == nullptr || transferParameters == nullptr) {
674 colorSpace = GraphicsJNI::colorSpaceForType(colorType);
675 } else {
676 SkColorSpaceTransferFn p = GraphicsJNI::getNativeTransferParameters(env, transferParameters);
677 SkMatrix44 xyzMatrix = GraphicsJNI::getNativeXYZMatrix(env, xyzD50);
678 colorSpace = SkColorSpace::MakeRGB(p, xyzMatrix);
679 }
680
681 bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType, colorSpace));
682
683 sk_sp<Bitmap> nativeBitmap = Bitmap::allocateHeapBitmap(&bitmap);
684 if (!nativeBitmap) {
685 ALOGE("OOM allocating Bitmap with dimensions %i x %i", width, height);
686 doThrowOOME(env);
687 return NULL;
688 }
689
690 if (jColors != NULL) {
691 GraphicsJNI::SetPixels(env, jColors, offset, stride, 0, 0, width, height, bitmap);
692 }
693
694 return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable));
695 }
696
bitmapCopyTo(SkBitmap * dst,SkColorType dstCT,const SkBitmap & src,SkBitmap::Allocator * alloc)697 static bool bitmapCopyTo(SkBitmap* dst, SkColorType dstCT, const SkBitmap& src,
698 SkBitmap::Allocator* alloc) {
699 SkPixmap srcPM;
700 if (!src.peekPixels(&srcPM)) {
701 return false;
702 }
703
704 SkImageInfo dstInfo = srcPM.info().makeColorType(dstCT);
705 switch (dstCT) {
706 case kRGB_565_SkColorType:
707 // copyTo() has never been strict on alpha type. Here we set the src to opaque to
708 // allow the call to readPixels() to succeed and preserve this lenient behavior.
709 if (kOpaque_SkAlphaType != srcPM.alphaType()) {
710 srcPM = SkPixmap(srcPM.info().makeAlphaType(kOpaque_SkAlphaType), srcPM.addr(),
711 srcPM.rowBytes());
712 dstInfo = dstInfo.makeAlphaType(kOpaque_SkAlphaType);
713 }
714 break;
715 case kRGBA_F16_SkColorType:
716 // The caller does not have an opportunity to pass a dst color space. Assume that
717 // they want linear sRGB.
718 dstInfo = dstInfo.makeColorSpace(SkColorSpace::MakeSRGBLinear());
719
720 if (!srcPM.colorSpace()) {
721 // Skia needs a color space to convert to F16. nullptr should be treated as sRGB.
722 srcPM.setColorSpace(SkColorSpace::MakeSRGB());
723 }
724 break;
725 default:
726 break;
727 }
728
729 if (!dst->setInfo(dstInfo)) {
730 return false;
731 }
732 if (!dst->tryAllocPixels(alloc)) {
733 return false;
734 }
735
736 // Skia does not support copying from kAlpha8 to types that are not alpha only.
737 // We will handle this case here.
738 if (kAlpha_8_SkColorType == srcPM.colorType() && kAlpha_8_SkColorType != dstCT) {
739 switch (dstCT) {
740 case kRGBA_8888_SkColorType:
741 case kBGRA_8888_SkColorType: {
742 for (int y = 0; y < src.height(); y++) {
743 const uint8_t* srcRow = srcPM.addr8(0, y);
744 uint32_t* dstRow = dst->getAddr32(0, y);
745 ToColor_SA8(dstRow, srcRow, src.width());
746 }
747 return true;
748 }
749 case kRGB_565_SkColorType: {
750 for (int y = 0; y < src.height(); y++) {
751 uint16_t* dstRow = dst->getAddr16(0, y);
752 memset(dstRow, 0, sizeof(uint16_t) * src.width());
753 }
754 return true;
755 }
756 case kRGBA_F16_SkColorType: {
757 for (int y = 0; y < src.height(); y++) {
758 const uint8_t* srcRow = srcPM.addr8(0, y);
759 void* dstRow = dst->getAddr(0, y);
760 ToF16_SA8(dstRow, srcRow, src.width());
761 }
762 return true;
763 }
764 default:
765 return false;
766 }
767 }
768
769 SkPixmap dstPM;
770 if (!dst->peekPixels(&dstPM)) {
771 return false;
772 }
773
774 // Skia needs a color space to convert from F16. nullptr should be treated as sRGB.
775 if (kRGBA_F16_SkColorType == srcPM.colorType() && !dstPM.colorSpace()) {
776 dstPM.setColorSpace(SkColorSpace::MakeSRGB());
777 }
778
779 // readPixels does not support color spaces with parametric transfer functions. This
780 // works around that restriction when the color spaces are equal.
781 if (kRGBA_F16_SkColorType != dstCT && kRGBA_F16_SkColorType != srcPM.colorType() &&
782 dstPM.colorSpace() == srcPM.colorSpace()) {
783 dstPM.setColorSpace(nullptr);
784 srcPM.setColorSpace(nullptr);
785 }
786
787 return srcPM.readPixels(dstPM);
788 }
789
Bitmap_copy(JNIEnv * env,jobject,jlong srcHandle,jint dstConfigHandle,jboolean isMutable)790 static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle,
791 jint dstConfigHandle, jboolean isMutable) {
792 SkBitmap src;
793 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
794 if (dstConfigHandle == GraphicsJNI::hardwareLegacyBitmapConfig()) {
795 sk_sp<Bitmap> bitmap(Bitmap::allocateHardwareBitmap(src));
796 if (!bitmap.get()) {
797 return NULL;
798 }
799 return createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(isMutable));
800 }
801
802 SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
803 SkBitmap result;
804 HeapAllocator allocator;
805
806 if (!bitmapCopyTo(&result, dstCT, src, &allocator)) {
807 return NULL;
808 }
809 auto bitmap = allocator.getStorageObjAndReset();
810 return createBitmap(env, bitmap, getPremulBitmapCreateFlags(isMutable));
811 }
812
Bitmap_copyAshmemImpl(JNIEnv * env,SkBitmap & src,SkColorType & dstCT)813 static Bitmap* Bitmap_copyAshmemImpl(JNIEnv* env, SkBitmap& src, SkColorType& dstCT) {
814 SkBitmap result;
815
816 AshmemPixelAllocator allocator(env);
817 if (!bitmapCopyTo(&result, dstCT, src, &allocator)) {
818 return NULL;
819 }
820 auto bitmap = allocator.getStorageObjAndReset();
821 bitmap->setImmutable();
822 return bitmap;
823 }
824
Bitmap_copyAshmem(JNIEnv * env,jobject,jlong srcHandle)825 static jobject Bitmap_copyAshmem(JNIEnv* env, jobject, jlong srcHandle) {
826 SkBitmap src;
827 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
828 SkColorType dstCT = src.colorType();
829 auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
830 jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
831 return ret;
832 }
833
Bitmap_copyAshmemConfig(JNIEnv * env,jobject,jlong srcHandle,jint dstConfigHandle)834 static jobject Bitmap_copyAshmemConfig(JNIEnv* env, jobject, jlong srcHandle, jint dstConfigHandle) {
835 SkBitmap src;
836 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
837 SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
838 auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
839 jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
840 return ret;
841 }
842
Bitmap_destruct(BitmapWrapper * bitmap)843 static void Bitmap_destruct(BitmapWrapper* bitmap) {
844 delete bitmap;
845 }
846
Bitmap_getNativeFinalizer(JNIEnv *,jobject)847 static jlong Bitmap_getNativeFinalizer(JNIEnv*, jobject) {
848 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Bitmap_destruct));
849 }
850
Bitmap_recycle(JNIEnv * env,jobject,jlong bitmapHandle)851 static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {
852 LocalScopedBitmap bitmap(bitmapHandle);
853 bitmap->freePixels();
854 return JNI_TRUE;
855 }
856
Bitmap_reconfigure(JNIEnv * env,jobject clazz,jlong bitmapHandle,jint width,jint height,jint configHandle,jboolean requestPremul)857 static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
858 jint width, jint height, jint configHandle, jboolean requestPremul) {
859 LocalScopedBitmap bitmap(bitmapHandle);
860 bitmap->assertValid();
861 SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
862
863 // ARGB_4444 is a deprecated format, convert automatically to 8888
864 if (colorType == kARGB_4444_SkColorType) {
865 colorType = kN32_SkColorType;
866 }
867 size_t requestedSize = width * height * SkColorTypeBytesPerPixel(colorType);
868 if (requestedSize > bitmap->getAllocationByteCount()) {
869 // done in native as there's no way to get BytesPerPixel in Java
870 doThrowIAE(env, "Bitmap not large enough to support new configuration");
871 return;
872 }
873 SkAlphaType alphaType;
874 if (bitmap->info().colorType() != kRGB_565_SkColorType
875 && bitmap->info().alphaType() == kOpaque_SkAlphaType) {
876 // If the original bitmap was set to opaque, keep that setting, unless it
877 // was 565, which is required to be opaque.
878 alphaType = kOpaque_SkAlphaType;
879 } else {
880 // Otherwise respect the premultiplied request.
881 alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
882 }
883 bitmap->bitmap().reconfigure(SkImageInfo::Make(width, height, colorType, alphaType,
884 sk_ref_sp(bitmap->info().colorSpace())));
885 }
886
887 // These must match the int values in Bitmap.java
888 enum JavaEncodeFormat {
889 kJPEG_JavaEncodeFormat = 0,
890 kPNG_JavaEncodeFormat = 1,
891 kWEBP_JavaEncodeFormat = 2
892 };
893
Bitmap_compress(JNIEnv * env,jobject clazz,jlong bitmapHandle,jint format,jint quality,jobject jstream,jbyteArray jstorage)894 static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle,
895 jint format, jint quality,
896 jobject jstream, jbyteArray jstorage) {
897 SkEncodedImageFormat fm;
898 switch (format) {
899 case kJPEG_JavaEncodeFormat:
900 fm = SkEncodedImageFormat::kJPEG;
901 break;
902 case kPNG_JavaEncodeFormat:
903 fm = SkEncodedImageFormat::kPNG;
904 break;
905 case kWEBP_JavaEncodeFormat:
906 fm = SkEncodedImageFormat::kWEBP;
907 break;
908 default:
909 return JNI_FALSE;
910 }
911
912 LocalScopedBitmap bitmap(bitmapHandle);
913 if (!bitmap.valid()) {
914 return JNI_FALSE;
915 }
916
917 std::unique_ptr<SkWStream> strm(CreateJavaOutputStreamAdaptor(env, jstream, jstorage));
918 if (!strm.get()) {
919 return JNI_FALSE;
920 }
921
922 SkBitmap skbitmap;
923 bitmap->getSkBitmap(&skbitmap);
924 return SkEncodeImage(strm.get(), skbitmap, fm, quality) ? JNI_TRUE : JNI_FALSE;
925 }
926
Bitmap_erase(JNIEnv * env,jobject,jlong bitmapHandle,jint color)927 static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) {
928 LocalScopedBitmap bitmap(bitmapHandle);
929 SkBitmap skBitmap;
930 bitmap->getSkBitmap(&skBitmap);
931 skBitmap.eraseColor(color);
932 }
933
Bitmap_rowBytes(JNIEnv * env,jobject,jlong bitmapHandle)934 static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {
935 LocalScopedBitmap bitmap(bitmapHandle);
936 return static_cast<jint>(bitmap->rowBytes());
937 }
938
Bitmap_config(JNIEnv * env,jobject,jlong bitmapHandle)939 static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) {
940 LocalScopedBitmap bitmap(bitmapHandle);
941 if (bitmap->isHardware()) {
942 return GraphicsJNI::hardwareLegacyBitmapConfig();
943 }
944 return GraphicsJNI::colorTypeToLegacyBitmapConfig(bitmap->info().colorType());
945 }
946
Bitmap_getGenerationId(JNIEnv * env,jobject,jlong bitmapHandle)947 static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {
948 LocalScopedBitmap bitmap(bitmapHandle);
949 return static_cast<jint>(bitmap->getGenerationID());
950 }
951
Bitmap_isPremultiplied(JNIEnv * env,jobject,jlong bitmapHandle)952 static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) {
953 LocalScopedBitmap bitmap(bitmapHandle);
954 if (bitmap->info().alphaType() == kPremul_SkAlphaType) {
955 return JNI_TRUE;
956 }
957 return JNI_FALSE;
958 }
959
Bitmap_hasAlpha(JNIEnv * env,jobject,jlong bitmapHandle)960 static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) {
961 LocalScopedBitmap bitmap(bitmapHandle);
962 return !bitmap->info().isOpaque() ? JNI_TRUE : JNI_FALSE;
963 }
964
Bitmap_setHasAlpha(JNIEnv * env,jobject,jlong bitmapHandle,jboolean hasAlpha,jboolean requestPremul)965 static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle,
966 jboolean hasAlpha, jboolean requestPremul) {
967 LocalScopedBitmap bitmap(bitmapHandle);
968 if (hasAlpha) {
969 bitmap->setAlphaType(
970 requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
971 } else {
972 bitmap->setAlphaType(kOpaque_SkAlphaType);
973 }
974 }
975
Bitmap_setPremultiplied(JNIEnv * env,jobject,jlong bitmapHandle,jboolean isPremul)976 static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
977 jboolean isPremul) {
978 LocalScopedBitmap bitmap(bitmapHandle);
979 if (!bitmap->info().isOpaque()) {
980 if (isPremul) {
981 bitmap->setAlphaType(kPremul_SkAlphaType);
982 } else {
983 bitmap->setAlphaType(kUnpremul_SkAlphaType);
984 }
985 }
986 }
987
Bitmap_hasMipMap(JNIEnv * env,jobject,jlong bitmapHandle)988 static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) {
989 LocalScopedBitmap bitmap(bitmapHandle);
990 return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE;
991 }
992
Bitmap_setHasMipMap(JNIEnv * env,jobject,jlong bitmapHandle,jboolean hasMipMap)993 static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle,
994 jboolean hasMipMap) {
995 LocalScopedBitmap bitmap(bitmapHandle);
996 bitmap->setHasHardwareMipMap(hasMipMap);
997 }
998
999 ///////////////////////////////////////////////////////////////////////////////
1000
1001 // This is the maximum possible size because the SkColorSpace must be
1002 // representable (and therefore serializable) using a matrix and numerical
1003 // transfer function. If we allow more color space representations in the
1004 // framework, we may need to update this maximum size.
1005 static constexpr uint32_t kMaxColorSpaceSerializedBytes = 80;
1006
Bitmap_createFromParcel(JNIEnv * env,jobject,jobject parcel)1007 static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
1008 if (parcel == NULL) {
1009 SkDebugf("-------- unparcel parcel is NULL\n");
1010 return NULL;
1011 }
1012
1013 android::Parcel* p = android::parcelForJavaObject(env, parcel);
1014
1015 const bool isMutable = p->readInt32() != 0;
1016 const SkColorType colorType = (SkColorType)p->readInt32();
1017 const SkAlphaType alphaType = (SkAlphaType)p->readInt32();
1018 const uint32_t colorSpaceSize = p->readUint32();
1019 sk_sp<SkColorSpace> colorSpace;
1020 if (kRGBA_F16_SkColorType == colorType) {
1021 colorSpace = SkColorSpace::MakeSRGBLinear();
1022 } else if (colorSpaceSize > 0) {
1023 if (colorSpaceSize > kMaxColorSpaceSerializedBytes) {
1024 ALOGD("Bitmap_createFromParcel: Serialized SkColorSpace is larger than expected: "
1025 "%d bytes\n", colorSpaceSize);
1026 }
1027
1028 const void* data = p->readInplace(colorSpaceSize);
1029 if (data) {
1030 colorSpace = SkColorSpace::Deserialize(data, colorSpaceSize);
1031 } else {
1032 ALOGD("Bitmap_createFromParcel: Unable to read serialized SkColorSpace data\n");
1033 }
1034 }
1035 const int width = p->readInt32();
1036 const int height = p->readInt32();
1037 const int rowBytes = p->readInt32();
1038 const int density = p->readInt32();
1039
1040 if (kN32_SkColorType != colorType &&
1041 kRGBA_F16_SkColorType != colorType &&
1042 kRGB_565_SkColorType != colorType &&
1043 kARGB_4444_SkColorType != colorType &&
1044 kAlpha_8_SkColorType != colorType) {
1045 SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType);
1046 return NULL;
1047 }
1048
1049 std::unique_ptr<SkBitmap> bitmap(new SkBitmap);
1050 if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType, colorSpace),
1051 rowBytes)) {
1052 return NULL;
1053 }
1054
1055 // Read the bitmap blob.
1056 size_t size = bitmap->getSize();
1057 android::Parcel::ReadableBlob blob;
1058 android::status_t status = p->readBlob(size, &blob);
1059 if (status) {
1060 doThrowRE(env, "Could not read bitmap blob.");
1061 return NULL;
1062 }
1063
1064 // Map the bitmap in place from the ashmem region if possible otherwise copy.
1065 sk_sp<Bitmap> nativeBitmap;
1066 if (blob.fd() >= 0 && (blob.isMutable() || !isMutable) && (size >= ASHMEM_BITMAP_MIN_SIZE)) {
1067 #if DEBUG_PARCEL
1068 ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob "
1069 "(fds %s)",
1070 isMutable ? "mutable" : "immutable",
1071 blob.isMutable() ? "mutable" : "immutable",
1072 p->allowFds() ? "allowed" : "forbidden");
1073 #endif
1074 // Dup the file descriptor so we can keep a reference to it after the Parcel
1075 // is disposed.
1076 int dupFd = dup(blob.fd());
1077 if (dupFd < 0) {
1078 ALOGE("Error allocating dup fd. Error:%d", errno);
1079 blob.release();
1080 doThrowRE(env, "Could not allocate dup blob fd.");
1081 return NULL;
1082 }
1083
1084 // Map the pixels in place and take ownership of the ashmem region.
1085 nativeBitmap = sk_sp<Bitmap>(GraphicsJNI::mapAshmemBitmap(env, bitmap.get(),
1086 dupFd, const_cast<void*>(blob.data()), size, !isMutable));
1087 if (!nativeBitmap) {
1088 close(dupFd);
1089 blob.release();
1090 doThrowRE(env, "Could not allocate ashmem pixel ref.");
1091 return NULL;
1092 }
1093
1094 // Clear the blob handle, don't release it.
1095 blob.clear();
1096 } else {
1097 #if DEBUG_PARCEL
1098 if (blob.fd() >= 0) {
1099 ALOGD("Bitmap.createFromParcel: copied contents of mutable bitmap "
1100 "from immutable blob (fds %s)",
1101 p->allowFds() ? "allowed" : "forbidden");
1102 } else {
1103 ALOGD("Bitmap.createFromParcel: copied contents from %s blob "
1104 "(fds %s)",
1105 blob.isMutable() ? "mutable" : "immutable",
1106 p->allowFds() ? "allowed" : "forbidden");
1107 }
1108 #endif
1109
1110 // Copy the pixels into a new buffer.
1111 nativeBitmap = Bitmap::allocateHeapBitmap(bitmap.get());
1112 if (!nativeBitmap) {
1113 blob.release();
1114 doThrowRE(env, "Could not allocate java pixel ref.");
1115 return NULL;
1116 }
1117 memcpy(bitmap->getPixels(), blob.data(), size);
1118
1119 // Release the blob handle.
1120 blob.release();
1121 }
1122
1123 return createBitmap(env, nativeBitmap.release(),
1124 getPremulBitmapCreateFlags(isMutable), NULL, NULL, density);
1125 }
1126
Bitmap_writeToParcel(JNIEnv * env,jobject,jlong bitmapHandle,jboolean isMutable,jint density,jobject parcel)1127 static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
1128 jlong bitmapHandle,
1129 jboolean isMutable, jint density,
1130 jobject parcel) {
1131 if (parcel == NULL) {
1132 SkDebugf("------- writeToParcel null parcel\n");
1133 return JNI_FALSE;
1134 }
1135
1136 android::Parcel* p = android::parcelForJavaObject(env, parcel);
1137 SkBitmap bitmap;
1138
1139 auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle);
1140 bitmapWrapper->getSkBitmap(&bitmap);
1141
1142 p->writeInt32(isMutable);
1143 p->writeInt32(bitmap.colorType());
1144 p->writeInt32(bitmap.alphaType());
1145 SkColorSpace* colorSpace = bitmap.colorSpace();
1146 if (colorSpace != nullptr && bitmap.colorType() != kRGBA_F16_SkColorType) {
1147 sk_sp<SkData> data = colorSpace->serialize();
1148 size_t size = data->size();
1149 p->writeUint32(size);
1150 if (size > 0) {
1151 if (size > kMaxColorSpaceSerializedBytes) {
1152 ALOGD("Bitmap_writeToParcel: Serialized SkColorSpace is larger than expected: "
1153 "%zu bytes\n", size);
1154 }
1155
1156 p->write(data->data(), size);
1157 }
1158 } else {
1159 p->writeUint32(0);
1160 }
1161 p->writeInt32(bitmap.width());
1162 p->writeInt32(bitmap.height());
1163 p->writeInt32(bitmap.rowBytes());
1164 p->writeInt32(density);
1165
1166 // Transfer the underlying ashmem region if we have one and it's immutable.
1167 android::status_t status;
1168 int fd = bitmapWrapper->bitmap().getAshmemFd();
1169 if (fd >= 0 && !isMutable && p->allowFds()) {
1170 #if DEBUG_PARCEL
1171 ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as "
1172 "immutable blob (fds %s)",
1173 p->allowFds() ? "allowed" : "forbidden");
1174 #endif
1175
1176 status = p->writeDupImmutableBlobFileDescriptor(fd);
1177 if (status) {
1178 doThrowRE(env, "Could not write bitmap blob file descriptor.");
1179 return JNI_FALSE;
1180 }
1181 return JNI_TRUE;
1182 }
1183
1184 // Copy the bitmap to a new blob.
1185 bool mutableCopy = isMutable;
1186 #if DEBUG_PARCEL
1187 ALOGD("Bitmap.writeToParcel: copying %s bitmap into new %s blob (fds %s)",
1188 isMutable ? "mutable" : "immutable",
1189 mutableCopy ? "mutable" : "immutable",
1190 p->allowFds() ? "allowed" : "forbidden");
1191 #endif
1192
1193 size_t size = bitmap.getSize();
1194 android::Parcel::WritableBlob blob;
1195 status = p->writeBlob(size, mutableCopy, &blob);
1196 if (status) {
1197 doThrowRE(env, "Could not copy bitmap to parcel blob.");
1198 return JNI_FALSE;
1199 }
1200
1201 const void* pSrc = bitmap.getPixels();
1202 if (pSrc == NULL) {
1203 memset(blob.data(), 0, size);
1204 } else {
1205 memcpy(blob.data(), pSrc, size);
1206 }
1207
1208 blob.release();
1209 return JNI_TRUE;
1210 }
1211
Bitmap_extractAlpha(JNIEnv * env,jobject clazz,jlong srcHandle,jlong paintHandle,jintArray offsetXY)1212 static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
1213 jlong srcHandle, jlong paintHandle,
1214 jintArray offsetXY) {
1215 SkBitmap src;
1216 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
1217 const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle);
1218 SkIPoint offset;
1219 SkBitmap dst;
1220 HeapAllocator allocator;
1221
1222 src.extractAlpha(&dst, paint, &allocator, &offset);
1223 // If Skia can't allocate pixels for destination bitmap, it resets
1224 // it, that is set its pixels buffer to NULL, and zero width and height.
1225 if (dst.getPixels() == NULL && src.getPixels() != NULL) {
1226 doThrowOOME(env, "failed to allocate pixels for alpha");
1227 return NULL;
1228 }
1229 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
1230 int* array = env->GetIntArrayElements(offsetXY, NULL);
1231 array[0] = offset.fX;
1232 array[1] = offset.fY;
1233 env->ReleaseIntArrayElements(offsetXY, array, 0);
1234 }
1235
1236 return createBitmap(env, allocator.getStorageObjAndReset(),
1237 getPremulBitmapCreateFlags(true));
1238 }
1239
1240 ///////////////////////////////////////////////////////////////////////////////
1241
Bitmap_isSRGB(JNIEnv * env,jobject,jlong bitmapHandle)1242 static jboolean Bitmap_isSRGB(JNIEnv* env, jobject, jlong bitmapHandle) {
1243 LocalScopedBitmap bitmapHolder(bitmapHandle);
1244 if (!bitmapHolder.valid()) return JNI_TRUE;
1245
1246 SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
1247 return GraphicsJNI::isColorSpaceSRGB(colorSpace);
1248 }
1249
Bitmap_getColorSpace(JNIEnv * env,jobject,jlong bitmapHandle,jfloatArray xyzArray,jfloatArray paramsArray)1250 static jboolean Bitmap_getColorSpace(JNIEnv* env, jobject, jlong bitmapHandle,
1251 jfloatArray xyzArray, jfloatArray paramsArray) {
1252
1253 LocalScopedBitmap bitmapHolder(bitmapHandle);
1254 if (!bitmapHolder.valid()) return JNI_FALSE;
1255
1256 SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
1257 if (colorSpace == nullptr) return JNI_FALSE;
1258
1259 SkMatrix44 xyzMatrix(SkMatrix44::kUninitialized_Constructor);
1260 if (!colorSpace->toXYZD50(&xyzMatrix)) return JNI_FALSE;
1261
1262 jfloat* xyz = env->GetFloatArrayElements(xyzArray, NULL);
1263 xyz[0] = xyzMatrix.getFloat(0, 0);
1264 xyz[1] = xyzMatrix.getFloat(1, 0);
1265 xyz[2] = xyzMatrix.getFloat(2, 0);
1266 xyz[3] = xyzMatrix.getFloat(0, 1);
1267 xyz[4] = xyzMatrix.getFloat(1, 1);
1268 xyz[5] = xyzMatrix.getFloat(2, 1);
1269 xyz[6] = xyzMatrix.getFloat(0, 2);
1270 xyz[7] = xyzMatrix.getFloat(1, 2);
1271 xyz[8] = xyzMatrix.getFloat(2, 2);
1272 env->ReleaseFloatArrayElements(xyzArray, xyz, 0);
1273
1274 SkColorSpaceTransferFn transferParams;
1275 if (!colorSpace->isNumericalTransferFn(&transferParams)) return JNI_FALSE;
1276
1277 jfloat* params = env->GetFloatArrayElements(paramsArray, NULL);
1278 params[0] = transferParams.fA;
1279 params[1] = transferParams.fB;
1280 params[2] = transferParams.fC;
1281 params[3] = transferParams.fD;
1282 params[4] = transferParams.fE;
1283 params[5] = transferParams.fF;
1284 params[6] = transferParams.fG;
1285 env->ReleaseFloatArrayElements(paramsArray, params, 0);
1286
1287 return JNI_TRUE;
1288 }
1289
1290 ///////////////////////////////////////////////////////////////////////////////
1291
Bitmap_getPixel(JNIEnv * env,jobject,jlong bitmapHandle,jint x,jint y)1292 static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
1293 jint x, jint y) {
1294 SkBitmap bitmap;
1295 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1296
1297 ToColorProc proc = ChooseToColorProc(bitmap);
1298 if (NULL == proc) {
1299 return 0;
1300 }
1301 const void* src = bitmap.getAddr(x, y);
1302 if (NULL == src) {
1303 return 0;
1304 }
1305
1306 SkColor dst[1];
1307 proc(dst, src, 1);
1308
1309 SkColorSpace* colorSpace = bitmap.colorSpace();
1310 if (bitmap.colorType() != kRGBA_F16_SkColorType &&
1311 !GraphicsJNI::isColorSpaceSRGB(colorSpace)) {
1312 auto sRGB = SkColorSpace::MakeSRGB();
1313 auto xform = SkColorSpaceXform::New(colorSpace, sRGB.get());
1314 xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, &dst[0],
1315 SkColorSpaceXform::kBGRA_8888_ColorFormat, &dst[0], 1,
1316 SkAlphaType::kUnpremul_SkAlphaType);
1317 }
1318
1319 return static_cast<jint>(dst[0]);
1320 }
1321
Bitmap_getPixels(JNIEnv * env,jobject,jlong bitmapHandle,jintArray pixelArray,jint offset,jint stride,jint x,jint y,jint width,jint height)1322 static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,
1323 jintArray pixelArray, jint offset, jint stride,
1324 jint x, jint y, jint width, jint height) {
1325 SkBitmap bitmap;
1326 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1327
1328 ToColorProc proc = ChooseToColorProc(bitmap);
1329 if (NULL == proc) {
1330 return;
1331 }
1332 const void* src = bitmap.getAddr(x, y);
1333 if (NULL == src) {
1334 return;
1335 }
1336
1337 jint* dst = env->GetIntArrayElements(pixelArray, NULL);
1338 SkColor* d = (SkColor*)dst + offset;
1339
1340 SkColorSpace* colorSpace = bitmap.colorSpace();
1341 if (bitmap.colorType() == kRGBA_F16_SkColorType ||
1342 GraphicsJNI::isColorSpaceSRGB(colorSpace)) {
1343 while (--height >= 0) {
1344 proc(d, src, width);
1345 d += stride;
1346 src = (void*)((const char*)src + bitmap.rowBytes());
1347 }
1348 } else {
1349 auto sRGB = SkColorSpace::MakeSRGB();
1350 auto xform = SkColorSpaceXform::New(colorSpace, sRGB.get());
1351
1352 while (--height >= 0) {
1353 proc(d, src, width);
1354
1355 xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, d,
1356 SkColorSpaceXform::kBGRA_8888_ColorFormat, d, width,
1357 SkAlphaType::kUnpremul_SkAlphaType);
1358
1359 d += stride;
1360 src = (void*)((const char*)src + bitmap.rowBytes());
1361 }
1362 }
1363
1364 env->ReleaseIntArrayElements(pixelArray, dst, 0);
1365 }
1366
1367 ///////////////////////////////////////////////////////////////////////////////
1368
Bitmap_setPixel(JNIEnv * env,jobject,jlong bitmapHandle,jint x,jint y,jint colorHandle)1369 static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle,
1370 jint x, jint y, jint colorHandle) {
1371 SkBitmap bitmap;
1372 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1373 SkColor color = static_cast<SkColor>(colorHandle);
1374 if (NULL == bitmap.getPixels()) {
1375 return;
1376 }
1377
1378 FromColorProc proc = ChooseFromColorProc(bitmap);
1379 if (NULL == proc) {
1380 return;
1381 }
1382
1383 SkColorSpace* colorSpace = bitmap.colorSpace();
1384 if (bitmap.colorType() != kRGBA_F16_SkColorType &&
1385 !GraphicsJNI::isColorSpaceSRGB(colorSpace)) {
1386 auto sRGB = SkColorSpace::MakeSRGB();
1387 auto xform = SkColorSpaceXform::New(sRGB.get(), colorSpace);
1388 xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, &color,
1389 SkColorSpaceXform::kBGRA_8888_ColorFormat, &color, 1,
1390 SkAlphaType::kUnpremul_SkAlphaType);
1391 }
1392
1393 proc(bitmap.getAddr(x, y), &color, 1, x, y);
1394 bitmap.notifyPixelsChanged();
1395 }
1396
Bitmap_setPixels(JNIEnv * env,jobject,jlong bitmapHandle,jintArray pixelArray,jint offset,jint stride,jint x,jint y,jint width,jint height)1397 static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,
1398 jintArray pixelArray, jint offset, jint stride,
1399 jint x, jint y, jint width, jint height) {
1400 SkBitmap bitmap;
1401 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1402 GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
1403 x, y, width, height, bitmap);
1404 }
1405
Bitmap_copyPixelsToBuffer(JNIEnv * env,jobject,jlong bitmapHandle,jobject jbuffer)1406 static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
1407 jlong bitmapHandle, jobject jbuffer) {
1408 SkBitmap bitmap;
1409 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1410 const void* src = bitmap.getPixels();
1411
1412 if (NULL != src) {
1413 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
1414
1415 // the java side has already checked that buffer is large enough
1416 memcpy(abp.pointer(), src, bitmap.getSize());
1417 }
1418 }
1419
Bitmap_copyPixelsFromBuffer(JNIEnv * env,jobject,jlong bitmapHandle,jobject jbuffer)1420 static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,
1421 jlong bitmapHandle, jobject jbuffer) {
1422 SkBitmap bitmap;
1423 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1424 void* dst = bitmap.getPixels();
1425
1426 if (NULL != dst) {
1427 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);
1428 // the java side has already checked that buffer is large enough
1429 memcpy(dst, abp.pointer(), bitmap.getSize());
1430 bitmap.notifyPixelsChanged();
1431 }
1432 }
1433
Bitmap_sameAs(JNIEnv * env,jobject,jlong bm0Handle,jlong bm1Handle)1434 static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle, jlong bm1Handle) {
1435 SkBitmap bm0;
1436 SkBitmap bm1;
1437
1438 LocalScopedBitmap bitmap0(bm0Handle);
1439 LocalScopedBitmap bitmap1(bm1Handle);
1440
1441 // Paying the price for making Hardware Bitmap as Config:
1442 // later check for colorType will pass successfully,
1443 // because Hardware Config internally may be RGBA8888 or smth like that.
1444 if (bitmap0->isHardware() != bitmap1->isHardware()) {
1445 return JNI_FALSE;
1446 }
1447
1448 bitmap0->bitmap().getSkBitmap(&bm0);
1449 bitmap1->bitmap().getSkBitmap(&bm1);
1450 if (bm0.width() != bm1.width()
1451 || bm0.height() != bm1.height()
1452 || bm0.colorType() != bm1.colorType()
1453 || bm0.alphaType() != bm1.alphaType()
1454 || !SkColorSpace::Equals(bm0.colorSpace(), bm1.colorSpace())) {
1455 return JNI_FALSE;
1456 }
1457
1458 // if we can't load the pixels, return false
1459 if (NULL == bm0.getPixels() || NULL == bm1.getPixels()) {
1460 return JNI_FALSE;
1461 }
1462
1463 // now compare each scanline. We can't do the entire buffer at once,
1464 // since we don't care about the pixel values that might extend beyond
1465 // the width (since the scanline might be larger than the logical width)
1466 const int h = bm0.height();
1467 const size_t size = bm0.width() * bm0.bytesPerPixel();
1468 for (int y = 0; y < h; y++) {
1469 // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config
1470 // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0
1471 // and bm1 both have pixel data() (have passed NULL == getPixels() check),
1472 // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE
1473 // to warn user those 2 unrecognized config bitmaps may be different.
1474 void *bm0Addr = bm0.getAddr(0, y);
1475 void *bm1Addr = bm1.getAddr(0, y);
1476
1477 if(bm0Addr == NULL || bm1Addr == NULL) {
1478 return JNI_FALSE;
1479 }
1480
1481 if (memcmp(bm0Addr, bm1Addr, size) != 0) {
1482 return JNI_FALSE;
1483 }
1484 }
1485 return JNI_TRUE;
1486 }
1487
Bitmap_prepareToDraw(JNIEnv * env,jobject,jlong bitmapPtr)1488 static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapPtr) {
1489 LocalScopedBitmap bitmapHandle(bitmapPtr);
1490 if (!bitmapHandle.valid()) return;
1491 android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmapHandle->bitmap());
1492 }
1493
Bitmap_getAllocationByteCount(JNIEnv * env,jobject,jlong bitmapPtr)1494 static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr) {
1495 LocalScopedBitmap bitmapHandle(bitmapPtr);
1496 return static_cast<jint>(bitmapHandle->getAllocationByteCount());
1497 }
1498
Bitmap_copyPreserveInternalConfig(JNIEnv * env,jobject,jlong bitmapPtr)1499 static jobject Bitmap_copyPreserveInternalConfig(JNIEnv* env, jobject, jlong bitmapPtr) {
1500 LocalScopedBitmap bitmapHandle(bitmapPtr);
1501 LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
1502 "Hardware config is only supported config in Bitmap_nativeCopyPreserveInternalConfig");
1503 Bitmap& hwuiBitmap = bitmapHandle->bitmap();
1504 SkBitmap src;
1505 hwuiBitmap.getSkBitmap(&src);
1506
1507 SkBitmap result;
1508 HeapAllocator allocator;
1509 if (!bitmapCopyTo(&result, hwuiBitmap.info().colorType(), src, &allocator)) {
1510 doThrowRE(env, "Could not copy a hardware bitmap.");
1511 return NULL;
1512 }
1513 return createBitmap(env, allocator.getStorageObjAndReset(), getPremulBitmapCreateFlags(false));
1514 }
1515
Bitmap_createHardwareBitmap(JNIEnv * env,jobject,jobject graphicBuffer)1516 static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphicBuffer) {
1517 sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer));
1518 sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer);
1519 if (!bitmap.get()) {
1520 ALOGW("failed to create hardware bitmap from graphic buffer");
1521 return NULL;
1522 }
1523 return bitmap::createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false));
1524 }
1525
Bitmap_createGraphicBufferHandle(JNIEnv * env,jobject,jlong bitmapPtr)1526 static jobject Bitmap_createGraphicBufferHandle(JNIEnv* env, jobject, jlong bitmapPtr) {
1527 LocalScopedBitmap bitmapHandle(bitmapPtr);
1528 LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
1529 "Hardware config is only supported config in Bitmap_getGraphicBuffer");
1530
1531 Bitmap& hwuiBitmap = bitmapHandle->bitmap();
1532 sp<GraphicBuffer> buffer(hwuiBitmap.graphicBuffer());
1533 return createJavaGraphicBuffer(env, buffer);
1534 }
1535
Bitmap_copyColorSpace(JNIEnv * env,jobject,jlong srcBitmapPtr,jlong dstBitmapPtr)1536 static void Bitmap_copyColorSpace(JNIEnv* env, jobject, jlong srcBitmapPtr, jlong dstBitmapPtr) {
1537 LocalScopedBitmap srcBitmapHandle(srcBitmapPtr);
1538 LocalScopedBitmap dstBitmapHandle(dstBitmapPtr);
1539
1540 dstBitmapHandle->bitmap().setColorSpace(srcBitmapHandle->bitmap().info().refColorSpace());
1541 }
1542
1543 ///////////////////////////////////////////////////////////////////////////////
1544
1545 static const JNINativeMethod gBitmapMethods[] = {
1546 { "nativeCreate", "([IIIIIIZ[FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)Landroid/graphics/Bitmap;",
1547 (void*)Bitmap_creator },
1548 { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;",
1549 (void*)Bitmap_copy },
1550 { "nativeCopyAshmem", "(J)Landroid/graphics/Bitmap;",
1551 (void*)Bitmap_copyAshmem },
1552 { "nativeCopyAshmemConfig", "(JI)Landroid/graphics/Bitmap;",
1553 (void*)Bitmap_copyAshmemConfig },
1554 { "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer },
1555 { "nativeRecycle", "(J)Z", (void*)Bitmap_recycle },
1556 { "nativeReconfigure", "(JIIIZ)V", (void*)Bitmap_reconfigure },
1557 { "nativeCompress", "(JIILjava/io/OutputStream;[B)Z",
1558 (void*)Bitmap_compress },
1559 { "nativeErase", "(JI)V", (void*)Bitmap_erase },
1560 { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes },
1561 { "nativeConfig", "(J)I", (void*)Bitmap_config },
1562 { "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha },
1563 { "nativeIsPremultiplied", "(J)Z", (void*)Bitmap_isPremultiplied},
1564 { "nativeSetHasAlpha", "(JZZ)V", (void*)Bitmap_setHasAlpha},
1565 { "nativeSetPremultiplied", "(JZ)V", (void*)Bitmap_setPremultiplied},
1566 { "nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap },
1567 { "nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap },
1568 { "nativeCreateFromParcel",
1569 "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
1570 (void*)Bitmap_createFromParcel },
1571 { "nativeWriteToParcel", "(JZILandroid/os/Parcel;)Z",
1572 (void*)Bitmap_writeToParcel },
1573 { "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;",
1574 (void*)Bitmap_extractAlpha },
1575 { "nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId },
1576 { "nativeGetPixel", "(JII)I", (void*)Bitmap_getPixel },
1577 { "nativeGetPixels", "(J[IIIIIII)V", (void*)Bitmap_getPixels },
1578 { "nativeSetPixel", "(JIII)V", (void*)Bitmap_setPixel },
1579 { "nativeSetPixels", "(J[IIIIIII)V", (void*)Bitmap_setPixels },
1580 { "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V",
1581 (void*)Bitmap_copyPixelsToBuffer },
1582 { "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V",
1583 (void*)Bitmap_copyPixelsFromBuffer },
1584 { "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs },
1585 { "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw },
1586 { "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount },
1587 { "nativeCopyPreserveInternalConfig", "(J)Landroid/graphics/Bitmap;",
1588 (void*)Bitmap_copyPreserveInternalConfig },
1589 { "nativeCreateHardwareBitmap", "(Landroid/graphics/GraphicBuffer;)Landroid/graphics/Bitmap;",
1590 (void*) Bitmap_createHardwareBitmap },
1591 { "nativeCreateGraphicBufferHandle", "(J)Landroid/graphics/GraphicBuffer;",
1592 (void*) Bitmap_createGraphicBufferHandle },
1593 { "nativeGetColorSpace", "(J[F[F)Z", (void*)Bitmap_getColorSpace },
1594 { "nativeIsSRGB", "(J)Z", (void*)Bitmap_isSRGB },
1595 { "nativeCopyColorSpace", "(JJ)V",
1596 (void*)Bitmap_copyColorSpace },
1597 };
1598
register_android_graphics_Bitmap(JNIEnv * env)1599 int register_android_graphics_Bitmap(JNIEnv* env)
1600 {
1601 gBitmap_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Bitmap"));
1602 gBitmap_nativePtr = GetFieldIDOrDie(env, gBitmap_class, "mNativePtr", "J");
1603 gBitmap_constructorMethodID = GetMethodIDOrDie(env, gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
1604 gBitmap_reinitMethodID = GetMethodIDOrDie(env, gBitmap_class, "reinit", "(IIZ)V");
1605 gBitmap_getAllocationByteCountMethodID = GetMethodIDOrDie(env, gBitmap_class, "getAllocationByteCount", "()I");
1606 return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods,
1607 NELEM(gBitmapMethods));
1608 }
1609