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