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