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 if (skbitmap.colorType() == kRGBA_F16_SkColorType) {
925 // Convert to P3 before encoding. This matches SkAndroidCodec::computeOutputColorSpace
926 // for wide gamuts.
927 auto cs = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
928 SkColorSpace::kDCIP3_D65_Gamut);
929 auto info = skbitmap.info().makeColorType(kRGBA_8888_SkColorType)
930 .makeColorSpace(std::move(cs));
931 SkBitmap p3;
932 if (!p3.tryAllocPixels(info)) {
933 return JNI_FALSE;
934 }
935 auto xform = SkColorSpaceXform::New(skbitmap.colorSpace(), info.colorSpace());
936 if (!xform) {
937 return JNI_FALSE;
938 }
939 if (!xform->apply(SkColorSpaceXform::kRGBA_8888_ColorFormat, p3.getPixels(),
940 SkColorSpaceXform::kRGBA_F16_ColorFormat, skbitmap.getPixels(),
941 info.width() * info.height(), kUnpremul_SkAlphaType)) {
942 return JNI_FALSE;
943 }
944 skbitmap = p3;
945 }
946 return SkEncodeImage(strm.get(), skbitmap, fm, quality) ? JNI_TRUE : JNI_FALSE;
947 }
948
Bitmap_erase(JNIEnv * env,jobject,jlong bitmapHandle,jint color)949 static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) {
950 LocalScopedBitmap bitmap(bitmapHandle);
951 SkBitmap skBitmap;
952 bitmap->getSkBitmap(&skBitmap);
953 skBitmap.eraseColor(color);
954 }
955
Bitmap_rowBytes(JNIEnv * env,jobject,jlong bitmapHandle)956 static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {
957 LocalScopedBitmap bitmap(bitmapHandle);
958 return static_cast<jint>(bitmap->rowBytes());
959 }
960
Bitmap_config(JNIEnv * env,jobject,jlong bitmapHandle)961 static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) {
962 LocalScopedBitmap bitmap(bitmapHandle);
963 if (bitmap->isHardware()) {
964 return GraphicsJNI::hardwareLegacyBitmapConfig();
965 }
966 return GraphicsJNI::colorTypeToLegacyBitmapConfig(bitmap->info().colorType());
967 }
968
Bitmap_getGenerationId(JNIEnv * env,jobject,jlong bitmapHandle)969 static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {
970 LocalScopedBitmap bitmap(bitmapHandle);
971 return static_cast<jint>(bitmap->getGenerationID());
972 }
973
Bitmap_isPremultiplied(JNIEnv * env,jobject,jlong bitmapHandle)974 static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) {
975 LocalScopedBitmap bitmap(bitmapHandle);
976 if (bitmap->info().alphaType() == kPremul_SkAlphaType) {
977 return JNI_TRUE;
978 }
979 return JNI_FALSE;
980 }
981
Bitmap_hasAlpha(JNIEnv * env,jobject,jlong bitmapHandle)982 static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) {
983 LocalScopedBitmap bitmap(bitmapHandle);
984 return !bitmap->info().isOpaque() ? JNI_TRUE : JNI_FALSE;
985 }
986
Bitmap_setHasAlpha(JNIEnv * env,jobject,jlong bitmapHandle,jboolean hasAlpha,jboolean requestPremul)987 static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle,
988 jboolean hasAlpha, jboolean requestPremul) {
989 LocalScopedBitmap bitmap(bitmapHandle);
990 if (hasAlpha) {
991 bitmap->setAlphaType(
992 requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
993 } else {
994 bitmap->setAlphaType(kOpaque_SkAlphaType);
995 }
996 }
997
Bitmap_setPremultiplied(JNIEnv * env,jobject,jlong bitmapHandle,jboolean isPremul)998 static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
999 jboolean isPremul) {
1000 LocalScopedBitmap bitmap(bitmapHandle);
1001 if (!bitmap->info().isOpaque()) {
1002 if (isPremul) {
1003 bitmap->setAlphaType(kPremul_SkAlphaType);
1004 } else {
1005 bitmap->setAlphaType(kUnpremul_SkAlphaType);
1006 }
1007 }
1008 }
1009
Bitmap_hasMipMap(JNIEnv * env,jobject,jlong bitmapHandle)1010 static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) {
1011 LocalScopedBitmap bitmap(bitmapHandle);
1012 return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE;
1013 }
1014
Bitmap_setHasMipMap(JNIEnv * env,jobject,jlong bitmapHandle,jboolean hasMipMap)1015 static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle,
1016 jboolean hasMipMap) {
1017 LocalScopedBitmap bitmap(bitmapHandle);
1018 bitmap->setHasHardwareMipMap(hasMipMap);
1019 }
1020
1021 ///////////////////////////////////////////////////////////////////////////////
1022
1023 // This is the maximum possible size because the SkColorSpace must be
1024 // representable (and therefore serializable) using a matrix and numerical
1025 // transfer function. If we allow more color space representations in the
1026 // framework, we may need to update this maximum size.
1027 static constexpr uint32_t kMaxColorSpaceSerializedBytes = 80;
1028
Bitmap_createFromParcel(JNIEnv * env,jobject,jobject parcel)1029 static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
1030 if (parcel == NULL) {
1031 SkDebugf("-------- unparcel parcel is NULL\n");
1032 return NULL;
1033 }
1034
1035 android::Parcel* p = android::parcelForJavaObject(env, parcel);
1036
1037 const bool isMutable = p->readInt32() != 0;
1038 const SkColorType colorType = (SkColorType)p->readInt32();
1039 const SkAlphaType alphaType = (SkAlphaType)p->readInt32();
1040 const uint32_t colorSpaceSize = p->readUint32();
1041 sk_sp<SkColorSpace> colorSpace;
1042 if (kRGBA_F16_SkColorType == colorType) {
1043 colorSpace = SkColorSpace::MakeSRGBLinear();
1044 } else if (colorSpaceSize > 0) {
1045 if (colorSpaceSize > kMaxColorSpaceSerializedBytes) {
1046 ALOGD("Bitmap_createFromParcel: Serialized SkColorSpace is larger than expected: "
1047 "%d bytes\n", colorSpaceSize);
1048 }
1049
1050 const void* data = p->readInplace(colorSpaceSize);
1051 if (data) {
1052 colorSpace = SkColorSpace::Deserialize(data, colorSpaceSize);
1053 } else {
1054 ALOGD("Bitmap_createFromParcel: Unable to read serialized SkColorSpace data\n");
1055 }
1056 }
1057 const int width = p->readInt32();
1058 const int height = p->readInt32();
1059 const int rowBytes = p->readInt32();
1060 const int density = p->readInt32();
1061
1062 if (kN32_SkColorType != colorType &&
1063 kRGBA_F16_SkColorType != colorType &&
1064 kRGB_565_SkColorType != colorType &&
1065 kARGB_4444_SkColorType != colorType &&
1066 kAlpha_8_SkColorType != colorType) {
1067 SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType);
1068 return NULL;
1069 }
1070
1071 std::unique_ptr<SkBitmap> bitmap(new SkBitmap);
1072 if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType, colorSpace),
1073 rowBytes)) {
1074 return NULL;
1075 }
1076
1077 // Read the bitmap blob.
1078 size_t size = bitmap->computeByteSize();
1079 android::Parcel::ReadableBlob blob;
1080 android::status_t status = p->readBlob(size, &blob);
1081 if (status) {
1082 doThrowRE(env, "Could not read bitmap blob.");
1083 return NULL;
1084 }
1085
1086 // Map the bitmap in place from the ashmem region if possible otherwise copy.
1087 sk_sp<Bitmap> nativeBitmap;
1088 if (blob.fd() >= 0 && (blob.isMutable() || !isMutable) && (size >= ASHMEM_BITMAP_MIN_SIZE)) {
1089 #if DEBUG_PARCEL
1090 ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob "
1091 "(fds %s)",
1092 isMutable ? "mutable" : "immutable",
1093 blob.isMutable() ? "mutable" : "immutable",
1094 p->allowFds() ? "allowed" : "forbidden");
1095 #endif
1096 // Dup the file descriptor so we can keep a reference to it after the Parcel
1097 // is disposed.
1098 int dupFd = dup(blob.fd());
1099 if (dupFd < 0) {
1100 ALOGE("Error allocating dup fd. Error:%d", errno);
1101 blob.release();
1102 doThrowRE(env, "Could not allocate dup blob fd.");
1103 return NULL;
1104 }
1105
1106 // Map the pixels in place and take ownership of the ashmem region.
1107 nativeBitmap = sk_sp<Bitmap>(GraphicsJNI::mapAshmemBitmap(env, bitmap.get(),
1108 dupFd, const_cast<void*>(blob.data()), size, !isMutable));
1109 if (!nativeBitmap) {
1110 close(dupFd);
1111 blob.release();
1112 doThrowRE(env, "Could not allocate ashmem pixel ref.");
1113 return NULL;
1114 }
1115
1116 // Clear the blob handle, don't release it.
1117 blob.clear();
1118 } else {
1119 #if DEBUG_PARCEL
1120 if (blob.fd() >= 0) {
1121 ALOGD("Bitmap.createFromParcel: copied contents of mutable bitmap "
1122 "from immutable blob (fds %s)",
1123 p->allowFds() ? "allowed" : "forbidden");
1124 } else {
1125 ALOGD("Bitmap.createFromParcel: copied contents from %s blob "
1126 "(fds %s)",
1127 blob.isMutable() ? "mutable" : "immutable",
1128 p->allowFds() ? "allowed" : "forbidden");
1129 }
1130 #endif
1131
1132 // Copy the pixels into a new buffer.
1133 nativeBitmap = Bitmap::allocateHeapBitmap(bitmap.get());
1134 if (!nativeBitmap) {
1135 blob.release();
1136 doThrowRE(env, "Could not allocate java pixel ref.");
1137 return NULL;
1138 }
1139 memcpy(bitmap->getPixels(), blob.data(), size);
1140
1141 // Release the blob handle.
1142 blob.release();
1143 }
1144
1145 return createBitmap(env, nativeBitmap.release(),
1146 getPremulBitmapCreateFlags(isMutable), NULL, NULL, density);
1147 }
1148
Bitmap_writeToParcel(JNIEnv * env,jobject,jlong bitmapHandle,jboolean isMutable,jint density,jobject parcel)1149 static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
1150 jlong bitmapHandle,
1151 jboolean isMutable, jint density,
1152 jobject parcel) {
1153 if (parcel == NULL) {
1154 SkDebugf("------- writeToParcel null parcel\n");
1155 return JNI_FALSE;
1156 }
1157
1158 android::Parcel* p = android::parcelForJavaObject(env, parcel);
1159 SkBitmap bitmap;
1160
1161 auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle);
1162 bitmapWrapper->getSkBitmap(&bitmap);
1163
1164 p->writeInt32(isMutable);
1165 p->writeInt32(bitmap.colorType());
1166 p->writeInt32(bitmap.alphaType());
1167 SkColorSpace* colorSpace = bitmap.colorSpace();
1168 if (colorSpace != nullptr && bitmap.colorType() != kRGBA_F16_SkColorType) {
1169 sk_sp<SkData> data = colorSpace->serialize();
1170 size_t size = data->size();
1171 p->writeUint32(size);
1172 if (size > 0) {
1173 if (size > kMaxColorSpaceSerializedBytes) {
1174 ALOGD("Bitmap_writeToParcel: Serialized SkColorSpace is larger than expected: "
1175 "%zu bytes\n", size);
1176 }
1177
1178 p->write(data->data(), size);
1179 }
1180 } else {
1181 p->writeUint32(0);
1182 }
1183 p->writeInt32(bitmap.width());
1184 p->writeInt32(bitmap.height());
1185 p->writeInt32(bitmap.rowBytes());
1186 p->writeInt32(density);
1187
1188 // Transfer the underlying ashmem region if we have one and it's immutable.
1189 android::status_t status;
1190 int fd = bitmapWrapper->bitmap().getAshmemFd();
1191 if (fd >= 0 && !isMutable && p->allowFds()) {
1192 #if DEBUG_PARCEL
1193 ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as "
1194 "immutable blob (fds %s)",
1195 p->allowFds() ? "allowed" : "forbidden");
1196 #endif
1197
1198 status = p->writeDupImmutableBlobFileDescriptor(fd);
1199 if (status) {
1200 doThrowRE(env, "Could not write bitmap blob file descriptor.");
1201 return JNI_FALSE;
1202 }
1203 return JNI_TRUE;
1204 }
1205
1206 // Copy the bitmap to a new blob.
1207 bool mutableCopy = isMutable;
1208 #if DEBUG_PARCEL
1209 ALOGD("Bitmap.writeToParcel: copying %s bitmap into new %s blob (fds %s)",
1210 isMutable ? "mutable" : "immutable",
1211 mutableCopy ? "mutable" : "immutable",
1212 p->allowFds() ? "allowed" : "forbidden");
1213 #endif
1214
1215 size_t size = bitmap.computeByteSize();
1216 android::Parcel::WritableBlob blob;
1217 status = p->writeBlob(size, mutableCopy, &blob);
1218 if (status) {
1219 doThrowRE(env, "Could not copy bitmap to parcel blob.");
1220 return JNI_FALSE;
1221 }
1222
1223 const void* pSrc = bitmap.getPixels();
1224 if (pSrc == NULL) {
1225 memset(blob.data(), 0, size);
1226 } else {
1227 memcpy(blob.data(), pSrc, size);
1228 }
1229
1230 blob.release();
1231 return JNI_TRUE;
1232 }
1233
Bitmap_extractAlpha(JNIEnv * env,jobject clazz,jlong srcHandle,jlong paintHandle,jintArray offsetXY)1234 static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
1235 jlong srcHandle, jlong paintHandle,
1236 jintArray offsetXY) {
1237 SkBitmap src;
1238 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
1239 const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle);
1240 SkIPoint offset;
1241 SkBitmap dst;
1242 HeapAllocator allocator;
1243
1244 src.extractAlpha(&dst, paint, &allocator, &offset);
1245 // If Skia can't allocate pixels for destination bitmap, it resets
1246 // it, that is set its pixels buffer to NULL, and zero width and height.
1247 if (dst.getPixels() == NULL && src.getPixels() != NULL) {
1248 doThrowOOME(env, "failed to allocate pixels for alpha");
1249 return NULL;
1250 }
1251 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
1252 int* array = env->GetIntArrayElements(offsetXY, NULL);
1253 array[0] = offset.fX;
1254 array[1] = offset.fY;
1255 env->ReleaseIntArrayElements(offsetXY, array, 0);
1256 }
1257
1258 return createBitmap(env, allocator.getStorageObjAndReset(),
1259 getPremulBitmapCreateFlags(true));
1260 }
1261
1262 ///////////////////////////////////////////////////////////////////////////////
1263
Bitmap_isSRGB(JNIEnv * env,jobject,jlong bitmapHandle)1264 static jboolean Bitmap_isSRGB(JNIEnv* env, jobject, jlong bitmapHandle) {
1265 LocalScopedBitmap bitmapHolder(bitmapHandle);
1266 if (!bitmapHolder.valid()) return JNI_TRUE;
1267
1268 SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
1269 return GraphicsJNI::isColorSpaceSRGB(colorSpace);
1270 }
1271
Bitmap_isSRGBLinear(JNIEnv * env,jobject,jlong bitmapHandle)1272 static jboolean Bitmap_isSRGBLinear(JNIEnv* env, jobject, jlong bitmapHandle) {
1273 LocalScopedBitmap bitmapHolder(bitmapHandle);
1274 if (!bitmapHolder.valid()) return JNI_FALSE;
1275
1276 SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
1277 sk_sp<SkColorSpace> srgbLinear = SkColorSpace::MakeSRGBLinear();
1278 return colorSpace == srgbLinear.get() ? JNI_TRUE : JNI_FALSE;
1279 }
1280
Bitmap_getColorSpace(JNIEnv * env,jobject,jlong bitmapHandle,jfloatArray xyzArray,jfloatArray paramsArray)1281 static jboolean Bitmap_getColorSpace(JNIEnv* env, jobject, jlong bitmapHandle,
1282 jfloatArray xyzArray, jfloatArray paramsArray) {
1283
1284 LocalScopedBitmap bitmapHolder(bitmapHandle);
1285 if (!bitmapHolder.valid()) return JNI_FALSE;
1286
1287 SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
1288 if (colorSpace == nullptr) return JNI_FALSE;
1289
1290 SkMatrix44 xyzMatrix(SkMatrix44::kUninitialized_Constructor);
1291 if (!colorSpace->toXYZD50(&xyzMatrix)) return JNI_FALSE;
1292
1293 jfloat* xyz = env->GetFloatArrayElements(xyzArray, NULL);
1294 xyz[0] = xyzMatrix.getFloat(0, 0);
1295 xyz[1] = xyzMatrix.getFloat(1, 0);
1296 xyz[2] = xyzMatrix.getFloat(2, 0);
1297 xyz[3] = xyzMatrix.getFloat(0, 1);
1298 xyz[4] = xyzMatrix.getFloat(1, 1);
1299 xyz[5] = xyzMatrix.getFloat(2, 1);
1300 xyz[6] = xyzMatrix.getFloat(0, 2);
1301 xyz[7] = xyzMatrix.getFloat(1, 2);
1302 xyz[8] = xyzMatrix.getFloat(2, 2);
1303 env->ReleaseFloatArrayElements(xyzArray, xyz, 0);
1304
1305 SkColorSpaceTransferFn transferParams;
1306 if (!colorSpace->isNumericalTransferFn(&transferParams)) return JNI_FALSE;
1307
1308 jfloat* params = env->GetFloatArrayElements(paramsArray, NULL);
1309 params[0] = transferParams.fA;
1310 params[1] = transferParams.fB;
1311 params[2] = transferParams.fC;
1312 params[3] = transferParams.fD;
1313 params[4] = transferParams.fE;
1314 params[5] = transferParams.fF;
1315 params[6] = transferParams.fG;
1316 env->ReleaseFloatArrayElements(paramsArray, params, 0);
1317
1318 return JNI_TRUE;
1319 }
1320
1321 ///////////////////////////////////////////////////////////////////////////////
1322
Bitmap_getPixel(JNIEnv * env,jobject,jlong bitmapHandle,jint x,jint y)1323 static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
1324 jint x, jint y) {
1325 SkBitmap bitmap;
1326 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1327
1328 ToColorProc proc = ChooseToColorProc(bitmap);
1329 if (NULL == proc) {
1330 return 0;
1331 }
1332 const void* src = bitmap.getAddr(x, y);
1333 if (NULL == src) {
1334 return 0;
1335 }
1336
1337 SkColor dst[1];
1338 proc(dst, src, 1);
1339
1340 SkColorSpace* colorSpace = bitmap.colorSpace();
1341 if (bitmap.colorType() != kRGBA_F16_SkColorType &&
1342 !GraphicsJNI::isColorSpaceSRGB(colorSpace)) {
1343 auto sRGB = SkColorSpace::MakeSRGB();
1344 auto xform = SkColorSpaceXform::New(colorSpace, sRGB.get());
1345 xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, &dst[0],
1346 SkColorSpaceXform::kBGRA_8888_ColorFormat, &dst[0], 1,
1347 SkAlphaType::kUnpremul_SkAlphaType);
1348 }
1349
1350 return static_cast<jint>(dst[0]);
1351 }
1352
Bitmap_getPixels(JNIEnv * env,jobject,jlong bitmapHandle,jintArray pixelArray,jint offset,jint stride,jint x,jint y,jint width,jint height)1353 static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,
1354 jintArray pixelArray, jint offset, jint stride,
1355 jint x, jint y, jint width, jint height) {
1356 SkBitmap bitmap;
1357 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1358
1359 ToColorProc proc = ChooseToColorProc(bitmap);
1360 if (NULL == proc) {
1361 return;
1362 }
1363 const void* src = bitmap.getAddr(x, y);
1364 if (NULL == src) {
1365 return;
1366 }
1367
1368 jint* dst = env->GetIntArrayElements(pixelArray, NULL);
1369 SkColor* d = (SkColor*)dst + offset;
1370
1371 SkColorSpace* colorSpace = bitmap.colorSpace();
1372 if (bitmap.colorType() == kRGBA_F16_SkColorType ||
1373 GraphicsJNI::isColorSpaceSRGB(colorSpace)) {
1374 while (--height >= 0) {
1375 proc(d, src, width);
1376 d += stride;
1377 src = (void*)((const char*)src + bitmap.rowBytes());
1378 }
1379 } else {
1380 auto sRGB = SkColorSpace::MakeSRGB();
1381 auto xform = SkColorSpaceXform::New(colorSpace, sRGB.get());
1382
1383 while (--height >= 0) {
1384 proc(d, src, width);
1385
1386 xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, d,
1387 SkColorSpaceXform::kBGRA_8888_ColorFormat, d, width,
1388 SkAlphaType::kUnpremul_SkAlphaType);
1389
1390 d += stride;
1391 src = (void*)((const char*)src + bitmap.rowBytes());
1392 }
1393 }
1394
1395 env->ReleaseIntArrayElements(pixelArray, dst, 0);
1396 }
1397
1398 ///////////////////////////////////////////////////////////////////////////////
1399
Bitmap_setPixel(JNIEnv * env,jobject,jlong bitmapHandle,jint x,jint y,jint colorHandle)1400 static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle,
1401 jint x, jint y, jint colorHandle) {
1402 SkBitmap bitmap;
1403 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1404 SkColor color = static_cast<SkColor>(colorHandle);
1405 if (NULL == bitmap.getPixels()) {
1406 return;
1407 }
1408
1409 FromColorProc proc = ChooseFromColorProc(bitmap);
1410 if (NULL == proc) {
1411 return;
1412 }
1413
1414 SkColorSpace* colorSpace = bitmap.colorSpace();
1415 if (bitmap.colorType() != kRGBA_F16_SkColorType &&
1416 !GraphicsJNI::isColorSpaceSRGB(colorSpace)) {
1417 auto sRGB = SkColorSpace::MakeSRGB();
1418 auto xform = SkColorSpaceXform::New(sRGB.get(), colorSpace);
1419 xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, &color,
1420 SkColorSpaceXform::kBGRA_8888_ColorFormat, &color, 1,
1421 SkAlphaType::kUnpremul_SkAlphaType);
1422 }
1423
1424 proc(bitmap.getAddr(x, y), &color, 1, x, y);
1425 bitmap.notifyPixelsChanged();
1426 }
1427
Bitmap_setPixels(JNIEnv * env,jobject,jlong bitmapHandle,jintArray pixelArray,jint offset,jint stride,jint x,jint y,jint width,jint height)1428 static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,
1429 jintArray pixelArray, jint offset, jint stride,
1430 jint x, jint y, jint width, jint height) {
1431 SkBitmap bitmap;
1432 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1433 GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
1434 x, y, width, height, bitmap);
1435 }
1436
Bitmap_copyPixelsToBuffer(JNIEnv * env,jobject,jlong bitmapHandle,jobject jbuffer)1437 static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
1438 jlong bitmapHandle, jobject jbuffer) {
1439 SkBitmap bitmap;
1440 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1441 const void* src = bitmap.getPixels();
1442
1443 if (NULL != src) {
1444 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
1445
1446 // the java side has already checked that buffer is large enough
1447 memcpy(abp.pointer(), src, bitmap.computeByteSize());
1448 }
1449 }
1450
Bitmap_copyPixelsFromBuffer(JNIEnv * env,jobject,jlong bitmapHandle,jobject jbuffer)1451 static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,
1452 jlong bitmapHandle, jobject jbuffer) {
1453 SkBitmap bitmap;
1454 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1455 void* dst = bitmap.getPixels();
1456
1457 if (NULL != dst) {
1458 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);
1459 // the java side has already checked that buffer is large enough
1460 memcpy(dst, abp.pointer(), bitmap.computeByteSize());
1461 bitmap.notifyPixelsChanged();
1462 }
1463 }
1464
Bitmap_sameAs(JNIEnv * env,jobject,jlong bm0Handle,jlong bm1Handle)1465 static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle, jlong bm1Handle) {
1466 SkBitmap bm0;
1467 SkBitmap bm1;
1468
1469 LocalScopedBitmap bitmap0(bm0Handle);
1470 LocalScopedBitmap bitmap1(bm1Handle);
1471
1472 // Paying the price for making Hardware Bitmap as Config:
1473 // later check for colorType will pass successfully,
1474 // because Hardware Config internally may be RGBA8888 or smth like that.
1475 if (bitmap0->isHardware() != bitmap1->isHardware()) {
1476 return JNI_FALSE;
1477 }
1478
1479 bitmap0->bitmap().getSkBitmap(&bm0);
1480 bitmap1->bitmap().getSkBitmap(&bm1);
1481 if (bm0.width() != bm1.width()
1482 || bm0.height() != bm1.height()
1483 || bm0.colorType() != bm1.colorType()
1484 || bm0.alphaType() != bm1.alphaType()
1485 || !SkColorSpace::Equals(bm0.colorSpace(), bm1.colorSpace())) {
1486 return JNI_FALSE;
1487 }
1488
1489 // if we can't load the pixels, return false
1490 if (NULL == bm0.getPixels() || NULL == bm1.getPixels()) {
1491 return JNI_FALSE;
1492 }
1493
1494 // now compare each scanline. We can't do the entire buffer at once,
1495 // since we don't care about the pixel values that might extend beyond
1496 // the width (since the scanline might be larger than the logical width)
1497 const int h = bm0.height();
1498 const size_t size = bm0.width() * bm0.bytesPerPixel();
1499 for (int y = 0; y < h; y++) {
1500 // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config
1501 // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0
1502 // and bm1 both have pixel data() (have passed NULL == getPixels() check),
1503 // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE
1504 // to warn user those 2 unrecognized config bitmaps may be different.
1505 void *bm0Addr = bm0.getAddr(0, y);
1506 void *bm1Addr = bm1.getAddr(0, y);
1507
1508 if(bm0Addr == NULL || bm1Addr == NULL) {
1509 return JNI_FALSE;
1510 }
1511
1512 if (memcmp(bm0Addr, bm1Addr, size) != 0) {
1513 return JNI_FALSE;
1514 }
1515 }
1516 return JNI_TRUE;
1517 }
1518
Bitmap_prepareToDraw(JNIEnv * env,jobject,jlong bitmapPtr)1519 static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapPtr) {
1520 LocalScopedBitmap bitmapHandle(bitmapPtr);
1521 if (!bitmapHandle.valid()) return;
1522 android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmapHandle->bitmap());
1523 }
1524
Bitmap_getAllocationByteCount(JNIEnv * env,jobject,jlong bitmapPtr)1525 static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr) {
1526 LocalScopedBitmap bitmapHandle(bitmapPtr);
1527 return static_cast<jint>(bitmapHandle->getAllocationByteCount());
1528 }
1529
Bitmap_copyPreserveInternalConfig(JNIEnv * env,jobject,jlong bitmapPtr)1530 static jobject Bitmap_copyPreserveInternalConfig(JNIEnv* env, jobject, jlong bitmapPtr) {
1531 LocalScopedBitmap bitmapHandle(bitmapPtr);
1532 LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
1533 "Hardware config is only supported config in Bitmap_nativeCopyPreserveInternalConfig");
1534 Bitmap& hwuiBitmap = bitmapHandle->bitmap();
1535 SkBitmap src;
1536 hwuiBitmap.getSkBitmap(&src);
1537
1538 SkBitmap result;
1539 HeapAllocator allocator;
1540 if (!bitmapCopyTo(&result, hwuiBitmap.info().colorType(), src, &allocator)) {
1541 doThrowRE(env, "Could not copy a hardware bitmap.");
1542 return NULL;
1543 }
1544 return createBitmap(env, allocator.getStorageObjAndReset(), getPremulBitmapCreateFlags(false));
1545 }
1546
Bitmap_createHardwareBitmap(JNIEnv * env,jobject,jobject graphicBuffer)1547 static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphicBuffer) {
1548 sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer));
1549 sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer);
1550 if (!bitmap.get()) {
1551 ALOGW("failed to create hardware bitmap from graphic buffer");
1552 return NULL;
1553 }
1554 return bitmap::createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false));
1555 }
1556
Bitmap_createGraphicBufferHandle(JNIEnv * env,jobject,jlong bitmapPtr)1557 static jobject Bitmap_createGraphicBufferHandle(JNIEnv* env, jobject, jlong bitmapPtr) {
1558 LocalScopedBitmap bitmapHandle(bitmapPtr);
1559 LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
1560 "Hardware config is only supported config in Bitmap_getGraphicBuffer");
1561
1562 Bitmap& hwuiBitmap = bitmapHandle->bitmap();
1563 sp<GraphicBuffer> buffer(hwuiBitmap.graphicBuffer());
1564 return createJavaGraphicBuffer(env, buffer);
1565 }
1566
Bitmap_copyColorSpace(JNIEnv * env,jobject,jlong srcBitmapPtr,jlong dstBitmapPtr)1567 static void Bitmap_copyColorSpace(JNIEnv* env, jobject, jlong srcBitmapPtr, jlong dstBitmapPtr) {
1568 LocalScopedBitmap srcBitmapHandle(srcBitmapPtr);
1569 LocalScopedBitmap dstBitmapHandle(dstBitmapPtr);
1570
1571 dstBitmapHandle->bitmap().setColorSpace(srcBitmapHandle->bitmap().info().refColorSpace());
1572 }
1573
1574 ///////////////////////////////////////////////////////////////////////////////
1575
1576 static const JNINativeMethod gBitmapMethods[] = {
1577 { "nativeCreate", "([IIIIIIZ[FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)Landroid/graphics/Bitmap;",
1578 (void*)Bitmap_creator },
1579 { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;",
1580 (void*)Bitmap_copy },
1581 { "nativeCopyAshmem", "(J)Landroid/graphics/Bitmap;",
1582 (void*)Bitmap_copyAshmem },
1583 { "nativeCopyAshmemConfig", "(JI)Landroid/graphics/Bitmap;",
1584 (void*)Bitmap_copyAshmemConfig },
1585 { "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer },
1586 { "nativeRecycle", "(J)Z", (void*)Bitmap_recycle },
1587 { "nativeReconfigure", "(JIIIZ)V", (void*)Bitmap_reconfigure },
1588 { "nativeCompress", "(JIILjava/io/OutputStream;[B)Z",
1589 (void*)Bitmap_compress },
1590 { "nativeErase", "(JI)V", (void*)Bitmap_erase },
1591 { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes },
1592 { "nativeConfig", "(J)I", (void*)Bitmap_config },
1593 { "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha },
1594 { "nativeIsPremultiplied", "(J)Z", (void*)Bitmap_isPremultiplied},
1595 { "nativeSetHasAlpha", "(JZZ)V", (void*)Bitmap_setHasAlpha},
1596 { "nativeSetPremultiplied", "(JZ)V", (void*)Bitmap_setPremultiplied},
1597 { "nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap },
1598 { "nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap },
1599 { "nativeCreateFromParcel",
1600 "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
1601 (void*)Bitmap_createFromParcel },
1602 { "nativeWriteToParcel", "(JZILandroid/os/Parcel;)Z",
1603 (void*)Bitmap_writeToParcel },
1604 { "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;",
1605 (void*)Bitmap_extractAlpha },
1606 { "nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId },
1607 { "nativeGetPixel", "(JII)I", (void*)Bitmap_getPixel },
1608 { "nativeGetPixels", "(J[IIIIIII)V", (void*)Bitmap_getPixels },
1609 { "nativeSetPixel", "(JIII)V", (void*)Bitmap_setPixel },
1610 { "nativeSetPixels", "(J[IIIIIII)V", (void*)Bitmap_setPixels },
1611 { "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V",
1612 (void*)Bitmap_copyPixelsToBuffer },
1613 { "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V",
1614 (void*)Bitmap_copyPixelsFromBuffer },
1615 { "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs },
1616 { "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw },
1617 { "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount },
1618 { "nativeCopyPreserveInternalConfig", "(J)Landroid/graphics/Bitmap;",
1619 (void*)Bitmap_copyPreserveInternalConfig },
1620 { "nativeCreateHardwareBitmap", "(Landroid/graphics/GraphicBuffer;)Landroid/graphics/Bitmap;",
1621 (void*) Bitmap_createHardwareBitmap },
1622 { "nativeCreateGraphicBufferHandle", "(J)Landroid/graphics/GraphicBuffer;",
1623 (void*) Bitmap_createGraphicBufferHandle },
1624 { "nativeGetColorSpace", "(J[F[F)Z", (void*)Bitmap_getColorSpace },
1625 { "nativeIsSRGB", "(J)Z", (void*)Bitmap_isSRGB },
1626 { "nativeIsSRGBLinear", "(J)Z", (void*)Bitmap_isSRGBLinear},
1627 { "nativeCopyColorSpace", "(JJ)V",
1628 (void*)Bitmap_copyColorSpace },
1629 };
1630
register_android_graphics_Bitmap(JNIEnv * env)1631 int register_android_graphics_Bitmap(JNIEnv* env)
1632 {
1633 gBitmap_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Bitmap"));
1634 gBitmap_nativePtr = GetFieldIDOrDie(env, gBitmap_class, "mNativePtr", "J");
1635 gBitmap_constructorMethodID = GetMethodIDOrDie(env, gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
1636 gBitmap_reinitMethodID = GetMethodIDOrDie(env, gBitmap_class, "reinit", "(IIZ)V");
1637 gBitmap_getAllocationByteCountMethodID = GetMethodIDOrDie(env, gBitmap_class, "getAllocationByteCount", "()I");
1638 return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods,
1639 NELEM(gBitmapMethods));
1640 }
1641