• 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         inPlaceCallback(std::move(data.ptr), data.size);
690         return STATUS_OK;
691     } else if (type == BlobType::ASHMEM) {
692         int rawFd = -1;
693         int32_t size = 0;
694         ON_ERROR_RETURN(AParcel_readInt32(parcel, &size));
695         ON_ERROR_RETURN(AParcel_readParcelFileDescriptor(parcel, &rawFd));
696         android::base::unique_fd fd(rawFd);
697         ashmemCallback(std::move(fd), size);
698         return STATUS_OK;
699     } else {
700         // Although the above if/else was "exhaustive" guard against unknown types
701         return STATUS_UNKNOWN_ERROR;
702     }
703 }
704 
705 static constexpr size_t BLOB_INPLACE_LIMIT = 12 * 1024;
706 // Fail fast if we can't use ashmem and the size exceeds this limit - the binder transaction
707 // wouldn't go through, anyway
708 // TODO: Can we get this from somewhere?
709 static constexpr size_t BLOB_MAX_INPLACE_LIMIT = 1 * 1024 * 1024;
shouldUseAshmem(AParcel * parcel,int32_t size)710 static constexpr bool shouldUseAshmem(AParcel* parcel, int32_t size) {
711     return size > BLOB_INPLACE_LIMIT && AParcel_getAllowFds(parcel);
712 }
713 
writeBlobFromFd(AParcel * parcel,int32_t size,int fd)714 static binder_status_t writeBlobFromFd(AParcel* parcel, int32_t size, int fd) {
715     binder_status_t error = STATUS_OK;
716     ON_ERROR_RETURN(AParcel_writeInt32(parcel, static_cast<int32_t>(BlobType::ASHMEM)));
717     ON_ERROR_RETURN(AParcel_writeInt32(parcel, size));
718     ON_ERROR_RETURN(AParcel_writeParcelFileDescriptor(parcel, fd));
719     return STATUS_OK;
720 }
721 
writeBlob(AParcel * parcel,const int32_t size,const void * data,bool immutable)722 static binder_status_t writeBlob(AParcel* parcel, const int32_t size, const void* data, bool immutable) {
723     if (size <= 0 || data == nullptr) {
724         return STATUS_NOT_ENOUGH_DATA;
725     }
726     binder_status_t error = STATUS_OK;
727     if (shouldUseAshmem(parcel, size)) {
728         // Create new ashmem region with read/write priv
729         base::unique_fd fd(ashmem_create_region("bitmap", size));
730         if (fd.get() < 0) {
731             return STATUS_NO_MEMORY;
732         }
733 
734         {
735             void* dest = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd.get(), 0);
736             if (dest == MAP_FAILED) {
737                 return STATUS_NO_MEMORY;
738             }
739             memcpy(dest, data, size);
740             munmap(dest, size);
741         }
742 
743         if (immutable && ashmem_set_prot_region(fd.get(), PROT_READ) < 0) {
744             return STATUS_UNKNOWN_ERROR;
745         }
746         // Workaround b/149851140 in AParcel_writeParcelFileDescriptor
747         int rawFd = fd.release();
748         error = writeBlobFromFd(parcel, size, rawFd);
749         close(rawFd);
750         return error;
751     } else {
752         if (size > BLOB_MAX_INPLACE_LIMIT) {
753             return STATUS_FAILED_TRANSACTION;
754         }
755         ON_ERROR_RETURN(AParcel_writeInt32(parcel, static_cast<int32_t>(BlobType::IN_PLACE)));
756         ON_ERROR_RETURN(AParcel_writeByteArray(parcel, static_cast<const int8_t*>(data), size));
757         return STATUS_OK;
758     }
759 }
760 
761 #undef ON_ERROR_RETURN
762 
763 #endif // __ANDROID__ // Layoutlib does not support parcel
764 
765 // This is the maximum possible size because the SkColorSpace must be
766 // representable (and therefore serializable) using a matrix and numerical
767 // transfer function.  If we allow more color space representations in the
768 // framework, we may need to update this maximum size.
769 static constexpr size_t kMaxColorSpaceSerializedBytes = 80;
770 
771 static constexpr auto RuntimeException = "java/lang/RuntimeException";
772 
validateImageInfo(const SkImageInfo & info,int32_t rowBytes)773 static bool validateImageInfo(const SkImageInfo& info, int32_t rowBytes) {
774     // TODO: Can we avoid making a SkBitmap for this?
775     return SkBitmap().setInfo(info, rowBytes);
776 }
777 
Bitmap_createFromParcel(JNIEnv * env,jobject,jobject parcel)778 static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
779 #ifdef __ANDROID__ // Layoutlib does not support parcel
780     if (parcel == NULL) {
781         jniThrowNullPointerException(env, "parcel cannot be null");
782         return NULL;
783     }
784 
785     ScopedParcel p(env, parcel);
786 
787     const bool isMutable = p.readInt32();
788     const SkColorType colorType = static_cast<SkColorType>(p.readInt32());
789     const SkAlphaType alphaType = static_cast<SkAlphaType>(p.readInt32());
790     sk_sp<SkColorSpace> colorSpace;
791     const auto optColorSpaceData = p.readData();
792     if (optColorSpaceData) {
793         const auto& colorSpaceData = *optColorSpaceData;
794         if (colorSpaceData->size() > kMaxColorSpaceSerializedBytes) {
795             ALOGD("Bitmap_createFromParcel: Serialized SkColorSpace is larger than expected: "
796                   "%zu bytes (max: %zu)\n",
797                   colorSpaceData->size(), kMaxColorSpaceSerializedBytes);
798         }
799 
800         colorSpace = SkColorSpace::Deserialize(colorSpaceData->data(), colorSpaceData->size());
801     }
802     const int32_t width = p.readInt32();
803     const int32_t height = p.readInt32();
804     const int32_t rowBytes = p.readInt32();
805     const int32_t density = p.readInt32();
806 
807     if (kN32_SkColorType != colorType &&
808             kRGBA_F16_SkColorType != colorType &&
809             kRGB_565_SkColorType != colorType &&
810             kARGB_4444_SkColorType != colorType &&
811             kAlpha_8_SkColorType != colorType) {
812         jniThrowExceptionFmt(env, RuntimeException,
813                              "Bitmap_createFromParcel unknown colortype: %d\n", colorType);
814         return NULL;
815     }
816 
817     auto imageInfo = SkImageInfo::Make(width, height, colorType, alphaType, colorSpace);
818     size_t allocationSize = 0;
819     if (!validateImageInfo(imageInfo, rowBytes)) {
820         jniThrowRuntimeException(env, "Received bad SkImageInfo");
821         return NULL;
822     }
823     if (!Bitmap::computeAllocationSize(rowBytes, height, &allocationSize)) {
824         jniThrowExceptionFmt(env, RuntimeException,
825                              "Received bad bitmap size: width=%d, height=%d, rowBytes=%d", width,
826                              height, rowBytes);
827         return NULL;
828     }
829     sk_sp<Bitmap> nativeBitmap;
830     binder_status_t error = readBlob(
831             p.get(),
832             // In place callback
833             [&](std::unique_ptr<int8_t[]> buffer, int32_t size) {
834                 nativeBitmap = Bitmap::allocateHeapBitmap(allocationSize, imageInfo, rowBytes);
835                 if (nativeBitmap) {
836                     memcpy(nativeBitmap->pixels(), buffer.get(), size);
837                 }
838             },
839             // Ashmem callback
840             [&](android::base::unique_fd fd, int32_t size) {
841                 int flags = PROT_READ;
842                 if (isMutable) {
843                     flags |= PROT_WRITE;
844                 }
845                 void* addr = mmap(nullptr, size, flags, MAP_SHARED, fd.get(), 0);
846                 if (addr == MAP_FAILED) {
847                     const int err = errno;
848                     ALOGW("mmap failed, error %d (%s)", err, strerror(err));
849                     return;
850                 }
851                 nativeBitmap =
852                         Bitmap::createFrom(imageInfo, rowBytes, fd.release(), addr, size, !isMutable);
853             });
854     if (error != STATUS_OK) {
855         // TODO: Stringify the error, see signalExceptionForError in android_util_Binder.cpp
856         jniThrowExceptionFmt(env, RuntimeException, "Failed to read from Parcel, error=%d", error);
857         return nullptr;
858     }
859     if (!nativeBitmap) {
860         jniThrowRuntimeException(env, "Could not allocate java pixel ref.");
861         return nullptr;
862     }
863 
864     return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable), nullptr,
865                         nullptr, density);
866 #else
867     jniThrowRuntimeException(env, "Cannot use parcels outside of Android");
868     return NULL;
869 #endif
870 }
871 
Bitmap_writeToParcel(JNIEnv * env,jobject,jlong bitmapHandle,jint density,jobject parcel)872 static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
873                                      jlong bitmapHandle, jint density, jobject parcel) {
874 #ifdef __ANDROID__ // Layoutlib does not support parcel
875     if (parcel == NULL) {
876         SkDebugf("------- writeToParcel null parcel\n");
877         return JNI_FALSE;
878     }
879 
880     ScopedParcel p(env, parcel);
881     SkBitmap bitmap;
882 
883     auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle);
884     bitmapWrapper->getSkBitmap(&bitmap);
885 
886     p.writeInt32(!bitmap.isImmutable());
887     p.writeInt32(bitmap.colorType());
888     p.writeInt32(bitmap.alphaType());
889     SkColorSpace* colorSpace = bitmap.colorSpace();
890     if (colorSpace != nullptr) {
891         p.writeData(colorSpace->serialize());
892     } else {
893         p.writeData(std::nullopt);
894     }
895     p.writeInt32(bitmap.width());
896     p.writeInt32(bitmap.height());
897     p.writeInt32(bitmap.rowBytes());
898     p.writeInt32(density);
899 
900     // Transfer the underlying ashmem region if we have one and it's immutable.
901     binder_status_t status;
902     int fd = bitmapWrapper->bitmap().getAshmemFd();
903     if (fd >= 0 && p.allowFds() && bitmap.isImmutable()) {
904 #if DEBUG_PARCEL
905         ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as "
906               "immutable blob (fds %s)",
907               p.allowFds() ? "allowed" : "forbidden");
908 #endif
909 
910         status = writeBlobFromFd(p.get(), bitmapWrapper->bitmap().getAllocationByteCount(), fd);
911         if (status != STATUS_OK) {
912             doThrowRE(env, "Could not write bitmap blob file descriptor.");
913             return JNI_FALSE;
914         }
915         return JNI_TRUE;
916     }
917 
918     // Copy the bitmap to a new blob.
919 #if DEBUG_PARCEL
920     ALOGD("Bitmap.writeToParcel: copying bitmap into new blob (fds %s)",
921           p.allowFds() ? "allowed" : "forbidden");
922 #endif
923 
924     size_t size = bitmap.computeByteSize();
925     status = writeBlob(p.get(), size, bitmap.getPixels(), bitmap.isImmutable());
926     if (status) {
927         doThrowRE(env, "Could not copy bitmap to parcel blob.");
928         return JNI_FALSE;
929     }
930     return JNI_TRUE;
931 #else
932     doThrowRE(env, "Cannot use parcels outside of Android");
933     return JNI_FALSE;
934 #endif
935 }
936 
Bitmap_extractAlpha(JNIEnv * env,jobject clazz,jlong srcHandle,jlong paintHandle,jintArray offsetXY)937 static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
938                                    jlong srcHandle, jlong paintHandle,
939                                    jintArray offsetXY) {
940     SkBitmap src;
941     reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
942     const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle);
943     SkIPoint  offset;
944     SkBitmap dst;
945     HeapAllocator allocator;
946 
947     src.extractAlpha(&dst, paint, &allocator, &offset);
948     // If Skia can't allocate pixels for destination bitmap, it resets
949     // it, that is set its pixels buffer to NULL, and zero width and height.
950     if (dst.getPixels() == NULL && src.getPixels() != NULL) {
951         doThrowOOME(env, "failed to allocate pixels for alpha");
952         return NULL;
953     }
954     if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
955         int* array = env->GetIntArrayElements(offsetXY, NULL);
956         array[0] = offset.fX;
957         array[1] = offset.fY;
958         env->ReleaseIntArrayElements(offsetXY, array, 0);
959     }
960 
961     return createBitmap(env, allocator.getStorageObjAndReset(),
962             getPremulBitmapCreateFlags(true));
963 }
964 
965 ///////////////////////////////////////////////////////////////////////////////
966 
Bitmap_isSRGB(JNIEnv * env,jobject,jlong bitmapHandle)967 static jboolean Bitmap_isSRGB(JNIEnv* env, jobject, jlong bitmapHandle) {
968     LocalScopedBitmap bitmapHolder(bitmapHandle);
969     if (!bitmapHolder.valid()) return JNI_TRUE;
970 
971     SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
972     return colorSpace == nullptr || colorSpace->isSRGB();
973 }
974 
Bitmap_isSRGBLinear(JNIEnv * env,jobject,jlong bitmapHandle)975 static jboolean Bitmap_isSRGBLinear(JNIEnv* env, jobject, jlong bitmapHandle) {
976     LocalScopedBitmap bitmapHolder(bitmapHandle);
977     if (!bitmapHolder.valid()) return JNI_FALSE;
978 
979     SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
980     sk_sp<SkColorSpace> srgbLinear = SkColorSpace::MakeSRGBLinear();
981     return colorSpace == srgbLinear.get() ? JNI_TRUE : JNI_FALSE;
982 }
983 
Bitmap_computeColorSpace(JNIEnv * env,jobject,jlong bitmapHandle)984 static jobject Bitmap_computeColorSpace(JNIEnv* env, jobject, jlong bitmapHandle) {
985     LocalScopedBitmap bitmapHolder(bitmapHandle);
986     if (!bitmapHolder.valid()) return nullptr;
987 
988     SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
989     if (colorSpace == nullptr) return nullptr;
990 
991     return GraphicsJNI::getColorSpace(env, colorSpace, bitmapHolder->info().colorType());
992 }
993 
Bitmap_setColorSpace(JNIEnv * env,jobject,jlong bitmapHandle,jlong colorSpacePtr)994 static void Bitmap_setColorSpace(JNIEnv* env, jobject, jlong bitmapHandle, jlong colorSpacePtr) {
995     LocalScopedBitmap bitmapHolder(bitmapHandle);
996     sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(colorSpacePtr);
997     bitmapHolder->setColorSpace(cs);
998 }
999 
1000 ///////////////////////////////////////////////////////////////////////////////
1001 
Bitmap_getPixel(JNIEnv * env,jobject,jlong bitmapHandle,jint x,jint y)1002 static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
1003         jint x, jint y) {
1004     SkBitmap bitmap;
1005     reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1006 
1007     auto sRGB = SkColorSpace::MakeSRGB();
1008     SkImageInfo dstInfo = SkImageInfo::Make(
1009             1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
1010 
1011     SkColor dst;
1012     bitmap.readPixels(dstInfo, &dst, dstInfo.minRowBytes(), x, y);
1013     return static_cast<jint>(dst);
1014 }
1015 
Bitmap_getColor(JNIEnv * env,jobject,jlong bitmapHandle,jint x,jint y)1016 static jlong Bitmap_getColor(JNIEnv* env, jobject, jlong bitmapHandle,
1017         jint x, jint y) {
1018     SkBitmap bitmap;
1019     reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1020 
1021     SkImageInfo dstInfo = SkImageInfo::Make(
1022             1, 1, kRGBA_F16_SkColorType, kUnpremul_SkAlphaType, bitmap.refColorSpace());
1023 
1024     uint64_t dst;
1025     bitmap.readPixels(dstInfo, &dst, dstInfo.minRowBytes(), x, y);
1026     return static_cast<jlong>(dst);
1027 }
1028 
Bitmap_getPixels(JNIEnv * env,jobject,jlong bitmapHandle,jintArray pixelArray,jint offset,jint stride,jint x,jint y,jint width,jint height)1029 static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,
1030         jintArray pixelArray, jint offset, jint stride,
1031         jint x, jint y, jint width, jint height) {
1032     SkBitmap bitmap;
1033     reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1034 
1035     auto sRGB = SkColorSpace::MakeSRGB();
1036     SkImageInfo dstInfo = SkImageInfo::Make(
1037             width, height, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
1038 
1039     jint* dst = env->GetIntArrayElements(pixelArray, NULL);
1040     bitmap.readPixels(dstInfo, dst + offset, stride * 4, x, y);
1041     env->ReleaseIntArrayElements(pixelArray, dst, 0);
1042 }
1043 
1044 ///////////////////////////////////////////////////////////////////////////////
1045 
Bitmap_setPixel(JNIEnv * env,jobject,jlong bitmapHandle,jint x,jint y,jint colorHandle)1046 static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle,
1047         jint x, jint y, jint colorHandle) {
1048     SkBitmap bitmap;
1049     reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1050     SkColor color = static_cast<SkColor>(colorHandle);
1051 
1052     auto sRGB = SkColorSpace::MakeSRGB();
1053     SkImageInfo srcInfo = SkImageInfo::Make(
1054             1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
1055     SkPixmap srcPM(srcInfo, &color, srcInfo.minRowBytes());
1056 
1057     bitmap.writePixels(srcPM, x, y);
1058 }
1059 
Bitmap_setPixels(JNIEnv * env,jobject,jlong bitmapHandle,jintArray pixelArray,jint offset,jint stride,jint x,jint y,jint width,jint height)1060 static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,
1061         jintArray pixelArray, jint offset, jint stride,
1062         jint x, jint y, jint width, jint height) {
1063     SkBitmap bitmap;
1064     reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1065     GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
1066             x, y, width, height, &bitmap);
1067 }
1068 
Bitmap_copyPixelsToBuffer(JNIEnv * env,jobject,jlong bitmapHandle,jobject jbuffer)1069 static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
1070                                       jlong bitmapHandle, jobject jbuffer) {
1071     SkBitmap bitmap;
1072     reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1073     const void* src = bitmap.getPixels();
1074 
1075     if (NULL != src) {
1076         android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
1077 
1078         // the java side has already checked that buffer is large enough
1079         memcpy(abp.pointer(), src, bitmap.computeByteSize());
1080     }
1081 }
1082 
Bitmap_copyPixelsFromBuffer(JNIEnv * env,jobject,jlong bitmapHandle,jobject jbuffer)1083 static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,
1084                                         jlong bitmapHandle, jobject jbuffer) {
1085     SkBitmap bitmap;
1086     reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1087     void* dst = bitmap.getPixels();
1088 
1089     if (NULL != dst) {
1090         android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);
1091         // the java side has already checked that buffer is large enough
1092         memcpy(dst, abp.pointer(), bitmap.computeByteSize());
1093         bitmap.notifyPixelsChanged();
1094     }
1095 }
1096 
Bitmap_sameAs(JNIEnv * env,jobject,jlong bm0Handle,jlong bm1Handle)1097 static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle, jlong bm1Handle) {
1098     SkBitmap bm0;
1099     SkBitmap bm1;
1100 
1101     LocalScopedBitmap bitmap0(bm0Handle);
1102     LocalScopedBitmap bitmap1(bm1Handle);
1103 
1104     // Paying the price for making Hardware Bitmap as Config:
1105     // later check for colorType will pass successfully,
1106     // because Hardware Config internally may be RGBA8888 or smth like that.
1107     if (bitmap0->isHardware() != bitmap1->isHardware()) {
1108         return JNI_FALSE;
1109     }
1110 
1111     bitmap0->bitmap().getSkBitmap(&bm0);
1112     bitmap1->bitmap().getSkBitmap(&bm1);
1113     if (bm0.width() != bm1.width()
1114             || bm0.height() != bm1.height()
1115             || bm0.colorType() != bm1.colorType()
1116             || bm0.alphaType() != bm1.alphaType()
1117             || !SkColorSpace::Equals(bm0.colorSpace(), bm1.colorSpace())) {
1118         return JNI_FALSE;
1119     }
1120 
1121     // if we can't load the pixels, return false
1122     if (NULL == bm0.getPixels() || NULL == bm1.getPixels()) {
1123         return JNI_FALSE;
1124     }
1125 
1126     // now compare each scanline. We can't do the entire buffer at once,
1127     // since we don't care about the pixel values that might extend beyond
1128     // the width (since the scanline might be larger than the logical width)
1129     const int h = bm0.height();
1130     const size_t size = bm0.width() * bm0.bytesPerPixel();
1131     for (int y = 0; y < h; y++) {
1132         // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config
1133         // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0
1134         // and bm1 both have pixel data() (have passed NULL == getPixels() check),
1135         // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE
1136         // to warn user those 2 unrecognized config bitmaps may be different.
1137         void *bm0Addr = bm0.getAddr(0, y);
1138         void *bm1Addr = bm1.getAddr(0, y);
1139 
1140         if(bm0Addr == NULL || bm1Addr == NULL) {
1141             return JNI_FALSE;
1142         }
1143 
1144         if (memcmp(bm0Addr, bm1Addr, size) != 0) {
1145             return JNI_FALSE;
1146         }
1147     }
1148     return JNI_TRUE;
1149 }
1150 
Bitmap_prepareToDraw(JNIEnv * env,jobject,jlong bitmapPtr)1151 static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapPtr) {
1152 #ifdef __ANDROID__ // Layoutlib does not support render thread
1153     LocalScopedBitmap bitmapHandle(bitmapPtr);
1154     if (!bitmapHandle.valid()) return;
1155     android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmapHandle->bitmap());
1156 #endif
1157 }
1158 
Bitmap_getAllocationByteCount(JNIEnv * env,jobject,jlong bitmapPtr)1159 static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr) {
1160     LocalScopedBitmap bitmapHandle(bitmapPtr);
1161     return static_cast<jint>(bitmapHandle->getAllocationByteCount());
1162 }
1163 
Bitmap_copyPreserveInternalConfig(JNIEnv * env,jobject,jlong bitmapPtr)1164 static jobject Bitmap_copyPreserveInternalConfig(JNIEnv* env, jobject, jlong bitmapPtr) {
1165     LocalScopedBitmap bitmapHandle(bitmapPtr);
1166     LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
1167             "Hardware config is only supported config in Bitmap_nativeCopyPreserveInternalConfig");
1168     Bitmap& hwuiBitmap = bitmapHandle->bitmap();
1169     SkBitmap src;
1170     hwuiBitmap.getSkBitmap(&src);
1171 
1172     if (src.pixelRef() == nullptr) {
1173         doThrowRE(env, "Could not copy a hardware bitmap.");
1174         return NULL;
1175     }
1176 
1177     sk_sp<Bitmap> bitmap = Bitmap::createFrom(src.info(), *src.pixelRef());
1178     return createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false));
1179 }
1180 
1181 #ifdef __ANDROID__ // Layoutlib does not support graphic buffer
1182 typedef AHardwareBuffer* (*AHB_from_HB)(JNIEnv*, jobject);
1183 AHB_from_HB AHardwareBuffer_fromHardwareBuffer;
1184 
1185 typedef jobject (*AHB_to_HB)(JNIEnv*, AHardwareBuffer*);
1186 AHB_to_HB AHardwareBuffer_toHardwareBuffer;
1187 #endif
1188 
Bitmap_wrapHardwareBufferBitmap(JNIEnv * env,jobject,jobject hardwareBuffer,jlong colorSpacePtr)1189 static jobject Bitmap_wrapHardwareBufferBitmap(JNIEnv* env, jobject, jobject hardwareBuffer,
1190                                                jlong colorSpacePtr) {
1191 #ifdef __ANDROID__ // Layoutlib does not support graphic buffer
1192     AHardwareBuffer* buffer = AHardwareBuffer_fromHardwareBuffer(env, hardwareBuffer);
1193     sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer,
1194                                               GraphicsJNI::getNativeColorSpace(colorSpacePtr));
1195     if (!bitmap.get()) {
1196         ALOGW("failed to create hardware bitmap from hardware buffer");
1197         return NULL;
1198     }
1199     return bitmap::createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false));
1200 #else
1201     return NULL;
1202 #endif
1203 }
1204 
Bitmap_getHardwareBuffer(JNIEnv * env,jobject,jlong bitmapPtr)1205 static jobject Bitmap_getHardwareBuffer(JNIEnv* env, jobject, jlong bitmapPtr) {
1206 #ifdef __ANDROID__ // Layoutlib does not support graphic buffer
1207     LocalScopedBitmap bitmapHandle(bitmapPtr);
1208     if (!bitmapHandle->isHardware()) {
1209         jniThrowException(env, "java/lang/IllegalStateException",
1210             "Hardware config is only supported config in Bitmap_getHardwareBuffer");
1211         return nullptr;
1212     }
1213 
1214     Bitmap& bitmap = bitmapHandle->bitmap();
1215     return AHardwareBuffer_toHardwareBuffer(env, bitmap.hardwareBuffer());
1216 #else
1217     return nullptr;
1218 #endif
1219 }
1220 
Bitmap_isImmutable(CRITICAL_JNI_PARAMS_COMMA jlong bitmapHandle)1221 static jboolean Bitmap_isImmutable(CRITICAL_JNI_PARAMS_COMMA jlong bitmapHandle) {
1222     LocalScopedBitmap bitmapHolder(bitmapHandle);
1223     if (!bitmapHolder.valid()) return JNI_FALSE;
1224 
1225     return bitmapHolder->bitmap().isImmutable() ? JNI_TRUE : JNI_FALSE;
1226 }
1227 
Bitmap_isBackedByAshmem(CRITICAL_JNI_PARAMS_COMMA jlong bitmapHandle)1228 static jboolean Bitmap_isBackedByAshmem(CRITICAL_JNI_PARAMS_COMMA jlong bitmapHandle) {
1229     LocalScopedBitmap bitmapHolder(bitmapHandle);
1230     if (!bitmapHolder.valid()) return JNI_FALSE;
1231 
1232     return bitmapHolder->bitmap().pixelStorageType() == PixelStorageType::Ashmem ? JNI_TRUE
1233                                                                                  : JNI_FALSE;
1234 }
1235 
Bitmap_setImmutable(JNIEnv * env,jobject,jlong bitmapHandle)1236 static void Bitmap_setImmutable(JNIEnv* env, jobject, jlong bitmapHandle) {
1237     LocalScopedBitmap bitmapHolder(bitmapHandle);
1238     if (!bitmapHolder.valid()) return;
1239 
1240     return bitmapHolder->bitmap().setImmutable();
1241 }
1242 
1243 ///////////////////////////////////////////////////////////////////////////////
1244 
1245 static const JNINativeMethod gBitmapMethods[] = {
1246     {   "nativeCreate",             "([IIIIIIZJ)Landroid/graphics/Bitmap;",
1247         (void*)Bitmap_creator },
1248     {   "nativeCopy",               "(JIZ)Landroid/graphics/Bitmap;",
1249         (void*)Bitmap_copy },
1250     {   "nativeCopyAshmem",         "(J)Landroid/graphics/Bitmap;",
1251         (void*)Bitmap_copyAshmem },
1252     {   "nativeCopyAshmemConfig",   "(JI)Landroid/graphics/Bitmap;",
1253         (void*)Bitmap_copyAshmemConfig },
1254     {   "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer },
1255     {   "nativeRecycle",            "(J)V", (void*)Bitmap_recycle },
1256     {   "nativeReconfigure",        "(JIIIZ)V", (void*)Bitmap_reconfigure },
1257     {   "nativeCompress",           "(JIILjava/io/OutputStream;[B)Z",
1258         (void*)Bitmap_compress },
1259     {   "nativeErase",              "(JI)V", (void*)Bitmap_erase },
1260     {   "nativeErase",              "(JJJ)V", (void*)Bitmap_eraseLong },
1261     {   "nativeRowBytes",           "(J)I", (void*)Bitmap_rowBytes },
1262     {   "nativeConfig",             "(J)I", (void*)Bitmap_config },
1263     {   "nativeHasAlpha",           "(J)Z", (void*)Bitmap_hasAlpha },
1264     {   "nativeIsPremultiplied",    "(J)Z", (void*)Bitmap_isPremultiplied},
1265     {   "nativeSetHasAlpha",        "(JZZ)V", (void*)Bitmap_setHasAlpha},
1266     {   "nativeSetPremultiplied",   "(JZ)V", (void*)Bitmap_setPremultiplied},
1267     {   "nativeHasMipMap",          "(J)Z", (void*)Bitmap_hasMipMap },
1268     {   "nativeSetHasMipMap",       "(JZ)V", (void*)Bitmap_setHasMipMap },
1269     {   "nativeCreateFromParcel",
1270         "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
1271         (void*)Bitmap_createFromParcel },
1272     {   "nativeWriteToParcel",      "(JILandroid/os/Parcel;)Z",
1273         (void*)Bitmap_writeToParcel },
1274     {   "nativeExtractAlpha",       "(JJ[I)Landroid/graphics/Bitmap;",
1275         (void*)Bitmap_extractAlpha },
1276     {   "nativeGenerationId",       "(J)I", (void*)Bitmap_getGenerationId },
1277     {   "nativeGetPixel",           "(JII)I", (void*)Bitmap_getPixel },
1278     {   "nativeGetColor",           "(JII)J", (void*)Bitmap_getColor },
1279     {   "nativeGetPixels",          "(J[IIIIIII)V", (void*)Bitmap_getPixels },
1280     {   "nativeSetPixel",           "(JIII)V", (void*)Bitmap_setPixel },
1281     {   "nativeSetPixels",          "(J[IIIIIII)V", (void*)Bitmap_setPixels },
1282     {   "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V",
1283                                             (void*)Bitmap_copyPixelsToBuffer },
1284     {   "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V",
1285                                             (void*)Bitmap_copyPixelsFromBuffer },
1286     {   "nativeSameAs",             "(JJ)Z", (void*)Bitmap_sameAs },
1287     {   "nativePrepareToDraw",      "(J)V", (void*)Bitmap_prepareToDraw },
1288     {   "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount },
1289     {   "nativeCopyPreserveInternalConfig", "(J)Landroid/graphics/Bitmap;",
1290         (void*)Bitmap_copyPreserveInternalConfig },
1291     {   "nativeWrapHardwareBufferBitmap", "(Landroid/hardware/HardwareBuffer;J)Landroid/graphics/Bitmap;",
1292         (void*) Bitmap_wrapHardwareBufferBitmap },
1293     {   "nativeGetHardwareBuffer", "(J)Landroid/hardware/HardwareBuffer;",
1294         (void*) Bitmap_getHardwareBuffer },
1295     {   "nativeComputeColorSpace",  "(J)Landroid/graphics/ColorSpace;", (void*)Bitmap_computeColorSpace },
1296     {   "nativeSetColorSpace",      "(JJ)V", (void*)Bitmap_setColorSpace },
1297     {   "nativeIsSRGB",             "(J)Z", (void*)Bitmap_isSRGB },
1298     {   "nativeIsSRGBLinear",       "(J)Z", (void*)Bitmap_isSRGBLinear},
1299     {   "nativeSetImmutable",       "(J)V", (void*)Bitmap_setImmutable},
1300 
1301     // ------------ @CriticalNative ----------------
1302     {   "nativeIsImmutable",        "(J)Z", (void*)Bitmap_isImmutable},
1303     {   "nativeIsBackedByAshmem",   "(J)Z", (void*)Bitmap_isBackedByAshmem}
1304 
1305 };
1306 
register_android_graphics_Bitmap(JNIEnv * env)1307 int register_android_graphics_Bitmap(JNIEnv* env)
1308 {
1309     gBitmap_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Bitmap"));
1310     gBitmap_nativePtr = GetFieldIDOrDie(env, gBitmap_class, "mNativePtr", "J");
1311     gBitmap_constructorMethodID = GetMethodIDOrDie(env, gBitmap_class, "<init>", "(JIIIZ[BLandroid/graphics/NinePatch$InsetStruct;Z)V");
1312     gBitmap_reinitMethodID = GetMethodIDOrDie(env, gBitmap_class, "reinit", "(IIZ)V");
1313 
1314 #ifdef __ANDROID__ // Layoutlib does not support graphic buffer or parcel
1315     void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
1316     AHardwareBuffer_fromHardwareBuffer =
1317             (AHB_from_HB)dlsym(handle_, "AHardwareBuffer_fromHardwareBuffer");
1318     LOG_ALWAYS_FATAL_IF(AHardwareBuffer_fromHardwareBuffer == nullptr,
1319                         "Failed to find required symbol AHardwareBuffer_fromHardwareBuffer!");
1320 
1321     AHardwareBuffer_toHardwareBuffer = (AHB_to_HB)dlsym(handle_, "AHardwareBuffer_toHardwareBuffer");
1322     LOG_ALWAYS_FATAL_IF(AHardwareBuffer_toHardwareBuffer == nullptr,
1323                         " Failed to find required symbol AHardwareBuffer_toHardwareBuffer!");
1324 #endif
1325     return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods,
1326                                          NELEM(gBitmapMethods));
1327 }
1328