1 #undef LOG_TAG
2 #define LOG_TAG "Bitmap"
3 #include "Bitmap.h"
4
5 #include "SkBitmap.h"
6 #include "SkPixelRef.h"
7 #include "SkImageEncoder.h"
8 #include "SkImageInfo.h"
9 #include "SkColor.h"
10 #include "SkColorSpace.h"
11 #include "GraphicsJNI.h"
12 #include "SkStream.h"
13 #include "SkWebpEncoder.h"
14
15 #include "android_nio_utils.h"
16 #include "CreateJavaOutputStreamAdaptor.h"
17 #include <hwui/Paint.h>
18 #include <hwui/Bitmap.h>
19 #include <utils/Color.h>
20
21 #ifdef __ANDROID__ // Layoutlib does not support graphic buffer, parcel or render thread
22 #include <private/android/AHardwareBufferHelpers.h>
23 #include <binder/Parcel.h>
24 #include <dlfcn.h>
25 #include <renderthread/RenderProxy.h>
26 #endif
27
28 #include <string.h>
29 #include <memory>
30 #include <string>
31
32 #define DEBUG_PARCEL 0
33
34 static jclass gBitmap_class;
35 static jfieldID gBitmap_nativePtr;
36 static jmethodID gBitmap_constructorMethodID;
37 static jmethodID gBitmap_reinitMethodID;
38
39 namespace android {
40
41 class BitmapWrapper {
42 public:
BitmapWrapper(Bitmap * bitmap)43 explicit BitmapWrapper(Bitmap* bitmap)
44 : mBitmap(bitmap) { }
45
freePixels()46 void freePixels() {
47 mInfo = mBitmap->info();
48 mHasHardwareMipMap = mBitmap->hasHardwareMipMap();
49 mAllocationSize = mBitmap->getAllocationByteCount();
50 mRowBytes = mBitmap->rowBytes();
51 mGenerationId = mBitmap->getGenerationID();
52 mIsHardware = mBitmap->isHardware();
53 mBitmap.reset();
54 }
55
valid()56 bool valid() {
57 return mBitmap != nullptr;
58 }
59
bitmap()60 Bitmap& bitmap() {
61 assertValid();
62 return *mBitmap;
63 }
64
assertValid()65 void assertValid() {
66 LOG_ALWAYS_FATAL_IF(!valid(), "Error, cannot access an invalid/free'd bitmap here!");
67 }
68
getSkBitmap(SkBitmap * outBitmap)69 void getSkBitmap(SkBitmap* outBitmap) {
70 assertValid();
71 mBitmap->getSkBitmap(outBitmap);
72 }
73
hasHardwareMipMap()74 bool hasHardwareMipMap() {
75 if (mBitmap) {
76 return mBitmap->hasHardwareMipMap();
77 }
78 return mHasHardwareMipMap;
79 }
80
setHasHardwareMipMap(bool hasMipMap)81 void setHasHardwareMipMap(bool hasMipMap) {
82 assertValid();
83 mBitmap->setHasHardwareMipMap(hasMipMap);
84 }
85
setAlphaType(SkAlphaType alphaType)86 void setAlphaType(SkAlphaType alphaType) {
87 assertValid();
88 mBitmap->setAlphaType(alphaType);
89 }
90
setColorSpace(sk_sp<SkColorSpace> colorSpace)91 void setColorSpace(sk_sp<SkColorSpace> colorSpace) {
92 assertValid();
93 mBitmap->setColorSpace(colorSpace);
94 }
95
info()96 const SkImageInfo& info() {
97 if (mBitmap) {
98 return mBitmap->info();
99 }
100 return mInfo;
101 }
102
getAllocationByteCount() const103 size_t getAllocationByteCount() const {
104 if (mBitmap) {
105 return mBitmap->getAllocationByteCount();
106 }
107 return mAllocationSize;
108 }
109
rowBytes() const110 size_t rowBytes() const {
111 if (mBitmap) {
112 return mBitmap->rowBytes();
113 }
114 return mRowBytes;
115 }
116
getGenerationID() const117 uint32_t getGenerationID() const {
118 if (mBitmap) {
119 return mBitmap->getGenerationID();
120 }
121 return mGenerationId;
122 }
123
isHardware()124 bool isHardware() {
125 if (mBitmap) {
126 return mBitmap->isHardware();
127 }
128 return mIsHardware;
129 }
130
~BitmapWrapper()131 ~BitmapWrapper() { }
132
133 private:
134 sk_sp<Bitmap> mBitmap;
135 SkImageInfo mInfo;
136 bool mHasHardwareMipMap;
137 size_t mAllocationSize;
138 size_t mRowBytes;
139 uint32_t mGenerationId;
140 bool mIsHardware;
141 };
142
143 // Convenience class that does not take a global ref on the pixels, relying
144 // on the caller already having a local JNI ref
145 class LocalScopedBitmap {
146 public:
LocalScopedBitmap(jlong bitmapHandle)147 explicit LocalScopedBitmap(jlong bitmapHandle)
148 : mBitmapWrapper(reinterpret_cast<BitmapWrapper*>(bitmapHandle)) {}
149
operator ->()150 BitmapWrapper* operator->() {
151 return mBitmapWrapper;
152 }
153
pixels()154 void* pixels() {
155 return mBitmapWrapper->bitmap().pixels();
156 }
157
valid()158 bool valid() {
159 return mBitmapWrapper && mBitmapWrapper->valid();
160 }
161
162 private:
163 BitmapWrapper* mBitmapWrapper;
164 };
165
166 namespace bitmap {
167
168 // Assert that bitmap's SkAlphaType is consistent with isPremultiplied.
assert_premultiplied(const SkImageInfo & info,bool isPremultiplied)169 static void assert_premultiplied(const SkImageInfo& info, bool isPremultiplied) {
170 // kOpaque_SkAlphaType and kIgnore_SkAlphaType mean that isPremultiplied is
171 // irrelevant. This just tests to ensure that the SkAlphaType is not
172 // opposite of isPremultiplied.
173 if (isPremultiplied) {
174 SkASSERT(info.alphaType() != kUnpremul_SkAlphaType);
175 } else {
176 SkASSERT(info.alphaType() != kPremul_SkAlphaType);
177 }
178 }
179
reinitBitmap(JNIEnv * env,jobject javaBitmap,const SkImageInfo & info,bool isPremultiplied)180 void reinitBitmap(JNIEnv* env, jobject javaBitmap, const SkImageInfo& info,
181 bool isPremultiplied)
182 {
183 // The caller needs to have already set the alpha type properly, so the
184 // native SkBitmap stays in sync with the Java Bitmap.
185 assert_premultiplied(info, isPremultiplied);
186
187 env->CallVoidMethod(javaBitmap, gBitmap_reinitMethodID,
188 info.width(), info.height(), isPremultiplied);
189 }
190
createBitmap(JNIEnv * env,Bitmap * bitmap,int bitmapCreateFlags,jbyteArray ninePatchChunk,jobject ninePatchInsets,int density)191 jobject createBitmap(JNIEnv* env, Bitmap* bitmap,
192 int bitmapCreateFlags, jbyteArray ninePatchChunk, jobject ninePatchInsets,
193 int density) {
194 bool isMutable = bitmapCreateFlags & kBitmapCreateFlag_Mutable;
195 bool isPremultiplied = bitmapCreateFlags & kBitmapCreateFlag_Premultiplied;
196 // The caller needs to have already set the alpha type properly, so the
197 // native SkBitmap stays in sync with the Java Bitmap.
198 assert_premultiplied(bitmap->info(), isPremultiplied);
199 bool fromMalloc = bitmap->pixelStorageType() == PixelStorageType::Heap;
200 BitmapWrapper* bitmapWrapper = new BitmapWrapper(bitmap);
201 if (!isMutable) {
202 bitmapWrapper->bitmap().setImmutable();
203 }
204 jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
205 reinterpret_cast<jlong>(bitmapWrapper), bitmap->width(), bitmap->height(), density,
206 isPremultiplied, ninePatchChunk, ninePatchInsets, fromMalloc);
207
208 if (env->ExceptionCheck() != 0) {
209 ALOGE("*** Uncaught exception returned from Java call!\n");
210 env->ExceptionDescribe();
211 }
212 return obj;
213 }
214
toSkBitmap(jlong bitmapHandle,SkBitmap * outBitmap)215 void toSkBitmap(jlong bitmapHandle, SkBitmap* outBitmap) {
216 LocalScopedBitmap bitmap(bitmapHandle);
217 bitmap->getSkBitmap(outBitmap);
218 }
219
toBitmap(jlong bitmapHandle)220 Bitmap& toBitmap(jlong bitmapHandle) {
221 LocalScopedBitmap localBitmap(bitmapHandle);
222 return localBitmap->bitmap();
223 }
224
225 } // namespace bitmap
226
227 } // namespace android
228
229 using namespace android;
230 using namespace android::bitmap;
231
getNativeBitmap(JNIEnv * env,jobject bitmap)232 Bitmap* GraphicsJNI::getNativeBitmap(JNIEnv* env, jobject bitmap) {
233 SkASSERT(env);
234 SkASSERT(bitmap);
235 SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
236 jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
237 LocalScopedBitmap localBitmap(bitmapHandle);
238 return localBitmap.valid() ? &localBitmap->bitmap() : nullptr;
239 }
240
getBitmapInfo(JNIEnv * env,jobject bitmap,uint32_t * outRowBytes,bool * isHardware)241 SkImageInfo GraphicsJNI::getBitmapInfo(JNIEnv* env, jobject bitmap, uint32_t* outRowBytes,
242 bool* isHardware) {
243 SkASSERT(env);
244 SkASSERT(bitmap);
245 SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
246 jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
247 LocalScopedBitmap localBitmap(bitmapHandle);
248 if (outRowBytes) {
249 *outRowBytes = localBitmap->rowBytes();
250 }
251 if (isHardware) {
252 *isHardware = localBitmap->isHardware();
253 }
254 return localBitmap->info();
255 }
256
SetPixels(JNIEnv * env,jintArray srcColors,int srcOffset,int srcStride,int x,int y,int width,int height,SkBitmap * dstBitmap)257 bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride,
258 int x, int y, int width, int height, SkBitmap* dstBitmap) {
259 const jint* array = env->GetIntArrayElements(srcColors, NULL);
260 const SkColor* src = (const SkColor*)array + srcOffset;
261
262 auto sRGB = SkColorSpace::MakeSRGB();
263 SkImageInfo srcInfo = SkImageInfo::Make(
264 width, height, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
265 SkPixmap srcPM(srcInfo, src, srcStride * 4);
266
267 dstBitmap->writePixels(srcPM, x, y);
268
269 env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array), JNI_ABORT);
270 return true;
271 }
272
273 ///////////////////////////////////////////////////////////////////////////////
274 ///////////////////////////////////////////////////////////////////////////////
275
getPremulBitmapCreateFlags(bool isMutable)276 static int getPremulBitmapCreateFlags(bool isMutable) {
277 int flags = android::bitmap::kBitmapCreateFlag_Premultiplied;
278 if (isMutable) flags |= android::bitmap::kBitmapCreateFlag_Mutable;
279 return flags;
280 }
281
Bitmap_creator(JNIEnv * env,jobject,jintArray jColors,jint offset,jint stride,jint width,jint height,jint configHandle,jboolean isMutable,jlong colorSpacePtr)282 static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
283 jint offset, jint stride, jint width, jint height,
284 jint configHandle, jboolean isMutable,
285 jlong colorSpacePtr) {
286 SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
287 if (NULL != jColors) {
288 size_t n = env->GetArrayLength(jColors);
289 if (n < SkAbs32(stride) * (size_t)height) {
290 doThrowAIOOBE(env);
291 return NULL;
292 }
293 }
294
295 // ARGB_4444 is a deprecated format, convert automatically to 8888
296 if (colorType == kARGB_4444_SkColorType) {
297 colorType = kN32_SkColorType;
298 }
299
300 sk_sp<SkColorSpace> colorSpace;
301 if (colorType == kAlpha_8_SkColorType) {
302 colorSpace = nullptr;
303 } else {
304 colorSpace = GraphicsJNI::getNativeColorSpace(colorSpacePtr);
305 }
306
307 SkBitmap bitmap;
308 bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType,
309 colorSpace));
310
311 sk_sp<Bitmap> nativeBitmap = Bitmap::allocateHeapBitmap(&bitmap);
312 if (!nativeBitmap) {
313 ALOGE("OOM allocating Bitmap with dimensions %i x %i", width, height);
314 doThrowOOME(env);
315 return NULL;
316 }
317
318 if (jColors != NULL) {
319 GraphicsJNI::SetPixels(env, jColors, offset, stride, 0, 0, width, height, &bitmap);
320 }
321
322 return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable));
323 }
324
bitmapCopyTo(SkBitmap * dst,SkColorType dstCT,const SkBitmap & src,SkBitmap::Allocator * alloc)325 static bool bitmapCopyTo(SkBitmap* dst, SkColorType dstCT, const SkBitmap& src,
326 SkBitmap::Allocator* alloc) {
327 SkPixmap srcPM;
328 if (!src.peekPixels(&srcPM)) {
329 return false;
330 }
331
332 SkImageInfo dstInfo = srcPM.info().makeColorType(dstCT);
333 switch (dstCT) {
334 case kRGB_565_SkColorType:
335 dstInfo = dstInfo.makeAlphaType(kOpaque_SkAlphaType);
336 break;
337 case kAlpha_8_SkColorType:
338 dstInfo = dstInfo.makeColorSpace(nullptr);
339 break;
340 default:
341 break;
342 }
343
344 if (!dstInfo.colorSpace() && dstCT != kAlpha_8_SkColorType) {
345 dstInfo = dstInfo.makeColorSpace(SkColorSpace::MakeSRGB());
346 }
347
348 if (!dst->setInfo(dstInfo)) {
349 return false;
350 }
351 if (!dst->tryAllocPixels(alloc)) {
352 return false;
353 }
354
355 SkPixmap dstPM;
356 if (!dst->peekPixels(&dstPM)) {
357 return false;
358 }
359
360 return srcPM.readPixels(dstPM);
361 }
362
Bitmap_copy(JNIEnv * env,jobject,jlong srcHandle,jint dstConfigHandle,jboolean isMutable)363 static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle,
364 jint dstConfigHandle, jboolean isMutable) {
365 SkBitmap src;
366 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
367 if (dstConfigHandle == GraphicsJNI::hardwareLegacyBitmapConfig()) {
368 sk_sp<Bitmap> bitmap(Bitmap::allocateHardwareBitmap(src));
369 if (!bitmap.get()) {
370 return NULL;
371 }
372 return createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(isMutable));
373 }
374
375 SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
376 SkBitmap result;
377 HeapAllocator allocator;
378
379 if (!bitmapCopyTo(&result, dstCT, src, &allocator)) {
380 return NULL;
381 }
382 auto bitmap = allocator.getStorageObjAndReset();
383 return createBitmap(env, bitmap, getPremulBitmapCreateFlags(isMutable));
384 }
385
Bitmap_copyAshmemImpl(JNIEnv * env,SkBitmap & src,SkColorType & dstCT)386 static Bitmap* Bitmap_copyAshmemImpl(JNIEnv* env, SkBitmap& src, SkColorType& dstCT) {
387 SkBitmap result;
388
389 AshmemPixelAllocator allocator(env);
390 if (!bitmapCopyTo(&result, dstCT, src, &allocator)) {
391 return NULL;
392 }
393 auto bitmap = allocator.getStorageObjAndReset();
394 bitmap->setImmutable();
395 return bitmap;
396 }
397
Bitmap_copyAshmem(JNIEnv * env,jobject,jlong srcHandle)398 static jobject Bitmap_copyAshmem(JNIEnv* env, jobject, jlong srcHandle) {
399 SkBitmap src;
400 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
401 SkColorType dstCT = src.colorType();
402 auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
403 jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
404 return ret;
405 }
406
Bitmap_copyAshmemConfig(JNIEnv * env,jobject,jlong srcHandle,jint dstConfigHandle)407 static jobject Bitmap_copyAshmemConfig(JNIEnv* env, jobject, jlong srcHandle, jint dstConfigHandle) {
408 SkBitmap src;
409 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
410 SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
411 auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
412 jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
413 return ret;
414 }
415
Bitmap_destruct(BitmapWrapper * bitmap)416 static void Bitmap_destruct(BitmapWrapper* bitmap) {
417 delete bitmap;
418 }
419
Bitmap_getNativeFinalizer(JNIEnv *,jobject)420 static jlong Bitmap_getNativeFinalizer(JNIEnv*, jobject) {
421 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Bitmap_destruct));
422 }
423
Bitmap_recycle(JNIEnv * env,jobject,jlong bitmapHandle)424 static void Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {
425 LocalScopedBitmap bitmap(bitmapHandle);
426 bitmap->freePixels();
427 }
428
Bitmap_reconfigure(JNIEnv * env,jobject clazz,jlong bitmapHandle,jint width,jint height,jint configHandle,jboolean requestPremul)429 static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
430 jint width, jint height, jint configHandle, jboolean requestPremul) {
431 LocalScopedBitmap bitmap(bitmapHandle);
432 bitmap->assertValid();
433 SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
434
435 // ARGB_4444 is a deprecated format, convert automatically to 8888
436 if (colorType == kARGB_4444_SkColorType) {
437 colorType = kN32_SkColorType;
438 }
439 size_t requestedSize = width * height * SkColorTypeBytesPerPixel(colorType);
440 if (requestedSize > bitmap->getAllocationByteCount()) {
441 // done in native as there's no way to get BytesPerPixel in Java
442 doThrowIAE(env, "Bitmap not large enough to support new configuration");
443 return;
444 }
445 SkAlphaType alphaType;
446 if (bitmap->info().colorType() != kRGB_565_SkColorType
447 && bitmap->info().alphaType() == kOpaque_SkAlphaType) {
448 // If the original bitmap was set to opaque, keep that setting, unless it
449 // was 565, which is required to be opaque.
450 alphaType = kOpaque_SkAlphaType;
451 } else {
452 // Otherwise respect the premultiplied request.
453 alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
454 }
455 bitmap->bitmap().reconfigure(SkImageInfo::Make(width, height, colorType, alphaType,
456 sk_ref_sp(bitmap->info().colorSpace())));
457 }
458
Bitmap_compress(JNIEnv * env,jobject clazz,jlong bitmapHandle,jint format,jint quality,jobject jstream,jbyteArray jstorage)459 static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle,
460 jint format, jint quality,
461 jobject jstream, jbyteArray jstorage) {
462 LocalScopedBitmap bitmap(bitmapHandle);
463 if (!bitmap.valid()) {
464 return JNI_FALSE;
465 }
466
467 std::unique_ptr<SkWStream> strm(CreateJavaOutputStreamAdaptor(env, jstream, jstorage));
468 if (!strm.get()) {
469 return JNI_FALSE;
470 }
471
472 auto fm = static_cast<Bitmap::JavaCompressFormat>(format);
473 return bitmap->bitmap().compress(fm, quality, strm.get()) ? JNI_TRUE : JNI_FALSE;
474 }
475
bitmapErase(SkBitmap bitmap,const SkColor4f & color,const sk_sp<SkColorSpace> & colorSpace)476 static inline void bitmapErase(SkBitmap bitmap, const SkColor4f& color,
477 const sk_sp<SkColorSpace>& colorSpace) {
478 SkPaint p;
479 p.setColor4f(color, colorSpace.get());
480 p.setBlendMode(SkBlendMode::kSrc);
481 SkCanvas canvas(bitmap);
482 canvas.drawPaint(p);
483 }
484
Bitmap_erase(JNIEnv * env,jobject,jlong bitmapHandle,jint color)485 static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) {
486 LocalScopedBitmap bitmap(bitmapHandle);
487 SkBitmap skBitmap;
488 bitmap->getSkBitmap(&skBitmap);
489 bitmapErase(skBitmap, SkColor4f::FromColor(color), SkColorSpace::MakeSRGB());
490 }
491
Bitmap_eraseLong(JNIEnv * env,jobject,jlong bitmapHandle,jlong colorSpaceHandle,jlong colorLong)492 static void Bitmap_eraseLong(JNIEnv* env, jobject, jlong bitmapHandle,
493 jlong colorSpaceHandle, jlong colorLong) {
494 LocalScopedBitmap bitmap(bitmapHandle);
495 SkBitmap skBitmap;
496 bitmap->getSkBitmap(&skBitmap);
497
498 SkColor4f color = GraphicsJNI::convertColorLong(colorLong);
499 sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
500 bitmapErase(skBitmap, color, cs);
501 }
502
Bitmap_rowBytes(JNIEnv * env,jobject,jlong bitmapHandle)503 static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {
504 LocalScopedBitmap bitmap(bitmapHandle);
505 return static_cast<jint>(bitmap->rowBytes());
506 }
507
Bitmap_config(JNIEnv * env,jobject,jlong bitmapHandle)508 static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) {
509 LocalScopedBitmap bitmap(bitmapHandle);
510 if (bitmap->isHardware()) {
511 return GraphicsJNI::hardwareLegacyBitmapConfig();
512 }
513 return GraphicsJNI::colorTypeToLegacyBitmapConfig(bitmap->info().colorType());
514 }
515
Bitmap_getGenerationId(JNIEnv * env,jobject,jlong bitmapHandle)516 static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {
517 LocalScopedBitmap bitmap(bitmapHandle);
518 return static_cast<jint>(bitmap->getGenerationID());
519 }
520
Bitmap_isPremultiplied(JNIEnv * env,jobject,jlong bitmapHandle)521 static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) {
522 LocalScopedBitmap bitmap(bitmapHandle);
523 if (bitmap->info().alphaType() == kPremul_SkAlphaType) {
524 return JNI_TRUE;
525 }
526 return JNI_FALSE;
527 }
528
Bitmap_hasAlpha(JNIEnv * env,jobject,jlong bitmapHandle)529 static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) {
530 LocalScopedBitmap bitmap(bitmapHandle);
531 return !bitmap->info().isOpaque() ? JNI_TRUE : JNI_FALSE;
532 }
533
Bitmap_setHasAlpha(JNIEnv * env,jobject,jlong bitmapHandle,jboolean hasAlpha,jboolean requestPremul)534 static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle,
535 jboolean hasAlpha, jboolean requestPremul) {
536 LocalScopedBitmap bitmap(bitmapHandle);
537 if (hasAlpha) {
538 bitmap->setAlphaType(
539 requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
540 } else {
541 bitmap->setAlphaType(kOpaque_SkAlphaType);
542 }
543 }
544
Bitmap_setPremultiplied(JNIEnv * env,jobject,jlong bitmapHandle,jboolean isPremul)545 static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
546 jboolean isPremul) {
547 LocalScopedBitmap bitmap(bitmapHandle);
548 if (!bitmap->info().isOpaque()) {
549 if (isPremul) {
550 bitmap->setAlphaType(kPremul_SkAlphaType);
551 } else {
552 bitmap->setAlphaType(kUnpremul_SkAlphaType);
553 }
554 }
555 }
556
Bitmap_hasMipMap(JNIEnv * env,jobject,jlong bitmapHandle)557 static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) {
558 LocalScopedBitmap bitmap(bitmapHandle);
559 return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE;
560 }
561
Bitmap_setHasMipMap(JNIEnv * env,jobject,jlong bitmapHandle,jboolean hasMipMap)562 static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle,
563 jboolean hasMipMap) {
564 LocalScopedBitmap bitmap(bitmapHandle);
565 bitmap->setHasHardwareMipMap(hasMipMap);
566 }
567
568 ///////////////////////////////////////////////////////////////////////////////
569
570 #ifdef __ANDROID__ // Layoutlib does not support parcel
571 static struct parcel_offsets_t
572 {
573 jclass clazz;
574 jfieldID mNativePtr;
575 } gParcelOffsets;
576
parcelForJavaObject(JNIEnv * env,jobject obj)577 static Parcel* parcelForJavaObject(JNIEnv* env, jobject obj) {
578 if (obj) {
579 Parcel* p = (Parcel*)env->GetLongField(obj, gParcelOffsets.mNativePtr);
580 if (p != NULL) {
581 return p;
582 }
583 jniThrowException(env, "java/lang/IllegalStateException", "Parcel has been finalized!");
584 }
585 return NULL;
586 }
587 #endif
588
589 // This is the maximum possible size because the SkColorSpace must be
590 // representable (and therefore serializable) using a matrix and numerical
591 // transfer function. If we allow more color space representations in the
592 // framework, we may need to update this maximum size.
593 static constexpr uint32_t kMaxColorSpaceSerializedBytes = 80;
594
Bitmap_createFromParcel(JNIEnv * env,jobject,jobject parcel)595 static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
596 #ifdef __ANDROID__ // Layoutlib does not support parcel
597 if (parcel == NULL) {
598 SkDebugf("-------- unparcel parcel is NULL\n");
599 return NULL;
600 }
601
602 android::Parcel* p = parcelForJavaObject(env, parcel);
603
604 const bool isMutable = p->readInt32() != 0;
605 const SkColorType colorType = (SkColorType)p->readInt32();
606 const SkAlphaType alphaType = (SkAlphaType)p->readInt32();
607 const uint32_t colorSpaceSize = p->readUint32();
608 sk_sp<SkColorSpace> colorSpace;
609 if (colorSpaceSize > 0) {
610 if (colorSpaceSize > kMaxColorSpaceSerializedBytes) {
611 ALOGD("Bitmap_createFromParcel: Serialized SkColorSpace is larger than expected: "
612 "%d bytes\n", colorSpaceSize);
613 }
614
615 const void* data = p->readInplace(colorSpaceSize);
616 if (data) {
617 colorSpace = SkColorSpace::Deserialize(data, colorSpaceSize);
618 } else {
619 ALOGD("Bitmap_createFromParcel: Unable to read serialized SkColorSpace data\n");
620 }
621 }
622 const int width = p->readInt32();
623 const int height = p->readInt32();
624 const int rowBytes = p->readInt32();
625 const int density = p->readInt32();
626
627 if (kN32_SkColorType != colorType &&
628 kRGBA_F16_SkColorType != colorType &&
629 kRGB_565_SkColorType != colorType &&
630 kARGB_4444_SkColorType != colorType &&
631 kAlpha_8_SkColorType != colorType) {
632 SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType);
633 return NULL;
634 }
635
636 std::unique_ptr<SkBitmap> bitmap(new SkBitmap);
637 if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType, colorSpace),
638 rowBytes)) {
639 return NULL;
640 }
641
642 // Read the bitmap blob.
643 size_t size = bitmap->computeByteSize();
644 android::Parcel::ReadableBlob blob;
645 android::status_t status = p->readBlob(size, &blob);
646 if (status) {
647 doThrowRE(env, "Could not read bitmap blob.");
648 return NULL;
649 }
650
651 // Map the bitmap in place from the ashmem region if possible otherwise copy.
652 sk_sp<Bitmap> nativeBitmap;
653 // If the blob is mutable we have ownership of the region and can always use it
654 // If the blob is immutable _and_ we're immutable, we can then still use it
655 if (blob.fd() >= 0 && (blob.isMutable() || !isMutable)) {
656 #if DEBUG_PARCEL
657 ALOGD("Bitmap.createFromParcel: mapped contents of bitmap from %s blob "
658 "(fds %s)",
659 blob.isMutable() ? "mutable" : "immutable",
660 p->allowFds() ? "allowed" : "forbidden");
661 #endif
662 // Dup the file descriptor so we can keep a reference to it after the Parcel
663 // is disposed.
664 int dupFd = fcntl(blob.fd(), F_DUPFD_CLOEXEC, 0);
665 if (dupFd < 0) {
666 ALOGE("Error allocating dup fd. Error:%d", errno);
667 blob.release();
668 doThrowRE(env, "Could not allocate dup blob fd.");
669 return NULL;
670 }
671
672 // Map the pixels in place and take ownership of the ashmem region. We must also respect the
673 // rowBytes value already set on the bitmap instead of attempting to compute our own.
674 nativeBitmap = Bitmap::createFrom(bitmap->info(), bitmap->rowBytes(), dupFd,
675 const_cast<void*>(blob.data()), size, !isMutable);
676 if (!nativeBitmap) {
677 close(dupFd);
678 blob.release();
679 doThrowRE(env, "Could not allocate ashmem pixel ref.");
680 return NULL;
681 }
682
683 // Clear the blob handle, don't release it.
684 blob.clear();
685 } else {
686 #if DEBUG_PARCEL
687 if (blob.fd() >= 0) {
688 ALOGD("Bitmap.createFromParcel: copied contents of mutable bitmap "
689 "from immutable blob (fds %s)",
690 p->allowFds() ? "allowed" : "forbidden");
691 } else {
692 ALOGD("Bitmap.createFromParcel: copied contents from %s blob "
693 "(fds %s)",
694 blob.isMutable() ? "mutable" : "immutable",
695 p->allowFds() ? "allowed" : "forbidden");
696 }
697 #endif
698
699 // Copy the pixels into a new buffer.
700 nativeBitmap = Bitmap::allocateHeapBitmap(bitmap.get());
701 if (!nativeBitmap) {
702 blob.release();
703 doThrowRE(env, "Could not allocate java pixel ref.");
704 return NULL;
705 }
706 memcpy(bitmap->getPixels(), blob.data(), size);
707
708 // Release the blob handle.
709 blob.release();
710 }
711
712 return createBitmap(env, nativeBitmap.release(),
713 getPremulBitmapCreateFlags(isMutable), NULL, NULL, density);
714 #else
715 doThrowRE(env, "Cannot use parcels outside of Android");
716 return NULL;
717 #endif
718 }
719
Bitmap_writeToParcel(JNIEnv * env,jobject,jlong bitmapHandle,jint density,jobject parcel)720 static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
721 jlong bitmapHandle, jint density, jobject parcel) {
722 #ifdef __ANDROID__ // Layoutlib does not support parcel
723 if (parcel == NULL) {
724 SkDebugf("------- writeToParcel null parcel\n");
725 return JNI_FALSE;
726 }
727
728 android::Parcel* p = parcelForJavaObject(env, parcel);
729 SkBitmap bitmap;
730
731 auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle);
732 bitmapWrapper->getSkBitmap(&bitmap);
733
734 p->writeInt32(!bitmap.isImmutable());
735 p->writeInt32(bitmap.colorType());
736 p->writeInt32(bitmap.alphaType());
737 SkColorSpace* colorSpace = bitmap.colorSpace();
738 if (colorSpace != nullptr) {
739 sk_sp<SkData> data = colorSpace->serialize();
740 size_t size = data->size();
741 p->writeUint32(size);
742 if (size > 0) {
743 if (size > kMaxColorSpaceSerializedBytes) {
744 ALOGD("Bitmap_writeToParcel: Serialized SkColorSpace is larger than expected: "
745 "%zu bytes\n", size);
746 }
747
748 p->write(data->data(), size);
749 }
750 } else {
751 p->writeUint32(0);
752 }
753 p->writeInt32(bitmap.width());
754 p->writeInt32(bitmap.height());
755 p->writeInt32(bitmap.rowBytes());
756 p->writeInt32(density);
757
758 // Transfer the underlying ashmem region if we have one and it's immutable.
759 android::status_t status;
760 int fd = bitmapWrapper->bitmap().getAshmemFd();
761 if (fd >= 0 && bitmap.isImmutable() && p->allowFds()) {
762 #if DEBUG_PARCEL
763 ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as "
764 "immutable blob (fds %s)",
765 p->allowFds() ? "allowed" : "forbidden");
766 #endif
767
768 status = p->writeDupImmutableBlobFileDescriptor(fd);
769 if (status) {
770 doThrowRE(env, "Could not write bitmap blob file descriptor.");
771 return JNI_FALSE;
772 }
773 return JNI_TRUE;
774 }
775
776 // Copy the bitmap to a new blob.
777 #if DEBUG_PARCEL
778 ALOGD("Bitmap.writeToParcel: copying bitmap into new blob (fds %s)",
779 p->allowFds() ? "allowed" : "forbidden");
780 #endif
781
782 const bool mutableCopy = !bitmap.isImmutable();
783 size_t size = bitmap.computeByteSize();
784 android::Parcel::WritableBlob blob;
785 status = p->writeBlob(size, mutableCopy, &blob);
786 if (status) {
787 doThrowRE(env, "Could not copy bitmap to parcel blob.");
788 return JNI_FALSE;
789 }
790
791 const void* pSrc = bitmap.getPixels();
792 if (pSrc == NULL) {
793 memset(blob.data(), 0, size);
794 } else {
795 memcpy(blob.data(), pSrc, size);
796 }
797
798 blob.release();
799 return JNI_TRUE;
800 #else
801 doThrowRE(env, "Cannot use parcels outside of Android");
802 return JNI_FALSE;
803 #endif
804 }
805
Bitmap_extractAlpha(JNIEnv * env,jobject clazz,jlong srcHandle,jlong paintHandle,jintArray offsetXY)806 static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
807 jlong srcHandle, jlong paintHandle,
808 jintArray offsetXY) {
809 SkBitmap src;
810 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
811 const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle);
812 SkIPoint offset;
813 SkBitmap dst;
814 HeapAllocator allocator;
815
816 src.extractAlpha(&dst, paint, &allocator, &offset);
817 // If Skia can't allocate pixels for destination bitmap, it resets
818 // it, that is set its pixels buffer to NULL, and zero width and height.
819 if (dst.getPixels() == NULL && src.getPixels() != NULL) {
820 doThrowOOME(env, "failed to allocate pixels for alpha");
821 return NULL;
822 }
823 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
824 int* array = env->GetIntArrayElements(offsetXY, NULL);
825 array[0] = offset.fX;
826 array[1] = offset.fY;
827 env->ReleaseIntArrayElements(offsetXY, array, 0);
828 }
829
830 return createBitmap(env, allocator.getStorageObjAndReset(),
831 getPremulBitmapCreateFlags(true));
832 }
833
834 ///////////////////////////////////////////////////////////////////////////////
835
Bitmap_isSRGB(JNIEnv * env,jobject,jlong bitmapHandle)836 static jboolean Bitmap_isSRGB(JNIEnv* env, jobject, jlong bitmapHandle) {
837 LocalScopedBitmap bitmapHolder(bitmapHandle);
838 if (!bitmapHolder.valid()) return JNI_TRUE;
839
840 SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
841 return colorSpace == nullptr || colorSpace->isSRGB();
842 }
843
Bitmap_isSRGBLinear(JNIEnv * env,jobject,jlong bitmapHandle)844 static jboolean Bitmap_isSRGBLinear(JNIEnv* env, jobject, jlong bitmapHandle) {
845 LocalScopedBitmap bitmapHolder(bitmapHandle);
846 if (!bitmapHolder.valid()) return JNI_FALSE;
847
848 SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
849 sk_sp<SkColorSpace> srgbLinear = SkColorSpace::MakeSRGBLinear();
850 return colorSpace == srgbLinear.get() ? JNI_TRUE : JNI_FALSE;
851 }
852
Bitmap_computeColorSpace(JNIEnv * env,jobject,jlong bitmapHandle)853 static jobject Bitmap_computeColorSpace(JNIEnv* env, jobject, jlong bitmapHandle) {
854 LocalScopedBitmap bitmapHolder(bitmapHandle);
855 if (!bitmapHolder.valid()) return nullptr;
856
857 SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
858 if (colorSpace == nullptr) return nullptr;
859
860 return GraphicsJNI::getColorSpace(env, colorSpace, bitmapHolder->info().colorType());
861 }
862
Bitmap_setColorSpace(JNIEnv * env,jobject,jlong bitmapHandle,jlong colorSpacePtr)863 static void Bitmap_setColorSpace(JNIEnv* env, jobject, jlong bitmapHandle, jlong colorSpacePtr) {
864 LocalScopedBitmap bitmapHolder(bitmapHandle);
865 sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(colorSpacePtr);
866 bitmapHolder->setColorSpace(cs);
867 }
868
869 ///////////////////////////////////////////////////////////////////////////////
870
Bitmap_getPixel(JNIEnv * env,jobject,jlong bitmapHandle,jint x,jint y)871 static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
872 jint x, jint y) {
873 SkBitmap bitmap;
874 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
875
876 auto sRGB = SkColorSpace::MakeSRGB();
877 SkImageInfo dstInfo = SkImageInfo::Make(
878 1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
879
880 SkColor dst;
881 bitmap.readPixels(dstInfo, &dst, dstInfo.minRowBytes(), x, y);
882 return static_cast<jint>(dst);
883 }
884
Bitmap_getColor(JNIEnv * env,jobject,jlong bitmapHandle,jint x,jint y)885 static jlong Bitmap_getColor(JNIEnv* env, jobject, jlong bitmapHandle,
886 jint x, jint y) {
887 SkBitmap bitmap;
888 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
889
890 SkImageInfo dstInfo = SkImageInfo::Make(
891 1, 1, kRGBA_F16_SkColorType, kUnpremul_SkAlphaType, bitmap.refColorSpace());
892
893 uint64_t dst;
894 bitmap.readPixels(dstInfo, &dst, dstInfo.minRowBytes(), x, y);
895 return static_cast<jlong>(dst);
896 }
897
Bitmap_getPixels(JNIEnv * env,jobject,jlong bitmapHandle,jintArray pixelArray,jint offset,jint stride,jint x,jint y,jint width,jint height)898 static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,
899 jintArray pixelArray, jint offset, jint stride,
900 jint x, jint y, jint width, jint height) {
901 SkBitmap bitmap;
902 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
903
904 auto sRGB = SkColorSpace::MakeSRGB();
905 SkImageInfo dstInfo = SkImageInfo::Make(
906 width, height, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
907
908 jint* dst = env->GetIntArrayElements(pixelArray, NULL);
909 bitmap.readPixels(dstInfo, dst + offset, stride * 4, x, y);
910 env->ReleaseIntArrayElements(pixelArray, dst, 0);
911 }
912
913 ///////////////////////////////////////////////////////////////////////////////
914
Bitmap_setPixel(JNIEnv * env,jobject,jlong bitmapHandle,jint x,jint y,jint colorHandle)915 static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle,
916 jint x, jint y, jint colorHandle) {
917 SkBitmap bitmap;
918 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
919 SkColor color = static_cast<SkColor>(colorHandle);
920
921 auto sRGB = SkColorSpace::MakeSRGB();
922 SkImageInfo srcInfo = SkImageInfo::Make(
923 1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
924 SkPixmap srcPM(srcInfo, &color, srcInfo.minRowBytes());
925
926 bitmap.writePixels(srcPM, x, y);
927 }
928
Bitmap_setPixels(JNIEnv * env,jobject,jlong bitmapHandle,jintArray pixelArray,jint offset,jint stride,jint x,jint y,jint width,jint height)929 static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,
930 jintArray pixelArray, jint offset, jint stride,
931 jint x, jint y, jint width, jint height) {
932 SkBitmap bitmap;
933 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
934 GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
935 x, y, width, height, &bitmap);
936 }
937
Bitmap_copyPixelsToBuffer(JNIEnv * env,jobject,jlong bitmapHandle,jobject jbuffer)938 static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
939 jlong bitmapHandle, jobject jbuffer) {
940 SkBitmap bitmap;
941 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
942 const void* src = bitmap.getPixels();
943
944 if (NULL != src) {
945 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
946
947 // the java side has already checked that buffer is large enough
948 memcpy(abp.pointer(), src, bitmap.computeByteSize());
949 }
950 }
951
Bitmap_copyPixelsFromBuffer(JNIEnv * env,jobject,jlong bitmapHandle,jobject jbuffer)952 static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,
953 jlong bitmapHandle, jobject jbuffer) {
954 SkBitmap bitmap;
955 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
956 void* dst = bitmap.getPixels();
957
958 if (NULL != dst) {
959 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);
960 // the java side has already checked that buffer is large enough
961 memcpy(dst, abp.pointer(), bitmap.computeByteSize());
962 bitmap.notifyPixelsChanged();
963 }
964 }
965
Bitmap_sameAs(JNIEnv * env,jobject,jlong bm0Handle,jlong bm1Handle)966 static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle, jlong bm1Handle) {
967 SkBitmap bm0;
968 SkBitmap bm1;
969
970 LocalScopedBitmap bitmap0(bm0Handle);
971 LocalScopedBitmap bitmap1(bm1Handle);
972
973 // Paying the price for making Hardware Bitmap as Config:
974 // later check for colorType will pass successfully,
975 // because Hardware Config internally may be RGBA8888 or smth like that.
976 if (bitmap0->isHardware() != bitmap1->isHardware()) {
977 return JNI_FALSE;
978 }
979
980 bitmap0->bitmap().getSkBitmap(&bm0);
981 bitmap1->bitmap().getSkBitmap(&bm1);
982 if (bm0.width() != bm1.width()
983 || bm0.height() != bm1.height()
984 || bm0.colorType() != bm1.colorType()
985 || bm0.alphaType() != bm1.alphaType()
986 || !SkColorSpace::Equals(bm0.colorSpace(), bm1.colorSpace())) {
987 return JNI_FALSE;
988 }
989
990 // if we can't load the pixels, return false
991 if (NULL == bm0.getPixels() || NULL == bm1.getPixels()) {
992 return JNI_FALSE;
993 }
994
995 // now compare each scanline. We can't do the entire buffer at once,
996 // since we don't care about the pixel values that might extend beyond
997 // the width (since the scanline might be larger than the logical width)
998 const int h = bm0.height();
999 const size_t size = bm0.width() * bm0.bytesPerPixel();
1000 for (int y = 0; y < h; y++) {
1001 // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config
1002 // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0
1003 // and bm1 both have pixel data() (have passed NULL == getPixels() check),
1004 // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE
1005 // to warn user those 2 unrecognized config bitmaps may be different.
1006 void *bm0Addr = bm0.getAddr(0, y);
1007 void *bm1Addr = bm1.getAddr(0, y);
1008
1009 if(bm0Addr == NULL || bm1Addr == NULL) {
1010 return JNI_FALSE;
1011 }
1012
1013 if (memcmp(bm0Addr, bm1Addr, size) != 0) {
1014 return JNI_FALSE;
1015 }
1016 }
1017 return JNI_TRUE;
1018 }
1019
Bitmap_prepareToDraw(JNIEnv * env,jobject,jlong bitmapPtr)1020 static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapPtr) {
1021 #ifdef __ANDROID__ // Layoutlib does not support render thread
1022 LocalScopedBitmap bitmapHandle(bitmapPtr);
1023 if (!bitmapHandle.valid()) return;
1024 android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmapHandle->bitmap());
1025 #endif
1026 }
1027
Bitmap_getAllocationByteCount(JNIEnv * env,jobject,jlong bitmapPtr)1028 static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr) {
1029 LocalScopedBitmap bitmapHandle(bitmapPtr);
1030 return static_cast<jint>(bitmapHandle->getAllocationByteCount());
1031 }
1032
Bitmap_copyPreserveInternalConfig(JNIEnv * env,jobject,jlong bitmapPtr)1033 static jobject Bitmap_copyPreserveInternalConfig(JNIEnv* env, jobject, jlong bitmapPtr) {
1034 LocalScopedBitmap bitmapHandle(bitmapPtr);
1035 LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
1036 "Hardware config is only supported config in Bitmap_nativeCopyPreserveInternalConfig");
1037 Bitmap& hwuiBitmap = bitmapHandle->bitmap();
1038 SkBitmap src;
1039 hwuiBitmap.getSkBitmap(&src);
1040
1041 if (src.pixelRef() == nullptr) {
1042 doThrowRE(env, "Could not copy a hardware bitmap.");
1043 return NULL;
1044 }
1045
1046 sk_sp<Bitmap> bitmap = Bitmap::createFrom(src.info(), *src.pixelRef());
1047 return createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false));
1048 }
1049
1050 #ifdef __ANDROID__ // Layoutlib does not support graphic buffer
1051 typedef AHardwareBuffer* (*AHB_from_HB)(JNIEnv*, jobject);
1052 AHB_from_HB AHardwareBuffer_fromHardwareBuffer;
1053
1054 typedef jobject (*AHB_to_HB)(JNIEnv*, AHardwareBuffer*);
1055 AHB_to_HB AHardwareBuffer_toHardwareBuffer;
1056 #endif
1057
Bitmap_wrapHardwareBufferBitmap(JNIEnv * env,jobject,jobject hardwareBuffer,jlong colorSpacePtr)1058 static jobject Bitmap_wrapHardwareBufferBitmap(JNIEnv* env, jobject, jobject hardwareBuffer,
1059 jlong colorSpacePtr) {
1060 #ifdef __ANDROID__ // Layoutlib does not support graphic buffer
1061 AHardwareBuffer* buffer = AHardwareBuffer_fromHardwareBuffer(env, hardwareBuffer);
1062 sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer,
1063 GraphicsJNI::getNativeColorSpace(colorSpacePtr));
1064 if (!bitmap.get()) {
1065 ALOGW("failed to create hardware bitmap from hardware buffer");
1066 return NULL;
1067 }
1068 return bitmap::createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false));
1069 #else
1070 return NULL;
1071 #endif
1072 }
1073
Bitmap_getHardwareBuffer(JNIEnv * env,jobject,jlong bitmapPtr)1074 static jobject Bitmap_getHardwareBuffer(JNIEnv* env, jobject, jlong bitmapPtr) {
1075 #ifdef __ANDROID__ // Layoutlib does not support graphic buffer
1076 LocalScopedBitmap bitmapHandle(bitmapPtr);
1077 LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
1078 "Hardware config is only supported config in Bitmap_getHardwareBuffer");
1079
1080 Bitmap& bitmap = bitmapHandle->bitmap();
1081 return AHardwareBuffer_toHardwareBuffer(env, bitmap.hardwareBuffer());
1082 #else
1083 return NULL;
1084 #endif
1085 }
1086
Bitmap_isImmutable(CRITICAL_JNI_PARAMS_COMMA jlong bitmapHandle)1087 static jboolean Bitmap_isImmutable(CRITICAL_JNI_PARAMS_COMMA jlong bitmapHandle) {
1088 LocalScopedBitmap bitmapHolder(bitmapHandle);
1089 if (!bitmapHolder.valid()) return JNI_FALSE;
1090
1091 return bitmapHolder->bitmap().isImmutable() ? JNI_TRUE : JNI_FALSE;
1092 }
1093
Bitmap_setImmutable(JNIEnv * env,jobject,jlong bitmapHandle)1094 static void Bitmap_setImmutable(JNIEnv* env, jobject, jlong bitmapHandle) {
1095 LocalScopedBitmap bitmapHolder(bitmapHandle);
1096 if (!bitmapHolder.valid()) return;
1097
1098 return bitmapHolder->bitmap().setImmutable();
1099 }
1100
1101 ///////////////////////////////////////////////////////////////////////////////
1102
1103 static const JNINativeMethod gBitmapMethods[] = {
1104 { "nativeCreate", "([IIIIIIZJ)Landroid/graphics/Bitmap;",
1105 (void*)Bitmap_creator },
1106 { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;",
1107 (void*)Bitmap_copy },
1108 { "nativeCopyAshmem", "(J)Landroid/graphics/Bitmap;",
1109 (void*)Bitmap_copyAshmem },
1110 { "nativeCopyAshmemConfig", "(JI)Landroid/graphics/Bitmap;",
1111 (void*)Bitmap_copyAshmemConfig },
1112 { "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer },
1113 { "nativeRecycle", "(J)V", (void*)Bitmap_recycle },
1114 { "nativeReconfigure", "(JIIIZ)V", (void*)Bitmap_reconfigure },
1115 { "nativeCompress", "(JIILjava/io/OutputStream;[B)Z",
1116 (void*)Bitmap_compress },
1117 { "nativeErase", "(JI)V", (void*)Bitmap_erase },
1118 { "nativeErase", "(JJJ)V", (void*)Bitmap_eraseLong },
1119 { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes },
1120 { "nativeConfig", "(J)I", (void*)Bitmap_config },
1121 { "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha },
1122 { "nativeIsPremultiplied", "(J)Z", (void*)Bitmap_isPremultiplied},
1123 { "nativeSetHasAlpha", "(JZZ)V", (void*)Bitmap_setHasAlpha},
1124 { "nativeSetPremultiplied", "(JZ)V", (void*)Bitmap_setPremultiplied},
1125 { "nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap },
1126 { "nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap },
1127 { "nativeCreateFromParcel",
1128 "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
1129 (void*)Bitmap_createFromParcel },
1130 { "nativeWriteToParcel", "(JILandroid/os/Parcel;)Z",
1131 (void*)Bitmap_writeToParcel },
1132 { "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;",
1133 (void*)Bitmap_extractAlpha },
1134 { "nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId },
1135 { "nativeGetPixel", "(JII)I", (void*)Bitmap_getPixel },
1136 { "nativeGetColor", "(JII)J", (void*)Bitmap_getColor },
1137 { "nativeGetPixels", "(J[IIIIIII)V", (void*)Bitmap_getPixels },
1138 { "nativeSetPixel", "(JIII)V", (void*)Bitmap_setPixel },
1139 { "nativeSetPixels", "(J[IIIIIII)V", (void*)Bitmap_setPixels },
1140 { "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V",
1141 (void*)Bitmap_copyPixelsToBuffer },
1142 { "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V",
1143 (void*)Bitmap_copyPixelsFromBuffer },
1144 { "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs },
1145 { "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw },
1146 { "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount },
1147 { "nativeCopyPreserveInternalConfig", "(J)Landroid/graphics/Bitmap;",
1148 (void*)Bitmap_copyPreserveInternalConfig },
1149 { "nativeWrapHardwareBufferBitmap", "(Landroid/hardware/HardwareBuffer;J)Landroid/graphics/Bitmap;",
1150 (void*) Bitmap_wrapHardwareBufferBitmap },
1151 { "nativeGetHardwareBuffer", "(J)Landroid/hardware/HardwareBuffer;",
1152 (void*) Bitmap_getHardwareBuffer },
1153 { "nativeComputeColorSpace", "(J)Landroid/graphics/ColorSpace;", (void*)Bitmap_computeColorSpace },
1154 { "nativeSetColorSpace", "(JJ)V", (void*)Bitmap_setColorSpace },
1155 { "nativeIsSRGB", "(J)Z", (void*)Bitmap_isSRGB },
1156 { "nativeIsSRGBLinear", "(J)Z", (void*)Bitmap_isSRGBLinear},
1157 { "nativeSetImmutable", "(J)V", (void*)Bitmap_setImmutable},
1158
1159 // ------------ @CriticalNative ----------------
1160 { "nativeIsImmutable", "(J)Z", (void*)Bitmap_isImmutable}
1161
1162 };
1163
1164 const char* const kParcelPathName = "android/os/Parcel";
1165
register_android_graphics_Bitmap(JNIEnv * env)1166 int register_android_graphics_Bitmap(JNIEnv* env)
1167 {
1168 gBitmap_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Bitmap"));
1169 gBitmap_nativePtr = GetFieldIDOrDie(env, gBitmap_class, "mNativePtr", "J");
1170 gBitmap_constructorMethodID = GetMethodIDOrDie(env, gBitmap_class, "<init>", "(JIIIZ[BLandroid/graphics/NinePatch$InsetStruct;Z)V");
1171 gBitmap_reinitMethodID = GetMethodIDOrDie(env, gBitmap_class, "reinit", "(IIZ)V");
1172
1173 #ifdef __ANDROID__ // Layoutlib does not support graphic buffer or parcel
1174 void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
1175 AHardwareBuffer_fromHardwareBuffer =
1176 (AHB_from_HB)dlsym(handle_, "AHardwareBuffer_fromHardwareBuffer");
1177 LOG_ALWAYS_FATAL_IF(AHardwareBuffer_fromHardwareBuffer == nullptr,
1178 "Failed to find required symbol AHardwareBuffer_fromHardwareBuffer!");
1179
1180 AHardwareBuffer_toHardwareBuffer = (AHB_to_HB)dlsym(handle_, "AHardwareBuffer_toHardwareBuffer");
1181 LOG_ALWAYS_FATAL_IF(AHardwareBuffer_toHardwareBuffer == nullptr,
1182 " Failed to find required symbol AHardwareBuffer_toHardwareBuffer!");
1183
1184 gParcelOffsets.clazz = MakeGlobalRefOrDie(env, FindClassOrDie(env, kParcelPathName));
1185 gParcelOffsets.mNativePtr = GetFieldIDOrDie(env, gParcelOffsets.clazz, "mNativePtr", "J");
1186 #endif
1187 return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods,
1188 NELEM(gBitmapMethods));
1189 }
1190