blob: 1f2ce8ea6c819f9c5e3fa5ade4f0a0864c7ba6b2 [file] [log] [blame]
Derek Sollenberger5368eda2019-10-25 11:20:03 -04001#undef LOG_TAG
John Reckf29ed282015-04-07 07:32:03 -07002#define LOG_TAG "Bitmap"
John Reckf29ed282015-04-07 07:32:03 -07003#include "Bitmap.h"
4
Chris Craik32054b02014-05-09 13:58:56 -07005#include "SkBitmap.h"
6#include "SkPixelRef.h"
7#include "SkImageEncoder.h"
Leon Scroggins III57ee6202014-06-04 18:51:07 -04008#include "SkImageInfo.h"
Romain Guy9505a652016-12-14 09:43:50 -08009#include "SkColor.h"
Romain Guyce217fa2017-03-08 15:58:06 -080010#include "SkColorSpace.h"
Chris Craik32054b02014-05-09 13:58:56 -070011#include "GraphicsJNI.h"
Chris Craik32054b02014-05-09 13:58:56 -070012#include "SkStream.h"
Leon Scroggins III94d294b2019-09-06 13:22:46 -040013#include "SkWebpEncoder.h"
Chris Craik32054b02014-05-09 13:58:56 -070014
Chris Craik32054b02014-05-09 13:58:56 -070015#include "android_os_Parcel.h"
Chris Craik32054b02014-05-09 13:58:56 -070016#include "android_nio_utils.h"
17#include "CreateJavaOutputStreamAdaptor.h"
sergeyvdccca442016-03-21 15:38:21 -070018#include <hwui/Paint.h>
sergeyvc1c54062016-10-19 18:47:26 -070019#include <hwui/Bitmap.h>
Derek Sollenberger6e35e632019-01-22 13:56:25 -050020#include <utils/Color.h>
Chris Craik32054b02014-05-09 13:58:56 -070021
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +010022#ifdef __ANDROID__ // Layoutlib does not support graphic buffer, parcel or render thread
Derek Sollenbergere78f7c92019-07-31 15:18:47 -040023#include <android_runtime/android_graphics_GraphicBuffer.h>
Leon Scroggins III5a190b12020-02-18 13:52:18 -050024#include <binder/Parcel.h>
Leon Scroggins III898ce752020-02-18 12:22:17 -050025#include <dlfcn.h>
Leon Scroggins III5a190b12020-02-18 13:52:18 -050026#include <renderthread/RenderProxy.h>
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +010027#endif
rennb2e9f522018-09-26 10:49:00 -070028
Andreas Gampeed6b9df2014-11-20 22:02:20 -080029#include "core_jni_helpers.h"
30
Chris Craik32054b02014-05-09 13:58:56 -070031#include <jni.h>
Romain Guyce217fa2017-03-08 15:58:06 -080032#include <string.h>
Riley Andrews39d7f302014-11-13 17:43:25 -080033#include <memory>
34#include <string>
Chris Craik32054b02014-05-09 13:58:56 -070035
Jeff Browna316c5d2015-06-05 15:14:06 -070036#define DEBUG_PARCEL 0
37
sergeyvc69853c2016-10-07 14:14:09 -070038static jclass gBitmap_class;
39static jfieldID gBitmap_nativePtr;
40static jmethodID gBitmap_constructorMethodID;
41static jmethodID gBitmap_reinitMethodID;
sergeyvc69853c2016-10-07 14:14:09 -070042
John Reckf29ed282015-04-07 07:32:03 -070043namespace android {
44
sergeyvc1c54062016-10-19 18:47:26 -070045class BitmapWrapper {
John Reckf29ed282015-04-07 07:32:03 -070046public:
Chih-Hung Hsieh0727be12018-12-20 13:43:46 -080047 explicit BitmapWrapper(Bitmap* bitmap)
sergeyvc1c54062016-10-19 18:47:26 -070048 : mBitmap(bitmap) { }
sergeyvc69853c2016-10-07 14:14:09 -070049
50 void freePixels() {
sergeyvc1c54062016-10-19 18:47:26 -070051 mInfo = mBitmap->info();
52 mHasHardwareMipMap = mBitmap->hasHardwareMipMap();
53 mAllocationSize = mBitmap->getAllocationByteCount();
54 mRowBytes = mBitmap->rowBytes();
55 mGenerationId = mBitmap->getGenerationID();
sergeyv15a10852016-12-27 14:32:03 -080056 mIsHardware = mBitmap->isHardware();
sergeyvc1c54062016-10-19 18:47:26 -070057 mBitmap.reset();
John Reckf29ed282015-04-07 07:32:03 -070058 }
59
sergeyvc69853c2016-10-07 14:14:09 -070060 bool valid() {
Ben Wagner6b62ac02018-05-29 14:16:02 -040061 return mBitmap != nullptr;
John Reckf29ed282015-04-07 07:32:03 -070062 }
63
sergeyvaed7f582016-10-14 16:30:21 -070064 Bitmap& bitmap() {
65 assertValid();
66 return *mBitmap;
67 }
sergeyvc69853c2016-10-07 14:14:09 -070068
69 void assertValid() {
70 LOG_ALWAYS_FATAL_IF(!valid(), "Error, cannot access an invalid/free'd bitmap here!");
71 }
72
73 void getSkBitmap(SkBitmap* outBitmap) {
74 assertValid();
sergeyvc1c54062016-10-19 18:47:26 -070075 mBitmap->getSkBitmap(outBitmap);
sergeyvc69853c2016-10-07 14:14:09 -070076 }
77
78 bool hasHardwareMipMap() {
sergeyvc1c54062016-10-19 18:47:26 -070079 if (mBitmap) {
80 return mBitmap->hasHardwareMipMap();
John Reckf29ed282015-04-07 07:32:03 -070081 }
John Reckf29ed282015-04-07 07:32:03 -070082 return mHasHardwareMipMap;
83 }
84
85 void setHasHardwareMipMap(bool hasMipMap) {
sergeyvc69853c2016-10-07 14:14:09 -070086 assertValid();
sergeyvc1c54062016-10-19 18:47:26 -070087 mBitmap->setHasHardwareMipMap(hasMipMap);
John Reckf29ed282015-04-07 07:32:03 -070088 }
89
sergeyvc69853c2016-10-07 14:14:09 -070090 void setAlphaType(SkAlphaType alphaType) {
91 assertValid();
sergeyvc1c54062016-10-19 18:47:26 -070092 mBitmap->setAlphaType(alphaType);
John Reckf29ed282015-04-07 07:32:03 -070093 }
94
Derek Sollenberger202084c2019-01-14 13:55:08 -050095 void setColorSpace(sk_sp<SkColorSpace> colorSpace) {
96 assertValid();
97 mBitmap->setColorSpace(colorSpace);
98 }
99
sergeyvc69853c2016-10-07 14:14:09 -0700100 const SkImageInfo& info() {
sergeyvc1c54062016-10-19 18:47:26 -0700101 if (mBitmap) {
102 return mBitmap->info();
sergeyvc69853c2016-10-07 14:14:09 -0700103 }
104 return mInfo;
John Reckf29ed282015-04-07 07:32:03 -0700105 }
106
sergeyvc69853c2016-10-07 14:14:09 -0700107 size_t getAllocationByteCount() const {
sergeyvc1c54062016-10-19 18:47:26 -0700108 if (mBitmap) {
109 return mBitmap->getAllocationByteCount();
sergeyvc69853c2016-10-07 14:14:09 -0700110 }
111 return mAllocationSize;
John Reckf29ed282015-04-07 07:32:03 -0700112 }
113
sergeyvc69853c2016-10-07 14:14:09 -0700114 size_t rowBytes() const {
sergeyvc1c54062016-10-19 18:47:26 -0700115 if (mBitmap) {
116 return mBitmap->rowBytes();
sergeyvc69853c2016-10-07 14:14:09 -0700117 }
118 return mRowBytes;
119 }
120
121 uint32_t getGenerationID() const {
sergeyvc1c54062016-10-19 18:47:26 -0700122 if (mBitmap) {
123 return mBitmap->getGenerationID();
sergeyvc69853c2016-10-07 14:14:09 -0700124 }
125 return mGenerationId;
126 }
127
sergeyv15a10852016-12-27 14:32:03 -0800128 bool isHardware() {
129 if (mBitmap) {
130 return mBitmap->isHardware();
131 }
132 return mIsHardware;
133 }
134
sergeyvc1c54062016-10-19 18:47:26 -0700135 ~BitmapWrapper() { }
sergeyvc69853c2016-10-07 14:14:09 -0700136
John Reckf29ed282015-04-07 07:32:03 -0700137private:
sergeyvc1c54062016-10-19 18:47:26 -0700138 sk_sp<Bitmap> mBitmap;
sergeyvc69853c2016-10-07 14:14:09 -0700139 SkImageInfo mInfo;
140 bool mHasHardwareMipMap;
141 size_t mAllocationSize;
142 size_t mRowBytes;
143 uint32_t mGenerationId;
sergeyv15a10852016-12-27 14:32:03 -0800144 bool mIsHardware;
John Reckf29ed282015-04-07 07:32:03 -0700145};
146
John Reckf29ed282015-04-07 07:32:03 -0700147// Convenience class that does not take a global ref on the pixels, relying
148// on the caller already having a local JNI ref
149class LocalScopedBitmap {
150public:
Chih-Hung Hsiehc6baf562016-04-27 11:29:23 -0700151 explicit LocalScopedBitmap(jlong bitmapHandle)
sergeyvc1c54062016-10-19 18:47:26 -0700152 : mBitmapWrapper(reinterpret_cast<BitmapWrapper*>(bitmapHandle)) {}
John Reckf29ed282015-04-07 07:32:03 -0700153
sergeyvc1c54062016-10-19 18:47:26 -0700154 BitmapWrapper* operator->() {
155 return mBitmapWrapper;
John Reckf29ed282015-04-07 07:32:03 -0700156 }
157
158 void* pixels() {
sergeyvaed7f582016-10-14 16:30:21 -0700159 return mBitmapWrapper->bitmap().pixels();
John Reckf29ed282015-04-07 07:32:03 -0700160 }
161
162 bool valid() {
sergeyvc1c54062016-10-19 18:47:26 -0700163 return mBitmapWrapper && mBitmapWrapper->valid();
John Reckf29ed282015-04-07 07:32:03 -0700164 }
165
166private:
sergeyvc1c54062016-10-19 18:47:26 -0700167 BitmapWrapper* mBitmapWrapper;
John Reckf29ed282015-04-07 07:32:03 -0700168};
169
sergeyvc69853c2016-10-07 14:14:09 -0700170namespace bitmap {
171
172// Assert that bitmap's SkAlphaType is consistent with isPremultiplied.
173static void assert_premultiplied(const SkImageInfo& info, bool isPremultiplied) {
174 // kOpaque_SkAlphaType and kIgnore_SkAlphaType mean that isPremultiplied is
175 // irrelevant. This just tests to ensure that the SkAlphaType is not
176 // opposite of isPremultiplied.
177 if (isPremultiplied) {
178 SkASSERT(info.alphaType() != kUnpremul_SkAlphaType);
179 } else {
180 SkASSERT(info.alphaType() != kPremul_SkAlphaType);
181 }
182}
183
184void reinitBitmap(JNIEnv* env, jobject javaBitmap, const SkImageInfo& info,
185 bool isPremultiplied)
186{
187 // The caller needs to have already set the alpha type properly, so the
188 // native SkBitmap stays in sync with the Java Bitmap.
189 assert_premultiplied(info, isPremultiplied);
190
191 env->CallVoidMethod(javaBitmap, gBitmap_reinitMethodID,
192 info.width(), info.height(), isPremultiplied);
193}
194
sergeyvc1c54062016-10-19 18:47:26 -0700195jobject createBitmap(JNIEnv* env, Bitmap* bitmap,
sergeyvc69853c2016-10-07 14:14:09 -0700196 int bitmapCreateFlags, jbyteArray ninePatchChunk, jobject ninePatchInsets,
197 int density) {
198 bool isMutable = bitmapCreateFlags & kBitmapCreateFlag_Mutable;
199 bool isPremultiplied = bitmapCreateFlags & kBitmapCreateFlag_Premultiplied;
200 // The caller needs to have already set the alpha type properly, so the
201 // native SkBitmap stays in sync with the Java Bitmap.
sergeyvc1c54062016-10-19 18:47:26 -0700202 assert_premultiplied(bitmap->info(), isPremultiplied);
Leon Scroggins IIIbbdb7312019-01-31 14:35:54 -0500203 bool fromMalloc = bitmap->pixelStorageType() == PixelStorageType::Heap;
sergeyvc1c54062016-10-19 18:47:26 -0700204 BitmapWrapper* bitmapWrapper = new BitmapWrapper(bitmap);
Nader Jawade7b51292018-04-12 17:55:31 -0700205 if (!isMutable) {
206 bitmapWrapper->bitmap().setImmutable();
207 }
sergeyvc69853c2016-10-07 14:14:09 -0700208 jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
sergeyvc1c54062016-10-19 18:47:26 -0700209 reinterpret_cast<jlong>(bitmapWrapper), bitmap->width(), bitmap->height(), density,
Leon Scroggins IIIbbdb7312019-01-31 14:35:54 -0500210 isPremultiplied, ninePatchChunk, ninePatchInsets, fromMalloc);
sergeyvc69853c2016-10-07 14:14:09 -0700211
212 if (env->ExceptionCheck() != 0) {
213 ALOGE("*** Uncaught exception returned from Java call!\n");
214 env->ExceptionDescribe();
215 }
216 return obj;
217}
218
219void toSkBitmap(jlong bitmapHandle, SkBitmap* outBitmap) {
220 LocalScopedBitmap bitmap(bitmapHandle);
221 bitmap->getSkBitmap(outBitmap);
222}
223
Leon Scroggins III71fae622019-03-26 16:28:41 -0400224Bitmap& toBitmap(jlong bitmapHandle) {
sergeyv5fd2a1c2016-10-20 15:04:28 -0700225 LocalScopedBitmap localBitmap(bitmapHandle);
226 return localBitmap->bitmap();
227}
228
sergeyvc69853c2016-10-07 14:14:09 -0700229} // namespace bitmap
230
231} // namespace android
232
233using namespace android;
234using namespace android::bitmap;
235
Derek Sollenberger6c41ab12019-11-08 08:50:58 -0500236Bitmap* GraphicsJNI::getNativeBitmap(JNIEnv* env, jobject bitmap) {
237 SkASSERT(env);
238 SkASSERT(bitmap);
239 SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
240 jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
241 LocalScopedBitmap localBitmap(bitmapHandle);
242 return localBitmap.valid() ? &localBitmap->bitmap() : nullptr;
243}
244
Leon Scroggins III84a2afc2020-01-19 19:27:16 -0500245SkImageInfo GraphicsJNI::getBitmapInfo(JNIEnv* env, jobject bitmap, uint32_t* outRowBytes,
246 bool* isHardware) {
Derek Sollenberger6c41ab12019-11-08 08:50:58 -0500247 SkASSERT(env);
248 SkASSERT(bitmap);
249 SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
250 jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
251 LocalScopedBitmap localBitmap(bitmapHandle);
252 if (outRowBytes) {
253 *outRowBytes = localBitmap->rowBytes();
254 }
Leon Scroggins III84a2afc2020-01-19 19:27:16 -0500255 if (isHardware) {
256 *isHardware = localBitmap->isHardware();
257 }
Derek Sollenberger6c41ab12019-11-08 08:50:58 -0500258 return localBitmap->info();
259}
260
Chris Craik32054b02014-05-09 13:58:56 -0700261bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride,
Brian Osman91c9c282018-08-17 16:57:15 -0400262 int x, int y, int width, int height, SkBitmap* dstBitmap) {
Chris Craik32054b02014-05-09 13:58:56 -0700263 const jint* array = env->GetIntArrayElements(srcColors, NULL);
264 const SkColor* src = (const SkColor*)array + srcOffset;
265
Brian Osman91c9c282018-08-17 16:57:15 -0400266 auto sRGB = SkColorSpace::MakeSRGB();
267 SkImageInfo srcInfo = SkImageInfo::Make(
268 width, height, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
269 SkPixmap srcPM(srcInfo, src, srcStride * 4);
Romain Guyce217fa2017-03-08 15:58:06 -0800270
Brian Osman91c9c282018-08-17 16:57:15 -0400271 dstBitmap->writePixels(srcPM, x, y);
Chris Craik32054b02014-05-09 13:58:56 -0700272
Romain Guy9505a652016-12-14 09:43:50 -0800273 env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array), JNI_ABORT);
Chris Craik32054b02014-05-09 13:58:56 -0700274 return true;
275}
276
Chris Craik32054b02014-05-09 13:58:56 -0700277///////////////////////////////////////////////////////////////////////////////
278///////////////////////////////////////////////////////////////////////////////
279
280static int getPremulBitmapCreateFlags(bool isMutable) {
sergeyvc69853c2016-10-07 14:14:09 -0700281 int flags = android::bitmap::kBitmapCreateFlag_Premultiplied;
282 if (isMutable) flags |= android::bitmap::kBitmapCreateFlag_Mutable;
Chris Craik32054b02014-05-09 13:58:56 -0700283 return flags;
284}
285
286static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
287 jint offset, jint stride, jint width, jint height,
Romain Guy82426562017-04-04 19:38:50 -0700288 jint configHandle, jboolean isMutable,
Leon Scroggins III0e443d12018-12-19 11:38:35 -0500289 jlong colorSpacePtr) {
Mike Reed1103b322014-07-08 12:36:44 -0400290 SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700291 if (NULL != jColors) {
292 size_t n = env->GetArrayLength(jColors);
293 if (n < SkAbs32(stride) * (size_t)height) {
294 doThrowAIOOBE(env);
295 return NULL;
296 }
297 }
298
299 // ARGB_4444 is a deprecated format, convert automatically to 8888
Mike Reedb9330552014-06-16 17:31:48 -0400300 if (colorType == kARGB_4444_SkColorType) {
301 colorType = kN32_SkColorType;
Chris Craik32054b02014-05-09 13:58:56 -0700302 }
303
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500304 sk_sp<SkColorSpace> colorSpace;
305 if (colorType == kAlpha_8_SkColorType) {
306 colorSpace = nullptr;
307 } else {
308 colorSpace = GraphicsJNI::getNativeColorSpace(colorSpacePtr);
309 }
310
Chris Craik32054b02014-05-09 13:58:56 -0700311 SkBitmap bitmap;
Leon Scroggins III0e443d12018-12-19 11:38:35 -0500312 bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType,
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500313 colorSpace));
Chris Craik32054b02014-05-09 13:58:56 -0700314
Leon Scroggins IIIf51a80d2017-07-12 10:46:35 -0400315 sk_sp<Bitmap> nativeBitmap = Bitmap::allocateHeapBitmap(&bitmap);
John Reckf29ed282015-04-07 07:32:03 -0700316 if (!nativeBitmap) {
Leon Scroggins IIIf3a02992017-10-03 14:00:20 -0400317 ALOGE("OOM allocating Bitmap with dimensions %i x %i", width, height);
318 doThrowOOME(env);
Chris Craik32054b02014-05-09 13:58:56 -0700319 return NULL;
320 }
321
322 if (jColors != NULL) {
Brian Osman91c9c282018-08-17 16:57:15 -0400323 GraphicsJNI::SetPixels(env, jColors, offset, stride, 0, 0, width, height, &bitmap);
Chris Craik32054b02014-05-09 13:58:56 -0700324 }
325
sergeyvc36bd6c2016-10-11 15:49:16 -0700326 return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable));
Chris Craik32054b02014-05-09 13:58:56 -0700327}
328
Matt Sarett5320a722017-03-20 13:51:29 -0400329static bool bitmapCopyTo(SkBitmap* dst, SkColorType dstCT, const SkBitmap& src,
330 SkBitmap::Allocator* alloc) {
Matt Sarette9834402017-04-25 13:49:42 -0400331 SkPixmap srcPM;
332 if (!src.peekPixels(&srcPM)) {
333 return false;
334 }
335
336 SkImageInfo dstInfo = srcPM.info().makeColorType(dstCT);
337 switch (dstCT) {
338 case kRGB_565_SkColorType:
Brian Osmanbaf13e82018-09-21 11:21:30 -0400339 dstInfo = dstInfo.makeAlphaType(kOpaque_SkAlphaType);
Matt Sarette9834402017-04-25 13:49:42 -0400340 break;
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500341 case kAlpha_8_SkColorType:
342 dstInfo = dstInfo.makeColorSpace(nullptr);
Matt Sarette9834402017-04-25 13:49:42 -0400343 break;
344 default:
345 break;
346 }
347
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500348 if (!dstInfo.colorSpace() && dstCT != kAlpha_8_SkColorType) {
349 dstInfo = dstInfo.makeColorSpace(SkColorSpace::MakeSRGB());
350 }
351
Matt Sarette9834402017-04-25 13:49:42 -0400352 if (!dst->setInfo(dstInfo)) {
353 return false;
354 }
Mike Reed81397c42017-07-18 17:04:16 -0400355 if (!dst->tryAllocPixels(alloc)) {
Matt Sarette9834402017-04-25 13:49:42 -0400356 return false;
357 }
358
Matt Sarette9834402017-04-25 13:49:42 -0400359 SkPixmap dstPM;
360 if (!dst->peekPixels(&dstPM)) {
361 return false;
362 }
363
Matt Sarette9834402017-04-25 13:49:42 -0400364 return srcPM.readPixels(dstPM);
Matt Sarett5320a722017-03-20 13:51:29 -0400365}
366
Chris Craik32054b02014-05-09 13:58:56 -0700367static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle,
368 jint dstConfigHandle, jboolean isMutable) {
John Reckf29ed282015-04-07 07:32:03 -0700369 SkBitmap src;
sergeyvc1c54062016-10-19 18:47:26 -0700370 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
sergeyv05126d12016-12-15 19:50:15 -0800371 if (dstConfigHandle == GraphicsJNI::hardwareLegacyBitmapConfig()) {
372 sk_sp<Bitmap> bitmap(Bitmap::allocateHardwareBitmap(src));
373 if (!bitmap.get()) {
374 return NULL;
375 }
sergeyv656117b2017-02-28 15:25:10 -0800376 return createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(isMutable));
sergeyv05126d12016-12-15 19:50:15 -0800377 }
378
Mike Reed1103b322014-07-08 12:36:44 -0400379 SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
sergeyv45082182016-09-29 18:25:40 -0700380 SkBitmap result;
381 HeapAllocator allocator;
Chris Craik32054b02014-05-09 13:58:56 -0700382
Matt Sarett5320a722017-03-20 13:51:29 -0400383 if (!bitmapCopyTo(&result, dstCT, src, &allocator)) {
Chris Craik32054b02014-05-09 13:58:56 -0700384 return NULL;
385 }
sergeyvc1c54062016-10-19 18:47:26 -0700386 auto bitmap = allocator.getStorageObjAndReset();
387 return createBitmap(env, bitmap, getPremulBitmapCreateFlags(isMutable));
Chris Craik32054b02014-05-09 13:58:56 -0700388}
389
sergeyvc1c54062016-10-19 18:47:26 -0700390static Bitmap* Bitmap_copyAshmemImpl(JNIEnv* env, SkBitmap& src, SkColorType& dstCT) {
Riley Andrews721ae5f2015-05-11 16:08:22 -0700391 SkBitmap result;
392
393 AshmemPixelAllocator allocator(env);
Matt Sarett5320a722017-03-20 13:51:29 -0400394 if (!bitmapCopyTo(&result, dstCT, src, &allocator)) {
Riley Andrews721ae5f2015-05-11 16:08:22 -0700395 return NULL;
396 }
sergeyvc1c54062016-10-19 18:47:26 -0700397 auto bitmap = allocator.getStorageObjAndReset();
398 bitmap->setImmutable();
399 return bitmap;
Winsona5fdde92016-04-14 15:27:15 -0700400}
401
402static jobject Bitmap_copyAshmem(JNIEnv* env, jobject, jlong srcHandle) {
403 SkBitmap src;
sergeyvc1c54062016-10-19 18:47:26 -0700404 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
Winsona5fdde92016-04-14 15:27:15 -0700405 SkColorType dstCT = src.colorType();
sergeyvc1c54062016-10-19 18:47:26 -0700406 auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
407 jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
Winsona5fdde92016-04-14 15:27:15 -0700408 return ret;
409}
410
411static jobject Bitmap_copyAshmemConfig(JNIEnv* env, jobject, jlong srcHandle, jint dstConfigHandle) {
412 SkBitmap src;
sergeyvc1c54062016-10-19 18:47:26 -0700413 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
Winsona5fdde92016-04-14 15:27:15 -0700414 SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
sergeyvc1c54062016-10-19 18:47:26 -0700415 auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
416 jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
Riley Andrews721ae5f2015-05-11 16:08:22 -0700417 return ret;
418}
419
sergeyvc1c54062016-10-19 18:47:26 -0700420static void Bitmap_destruct(BitmapWrapper* bitmap) {
sergeyvc69853c2016-10-07 14:14:09 -0700421 delete bitmap;
Chris Craik32054b02014-05-09 13:58:56 -0700422}
423
Richard Uhler775873a2015-12-29 12:37:39 -0800424static jlong Bitmap_getNativeFinalizer(JNIEnv*, jobject) {
425 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Bitmap_destruct));
426}
427
Leon Scroggins IIIf8adae12018-05-24 15:25:08 -0400428static void Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700429 LocalScopedBitmap bitmap(bitmapHandle);
430 bitmap->freePixels();
Chris Craik32054b02014-05-09 13:58:56 -0700431}
432
433static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
sergeyv45082182016-09-29 18:25:40 -0700434 jint width, jint height, jint configHandle, jboolean requestPremul) {
John Reckf29ed282015-04-07 07:32:03 -0700435 LocalScopedBitmap bitmap(bitmapHandle);
sergeyvc69853c2016-10-07 14:14:09 -0700436 bitmap->assertValid();
Mike Reed1103b322014-07-08 12:36:44 -0400437 SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
Leon Scroggins III17a8bfc2014-06-03 16:15:15 -0400438
439 // ARGB_4444 is a deprecated format, convert automatically to 8888
440 if (colorType == kARGB_4444_SkColorType) {
441 colorType = kN32_SkColorType;
442 }
sergeyv45082182016-09-29 18:25:40 -0700443 size_t requestedSize = width * height * SkColorTypeBytesPerPixel(colorType);
444 if (requestedSize > bitmap->getAllocationByteCount()) {
Chris Craik32054b02014-05-09 13:58:56 -0700445 // done in native as there's no way to get BytesPerPixel in Java
446 doThrowIAE(env, "Bitmap not large enough to support new configuration");
447 return;
448 }
Leon Scroggins III17a8bfc2014-06-03 16:15:15 -0400449 SkAlphaType alphaType;
John Reckf29ed282015-04-07 07:32:03 -0700450 if (bitmap->info().colorType() != kRGB_565_SkColorType
451 && bitmap->info().alphaType() == kOpaque_SkAlphaType) {
Leon Scroggins III17a8bfc2014-06-03 16:15:15 -0400452 // If the original bitmap was set to opaque, keep that setting, unless it
453 // was 565, which is required to be opaque.
454 alphaType = kOpaque_SkAlphaType;
455 } else {
456 // Otherwise respect the premultiplied request.
457 alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
458 }
sergeyvaed7f582016-10-14 16:30:21 -0700459 bitmap->bitmap().reconfigure(SkImageInfo::Make(width, height, colorType, alphaType,
sergeyv7d5219f2016-11-03 16:18:16 -0700460 sk_ref_sp(bitmap->info().colorSpace())));
Chris Craik32054b02014-05-09 13:58:56 -0700461}
462
Chris Craik32054b02014-05-09 13:58:56 -0700463static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle,
464 jint format, jint quality,
465 jobject jstream, jbyteArray jstorage) {
Hal Canary10219fb2016-11-23 20:41:22 -0500466 LocalScopedBitmap bitmap(bitmapHandle);
John Reckf29ed282015-04-07 07:32:03 -0700467 if (!bitmap.valid()) {
468 return JNI_FALSE;
469 }
470
John Reckf29ed282015-04-07 07:32:03 -0700471 std::unique_ptr<SkWStream> strm(CreateJavaOutputStreamAdaptor(env, jstream, jstorage));
472 if (!strm.get()) {
473 return JNI_FALSE;
474 }
Chris Craik32054b02014-05-09 13:58:56 -0700475
Leon Scroggins III9010e8b2019-08-20 11:27:17 -0400476 auto fm = static_cast<Bitmap::JavaCompressFormat>(format);
Leon Scroggins III949c6002020-01-23 16:20:39 -0500477 return bitmap->bitmap().compress(fm, quality, strm.get()) ? JNI_TRUE : JNI_FALSE;
Chris Craik32054b02014-05-09 13:58:56 -0700478}
479
Leon Scroggins III4c4259b2018-12-17 10:40:07 -0500480static inline void bitmapErase(SkBitmap bitmap, const SkColor4f& color,
481 const sk_sp<SkColorSpace>& colorSpace) {
482 SkPaint p;
483 p.setColor4f(color, colorSpace.get());
484 p.setBlendMode(SkBlendMode::kSrc);
485 SkCanvas canvas(bitmap);
486 canvas.drawPaint(p);
487}
488
Chris Craik32054b02014-05-09 13:58:56 -0700489static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) {
John Reckf29ed282015-04-07 07:32:03 -0700490 LocalScopedBitmap bitmap(bitmapHandle);
491 SkBitmap skBitmap;
492 bitmap->getSkBitmap(&skBitmap);
Leon Scroggins III4c4259b2018-12-17 10:40:07 -0500493 bitmapErase(skBitmap, SkColor4f::FromColor(color), SkColorSpace::MakeSRGB());
494}
495
Leon Scroggins III94ba1002019-01-17 13:34:51 -0500496static void Bitmap_eraseLong(JNIEnv* env, jobject, jlong bitmapHandle,
497 jlong colorSpaceHandle, jlong colorLong) {
Leon Scroggins III4c4259b2018-12-17 10:40:07 -0500498 LocalScopedBitmap bitmap(bitmapHandle);
499 SkBitmap skBitmap;
500 bitmap->getSkBitmap(&skBitmap);
Leon Scroggins III0e443d12018-12-19 11:38:35 -0500501
Leon Scroggins III94ba1002019-01-17 13:34:51 -0500502 SkColor4f color = GraphicsJNI::convertColorLong(colorLong);
Leon Scroggins III0e443d12018-12-19 11:38:35 -0500503 sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
Leon Scroggins III4c4259b2018-12-17 10:40:07 -0500504 bitmapErase(skBitmap, color, cs);
Chris Craik32054b02014-05-09 13:58:56 -0700505}
506
507static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700508 LocalScopedBitmap bitmap(bitmapHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700509 return static_cast<jint>(bitmap->rowBytes());
510}
511
512static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700513 LocalScopedBitmap bitmap(bitmapHandle);
sergeyv15a10852016-12-27 14:32:03 -0800514 if (bitmap->isHardware()) {
sergeyv19b4b012016-12-13 16:06:00 -0800515 return GraphicsJNI::hardwareLegacyBitmapConfig();
516 }
John Reckf29ed282015-04-07 07:32:03 -0700517 return GraphicsJNI::colorTypeToLegacyBitmapConfig(bitmap->info().colorType());
Chris Craik32054b02014-05-09 13:58:56 -0700518}
519
520static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700521 LocalScopedBitmap bitmap(bitmapHandle);
sergeyvc69853c2016-10-07 14:14:09 -0700522 return static_cast<jint>(bitmap->getGenerationID());
Chris Craik32054b02014-05-09 13:58:56 -0700523}
524
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400525static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700526 LocalScopedBitmap bitmap(bitmapHandle);
527 if (bitmap->info().alphaType() == kPremul_SkAlphaType) {
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400528 return JNI_TRUE;
529 }
530 return JNI_FALSE;
531}
532
Chris Craik32054b02014-05-09 13:58:56 -0700533static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700534 LocalScopedBitmap bitmap(bitmapHandle);
535 return !bitmap->info().isOpaque() ? JNI_TRUE : JNI_FALSE;
Chris Craik32054b02014-05-09 13:58:56 -0700536}
537
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400538static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle,
539 jboolean hasAlpha, jboolean requestPremul) {
John Reckf29ed282015-04-07 07:32:03 -0700540 LocalScopedBitmap bitmap(bitmapHandle);
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400541 if (hasAlpha) {
John Reck0781a2f2015-05-27 16:29:17 -0700542 bitmap->setAlphaType(
John Reckf29ed282015-04-07 07:32:03 -0700543 requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
Chris Craik32054b02014-05-09 13:58:56 -0700544 } else {
John Reck0781a2f2015-05-27 16:29:17 -0700545 bitmap->setAlphaType(kOpaque_SkAlphaType);
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400546 }
547}
548
549static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
550 jboolean isPremul) {
John Reckf29ed282015-04-07 07:32:03 -0700551 LocalScopedBitmap bitmap(bitmapHandle);
552 if (!bitmap->info().isOpaque()) {
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400553 if (isPremul) {
John Reck0781a2f2015-05-27 16:29:17 -0700554 bitmap->setAlphaType(kPremul_SkAlphaType);
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400555 } else {
John Reck0781a2f2015-05-27 16:29:17 -0700556 bitmap->setAlphaType(kUnpremul_SkAlphaType);
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400557 }
Chris Craik32054b02014-05-09 13:58:56 -0700558 }
559}
560
561static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700562 LocalScopedBitmap bitmap(bitmapHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700563 return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE;
564}
565
566static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle,
567 jboolean hasMipMap) {
John Reckf29ed282015-04-07 07:32:03 -0700568 LocalScopedBitmap bitmap(bitmapHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700569 bitmap->setHasHardwareMipMap(hasMipMap);
570}
571
572///////////////////////////////////////////////////////////////////////////////
573
Matt Sarett3ca39752017-05-26 10:55:38 -0400574// This is the maximum possible size because the SkColorSpace must be
575// representable (and therefore serializable) using a matrix and numerical
576// transfer function. If we allow more color space representations in the
577// framework, we may need to update this maximum size.
578static constexpr uint32_t kMaxColorSpaceSerializedBytes = 80;
579
Chris Craik32054b02014-05-09 13:58:56 -0700580static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100581#ifdef __ANDROID__ // Layoutlib does not support parcel
Chris Craik32054b02014-05-09 13:58:56 -0700582 if (parcel == NULL) {
583 SkDebugf("-------- unparcel parcel is NULL\n");
584 return NULL;
585 }
586
587 android::Parcel* p = android::parcelForJavaObject(env, parcel);
588
Mike Reedb9330552014-06-16 17:31:48 -0400589 const SkColorType colorType = (SkColorType)p->readInt32();
590 const SkAlphaType alphaType = (SkAlphaType)p->readInt32();
Romain Guy5acc4762017-03-07 15:29:27 -0800591 const uint32_t colorSpaceSize = p->readUint32();
592 sk_sp<SkColorSpace> colorSpace;
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500593 if (colorSpaceSize > 0) {
Matt Sarett3ca39752017-05-26 10:55:38 -0400594 if (colorSpaceSize > kMaxColorSpaceSerializedBytes) {
595 ALOGD("Bitmap_createFromParcel: Serialized SkColorSpace is larger than expected: "
596 "%d bytes\n", colorSpaceSize);
597 }
598
599 const void* data = p->readInplace(colorSpaceSize);
600 if (data) {
601 colorSpace = SkColorSpace::Deserialize(data, colorSpaceSize);
602 } else {
603 ALOGD("Bitmap_createFromParcel: Unable to read serialized SkColorSpace data\n");
604 }
Romain Guy5acc4762017-03-07 15:29:27 -0800605 }
Mike Reedb9330552014-06-16 17:31:48 -0400606 const int width = p->readInt32();
607 const int height = p->readInt32();
608 const int rowBytes = p->readInt32();
609 const int density = p->readInt32();
Chris Craik32054b02014-05-09 13:58:56 -0700610
Mike Reedb9330552014-06-16 17:31:48 -0400611 if (kN32_SkColorType != colorType &&
Romain Guy9505a652016-12-14 09:43:50 -0800612 kRGBA_F16_SkColorType != colorType &&
Mike Reedb9330552014-06-16 17:31:48 -0400613 kRGB_565_SkColorType != colorType &&
614 kARGB_4444_SkColorType != colorType &&
Mike Reedb9330552014-06-16 17:31:48 -0400615 kAlpha_8_SkColorType != colorType) {
616 SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType);
Chris Craik32054b02014-05-09 13:58:56 -0700617 return NULL;
618 }
619
Leon Scroggins IIIec419e02015-03-11 13:12:06 -0400620 std::unique_ptr<SkBitmap> bitmap(new SkBitmap);
Romain Guy9505a652016-12-14 09:43:50 -0800621 if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType, colorSpace),
622 rowBytes)) {
Leon Scroggins IIIec419e02015-03-11 13:12:06 -0400623 return NULL;
624 }
Chris Craik32054b02014-05-09 13:58:56 -0700625
Jeff Browna316c5d2015-06-05 15:14:06 -0700626 // Read the bitmap blob.
Mike Reed7569de02017-10-06 16:25:49 -0400627 size_t size = bitmap->computeByteSize();
Jeff Browna316c5d2015-06-05 15:14:06 -0700628 android::Parcel::ReadableBlob blob;
629 android::status_t status = p->readBlob(size, &blob);
630 if (status) {
Jeff Browna316c5d2015-06-05 15:14:06 -0700631 doThrowRE(env, "Could not read bitmap blob.");
Chris Craik32054b02014-05-09 13:58:56 -0700632 return NULL;
633 }
634
Jeff Browna316c5d2015-06-05 15:14:06 -0700635 // Map the bitmap in place from the ashmem region if possible otherwise copy.
sergeyvc1c54062016-10-19 18:47:26 -0700636 sk_sp<Bitmap> nativeBitmap;
John Reckefac0522020-01-24 16:04:26 -0800637 if (blob.fd() >= 0 && !blob.isMutable()) {
Jeff Browna316c5d2015-06-05 15:14:06 -0700638#if DEBUG_PARCEL
John Reckefac0522020-01-24 16:04:26 -0800639 ALOGD("Bitmap.createFromParcel: mapped contents of bitmap from %s blob "
Jeff Browna316c5d2015-06-05 15:14:06 -0700640 "(fds %s)",
Jeff Browna316c5d2015-06-05 15:14:06 -0700641 blob.isMutable() ? "mutable" : "immutable",
642 p->allowFds() ? "allowed" : "forbidden");
643#endif
644 // Dup the file descriptor so we can keep a reference to it after the Parcel
645 // is disposed.
Nick Kralevich07f1c1d2019-01-14 13:42:22 -0800646 int dupFd = fcntl(blob.fd(), F_DUPFD_CLOEXEC, 0);
Jeff Browna316c5d2015-06-05 15:14:06 -0700647 if (dupFd < 0) {
Erik Wolsheimer211abad2015-11-13 11:54:47 -0800648 ALOGE("Error allocating dup fd. Error:%d", errno);
Jeff Browna316c5d2015-06-05 15:14:06 -0700649 blob.release();
Jeff Browna316c5d2015-06-05 15:14:06 -0700650 doThrowRE(env, "Could not allocate dup blob fd.");
651 return NULL;
652 }
653
Derek Sollenbergere2169482018-11-20 10:57:20 -0500654 // Map the pixels in place and take ownership of the ashmem region. We must also respect the
655 // rowBytes value already set on the bitmap instead of attempting to compute our own.
656 nativeBitmap = Bitmap::createFrom(bitmap->info(), bitmap->rowBytes(), dupFd,
John Reckefac0522020-01-24 16:04:26 -0800657 const_cast<void*>(blob.data()), size, true);
Jeff Browna316c5d2015-06-05 15:14:06 -0700658 if (!nativeBitmap) {
659 close(dupFd);
660 blob.release();
661 doThrowRE(env, "Could not allocate ashmem pixel ref.");
662 return NULL;
663 }
664
665 // Clear the blob handle, don't release it.
666 blob.clear();
667 } else {
668#if DEBUG_PARCEL
669 if (blob.fd() >= 0) {
670 ALOGD("Bitmap.createFromParcel: copied contents of mutable bitmap "
671 "from immutable blob (fds %s)",
672 p->allowFds() ? "allowed" : "forbidden");
673 } else {
674 ALOGD("Bitmap.createFromParcel: copied contents from %s blob "
675 "(fds %s)",
676 blob.isMutable() ? "mutable" : "immutable",
677 p->allowFds() ? "allowed" : "forbidden");
678 }
679#endif
680
681 // Copy the pixels into a new buffer.
Leon Scroggins IIIf51a80d2017-07-12 10:46:35 -0400682 nativeBitmap = Bitmap::allocateHeapBitmap(bitmap.get());
Jeff Browna316c5d2015-06-05 15:14:06 -0700683 if (!nativeBitmap) {
684 blob.release();
685 doThrowRE(env, "Could not allocate java pixel ref.");
686 return NULL;
687 }
Jeff Browna316c5d2015-06-05 15:14:06 -0700688 memcpy(bitmap->getPixels(), blob.data(), size);
Jeff Browna316c5d2015-06-05 15:14:06 -0700689
690 // Release the blob handle.
691 blob.release();
Chris Craik32054b02014-05-09 13:58:56 -0700692 }
Chris Craik32054b02014-05-09 13:58:56 -0700693
sergeyvc36bd6c2016-10-11 15:49:16 -0700694 return createBitmap(env, nativeBitmap.release(),
John Reckefac0522020-01-24 16:04:26 -0800695 getPremulBitmapCreateFlags(false), NULL, NULL, density);
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100696#else
697 doThrowRE(env, "Cannot use parcels outside of Android");
698 return NULL;
699#endif
Chris Craik32054b02014-05-09 13:58:56 -0700700}
701
702static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
John Reckefac0522020-01-24 16:04:26 -0800703 jlong bitmapHandle, jint density, jobject parcel) {
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100704#ifdef __ANDROID__ // Layoutlib does not support parcel
Chris Craik32054b02014-05-09 13:58:56 -0700705 if (parcel == NULL) {
706 SkDebugf("------- writeToParcel null parcel\n");
707 return JNI_FALSE;
708 }
709
710 android::Parcel* p = android::parcelForJavaObject(env, parcel);
John Reckf29ed282015-04-07 07:32:03 -0700711 SkBitmap bitmap;
Riley Andrews39d7f302014-11-13 17:43:25 -0800712
sergeyvc1c54062016-10-19 18:47:26 -0700713 auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle);
714 bitmapWrapper->getSkBitmap(&bitmap);
Chris Craik32054b02014-05-09 13:58:56 -0700715
John Reckf29ed282015-04-07 07:32:03 -0700716 p->writeInt32(bitmap.colorType());
717 p->writeInt32(bitmap.alphaType());
Romain Guy5acc4762017-03-07 15:29:27 -0800718 SkColorSpace* colorSpace = bitmap.colorSpace();
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500719 if (colorSpace != nullptr) {
Romain Guy5acc4762017-03-07 15:29:27 -0800720 sk_sp<SkData> data = colorSpace->serialize();
721 size_t size = data->size();
722 p->writeUint32(size);
723 if (size > 0) {
Matt Sarett3ca39752017-05-26 10:55:38 -0400724 if (size > kMaxColorSpaceSerializedBytes) {
725 ALOGD("Bitmap_writeToParcel: Serialized SkColorSpace is larger than expected: "
726 "%zu bytes\n", size);
727 }
728
Romain Guy5acc4762017-03-07 15:29:27 -0800729 p->write(data->data(), size);
730 }
731 } else {
732 p->writeUint32(0);
733 }
John Reckf29ed282015-04-07 07:32:03 -0700734 p->writeInt32(bitmap.width());
735 p->writeInt32(bitmap.height());
736 p->writeInt32(bitmap.rowBytes());
Chris Craik32054b02014-05-09 13:58:56 -0700737 p->writeInt32(density);
738
Jeff Browna316c5d2015-06-05 15:14:06 -0700739 // Transfer the underlying ashmem region if we have one and it's immutable.
740 android::status_t status;
sergeyvaed7f582016-10-14 16:30:21 -0700741 int fd = bitmapWrapper->bitmap().getAshmemFd();
John Reckefac0522020-01-24 16:04:26 -0800742 if (fd >= 0 && p->allowFds()) {
Jeff Browna316c5d2015-06-05 15:14:06 -0700743#if DEBUG_PARCEL
744 ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as "
745 "immutable blob (fds %s)",
746 p->allowFds() ? "allowed" : "forbidden");
747#endif
748
749 status = p->writeDupImmutableBlobFileDescriptor(fd);
750 if (status) {
751 doThrowRE(env, "Could not write bitmap blob file descriptor.");
Riley Andrews39d7f302014-11-13 17:43:25 -0800752 return JNI_FALSE;
753 }
Jeff Browna316c5d2015-06-05 15:14:06 -0700754 return JNI_TRUE;
Riley Andrews39d7f302014-11-13 17:43:25 -0800755 }
Jeff Browna316c5d2015-06-05 15:14:06 -0700756
757 // Copy the bitmap to a new blob.
Jeff Browna316c5d2015-06-05 15:14:06 -0700758#if DEBUG_PARCEL
John Reckefac0522020-01-24 16:04:26 -0800759 ALOGD("Bitmap.writeToParcel: copying bitmap into new blob (fds %s)",
Jeff Browna316c5d2015-06-05 15:14:06 -0700760 p->allowFds() ? "allowed" : "forbidden");
761#endif
762
Mike Reed7569de02017-10-06 16:25:49 -0400763 size_t size = bitmap.computeByteSize();
Jeff Browna316c5d2015-06-05 15:14:06 -0700764 android::Parcel::WritableBlob blob;
John Reckefac0522020-01-24 16:04:26 -0800765 status = p->writeBlob(size, false, &blob);
Jeff Browna316c5d2015-06-05 15:14:06 -0700766 if (status) {
767 doThrowRE(env, "Could not copy bitmap to parcel blob.");
768 return JNI_FALSE;
769 }
770
Jeff Browna316c5d2015-06-05 15:14:06 -0700771 const void* pSrc = bitmap.getPixels();
772 if (pSrc == NULL) {
773 memset(blob.data(), 0, size);
774 } else {
775 memcpy(blob.data(), pSrc, size);
776 }
Jeff Browna316c5d2015-06-05 15:14:06 -0700777
778 blob.release();
Chris Craik32054b02014-05-09 13:58:56 -0700779 return JNI_TRUE;
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100780#else
781 doThrowRE(env, "Cannot use parcels outside of Android");
782 return JNI_FALSE;
783#endif
Chris Craik32054b02014-05-09 13:58:56 -0700784}
785
786static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
787 jlong srcHandle, jlong paintHandle,
788 jintArray offsetXY) {
John Reckf29ed282015-04-07 07:32:03 -0700789 SkBitmap src;
sergeyvc1c54062016-10-19 18:47:26 -0700790 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400791 const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700792 SkIPoint offset;
John Reckf29ed282015-04-07 07:32:03 -0700793 SkBitmap dst;
sergeyv45082182016-09-29 18:25:40 -0700794 HeapAllocator allocator;
Chris Craik32054b02014-05-09 13:58:56 -0700795
John Reckf29ed282015-04-07 07:32:03 -0700796 src.extractAlpha(&dst, paint, &allocator, &offset);
Chris Craik32054b02014-05-09 13:58:56 -0700797 // If Skia can't allocate pixels for destination bitmap, it resets
798 // it, that is set its pixels buffer to NULL, and zero width and height.
John Reckf29ed282015-04-07 07:32:03 -0700799 if (dst.getPixels() == NULL && src.getPixels() != NULL) {
Chris Craik32054b02014-05-09 13:58:56 -0700800 doThrowOOME(env, "failed to allocate pixels for alpha");
801 return NULL;
802 }
803 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
804 int* array = env->GetIntArrayElements(offsetXY, NULL);
805 array[0] = offset.fX;
806 array[1] = offset.fY;
807 env->ReleaseIntArrayElements(offsetXY, array, 0);
808 }
809
sergeyvc69853c2016-10-07 14:14:09 -0700810 return createBitmap(env, allocator.getStorageObjAndReset(),
John Reckf29ed282015-04-07 07:32:03 -0700811 getPremulBitmapCreateFlags(true));
Chris Craik32054b02014-05-09 13:58:56 -0700812}
813
814///////////////////////////////////////////////////////////////////////////////
815
Romain Guyefb4b062017-02-27 11:00:04 -0800816static jboolean Bitmap_isSRGB(JNIEnv* env, jobject, jlong bitmapHandle) {
817 LocalScopedBitmap bitmapHolder(bitmapHandle);
818 if (!bitmapHolder.valid()) return JNI_TRUE;
819
820 SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
Brian Osman91c9c282018-08-17 16:57:15 -0400821 return colorSpace == nullptr || colorSpace->isSRGB();
Romain Guyefb4b062017-02-27 11:00:04 -0800822}
823
Leon Scroggins IIIce89a6e2018-03-13 15:39:39 -0400824static jboolean Bitmap_isSRGBLinear(JNIEnv* env, jobject, jlong bitmapHandle) {
825 LocalScopedBitmap bitmapHolder(bitmapHandle);
826 if (!bitmapHolder.valid()) return JNI_FALSE;
827
828 SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
829 sk_sp<SkColorSpace> srgbLinear = SkColorSpace::MakeSRGBLinear();
830 return colorSpace == srgbLinear.get() ? JNI_TRUE : JNI_FALSE;
831}
832
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500833static jobject Bitmap_computeColorSpace(JNIEnv* env, jobject, jlong bitmapHandle) {
Romain Guyefb4b062017-02-27 11:00:04 -0800834 LocalScopedBitmap bitmapHolder(bitmapHandle);
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500835 if (!bitmapHolder.valid()) return nullptr;
Romain Guyefb4b062017-02-27 11:00:04 -0800836
837 SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500838 if (colorSpace == nullptr) return nullptr;
Romain Guyefb4b062017-02-27 11:00:04 -0800839
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500840 return GraphicsJNI::getColorSpace(env, colorSpace, bitmapHolder->info().colorType());
Romain Guyefb4b062017-02-27 11:00:04 -0800841}
842
Derek Sollenberger202084c2019-01-14 13:55:08 -0500843static void Bitmap_setColorSpace(JNIEnv* env, jobject, jlong bitmapHandle, jlong colorSpacePtr) {
844 LocalScopedBitmap bitmapHolder(bitmapHandle);
845 sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(colorSpacePtr);
846 bitmapHolder->setColorSpace(cs);
847}
848
Romain Guyefb4b062017-02-27 11:00:04 -0800849///////////////////////////////////////////////////////////////////////////////
850
Chris Craik32054b02014-05-09 13:58:56 -0700851static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400852 jint x, jint y) {
John Reckf29ed282015-04-07 07:32:03 -0700853 SkBitmap bitmap;
sergeyvc1c54062016-10-19 18:47:26 -0700854 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
Chris Craik32054b02014-05-09 13:58:56 -0700855
Brian Osman91c9c282018-08-17 16:57:15 -0400856 auto sRGB = SkColorSpace::MakeSRGB();
857 SkImageInfo dstInfo = SkImageInfo::Make(
858 1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
Chris Craik32054b02014-05-09 13:58:56 -0700859
Brian Osman91c9c282018-08-17 16:57:15 -0400860 SkColor dst;
861 bitmap.readPixels(dstInfo, &dst, dstInfo.minRowBytes(), x, y);
862 return static_cast<jint>(dst);
Chris Craik32054b02014-05-09 13:58:56 -0700863}
864
Leon Scroggins III870053d2019-01-24 08:37:27 -0500865static jlong Bitmap_getColor(JNIEnv* env, jobject, jlong bitmapHandle,
866 jint x, jint y) {
867 SkBitmap bitmap;
868 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
869
870 SkImageInfo dstInfo = SkImageInfo::Make(
871 1, 1, kRGBA_F16_SkColorType, kUnpremul_SkAlphaType, bitmap.refColorSpace());
872
873 uint64_t dst;
874 bitmap.readPixels(dstInfo, &dst, dstInfo.minRowBytes(), x, y);
875 return static_cast<jlong>(dst);
876}
877
Chris Craik32054b02014-05-09 13:58:56 -0700878static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,
879 jintArray pixelArray, jint offset, jint stride,
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400880 jint x, jint y, jint width, jint height) {
John Reckf29ed282015-04-07 07:32:03 -0700881 SkBitmap bitmap;
sergeyvc1c54062016-10-19 18:47:26 -0700882 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
Chris Craik32054b02014-05-09 13:58:56 -0700883
Brian Osman91c9c282018-08-17 16:57:15 -0400884 auto sRGB = SkColorSpace::MakeSRGB();
885 SkImageInfo dstInfo = SkImageInfo::Make(
886 width, height, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
Chris Craik32054b02014-05-09 13:58:56 -0700887
Chris Craik32054b02014-05-09 13:58:56 -0700888 jint* dst = env->GetIntArrayElements(pixelArray, NULL);
Brian Osman91c9c282018-08-17 16:57:15 -0400889 bitmap.readPixels(dstInfo, dst + offset, stride * 4, x, y);
Chris Craik32054b02014-05-09 13:58:56 -0700890 env->ReleaseIntArrayElements(pixelArray, dst, 0);
891}
892
893///////////////////////////////////////////////////////////////////////////////
894
895static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle,
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400896 jint x, jint y, jint colorHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700897 SkBitmap bitmap;
sergeyvc1c54062016-10-19 18:47:26 -0700898 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
Chris Craik32054b02014-05-09 13:58:56 -0700899 SkColor color = static_cast<SkColor>(colorHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700900
Brian Osman91c9c282018-08-17 16:57:15 -0400901 auto sRGB = SkColorSpace::MakeSRGB();
902 SkImageInfo srcInfo = SkImageInfo::Make(
903 1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
904 SkPixmap srcPM(srcInfo, &color, srcInfo.minRowBytes());
Chris Craik32054b02014-05-09 13:58:56 -0700905
Brian Osman91c9c282018-08-17 16:57:15 -0400906 bitmap.writePixels(srcPM, x, y);
Chris Craik32054b02014-05-09 13:58:56 -0700907}
908
909static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,
910 jintArray pixelArray, jint offset, jint stride,
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400911 jint x, jint y, jint width, jint height) {
John Reckf29ed282015-04-07 07:32:03 -0700912 SkBitmap bitmap;
sergeyvc1c54062016-10-19 18:47:26 -0700913 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
Chris Craik32054b02014-05-09 13:58:56 -0700914 GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
Brian Osman91c9c282018-08-17 16:57:15 -0400915 x, y, width, height, &bitmap);
Chris Craik32054b02014-05-09 13:58:56 -0700916}
917
918static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
919 jlong bitmapHandle, jobject jbuffer) {
John Reckf29ed282015-04-07 07:32:03 -0700920 SkBitmap bitmap;
sergeyvc1c54062016-10-19 18:47:26 -0700921 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
John Reckf29ed282015-04-07 07:32:03 -0700922 const void* src = bitmap.getPixels();
Chris Craik32054b02014-05-09 13:58:56 -0700923
924 if (NULL != src) {
925 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
926
927 // the java side has already checked that buffer is large enough
Mike Reed7569de02017-10-06 16:25:49 -0400928 memcpy(abp.pointer(), src, bitmap.computeByteSize());
Chris Craik32054b02014-05-09 13:58:56 -0700929 }
930}
931
932static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,
933 jlong bitmapHandle, jobject jbuffer) {
John Reckf29ed282015-04-07 07:32:03 -0700934 SkBitmap bitmap;
sergeyvc1c54062016-10-19 18:47:26 -0700935 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
John Reckf29ed282015-04-07 07:32:03 -0700936 void* dst = bitmap.getPixels();
Chris Craik32054b02014-05-09 13:58:56 -0700937
938 if (NULL != dst) {
939 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);
940 // the java side has already checked that buffer is large enough
Mike Reed7569de02017-10-06 16:25:49 -0400941 memcpy(dst, abp.pointer(), bitmap.computeByteSize());
John Reckf29ed282015-04-07 07:32:03 -0700942 bitmap.notifyPixelsChanged();
Chris Craik32054b02014-05-09 13:58:56 -0700943 }
944}
945
Chris Craik795bd0f2016-12-16 15:22:31 -0800946static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle, jlong bm1Handle) {
John Reckf29ed282015-04-07 07:32:03 -0700947 SkBitmap bm0;
948 SkBitmap bm1;
sergeyv1eabed32016-12-14 14:19:47 -0800949
950 LocalScopedBitmap bitmap0(bm0Handle);
951 LocalScopedBitmap bitmap1(bm1Handle);
952
953 // Paying the price for making Hardware Bitmap as Config:
954 // later check for colorType will pass successfully,
955 // because Hardware Config internally may be RGBA8888 or smth like that.
sergeyv15a10852016-12-27 14:32:03 -0800956 if (bitmap0->isHardware() != bitmap1->isHardware()) {
sergeyv1eabed32016-12-14 14:19:47 -0800957 return JNI_FALSE;
958 }
959
960 bitmap0->bitmap().getSkBitmap(&bm0);
961 bitmap1->bitmap().getSkBitmap(&bm1);
Chris Craik795bd0f2016-12-16 15:22:31 -0800962 if (bm0.width() != bm1.width()
963 || bm0.height() != bm1.height()
964 || bm0.colorType() != bm1.colorType()
965 || bm0.alphaType() != bm1.alphaType()
966 || !SkColorSpace::Equals(bm0.colorSpace(), bm1.colorSpace())) {
Chris Craik32054b02014-05-09 13:58:56 -0700967 return JNI_FALSE;
968 }
969
Chris Craik32054b02014-05-09 13:58:56 -0700970 // if we can't load the pixels, return false
John Reckf29ed282015-04-07 07:32:03 -0700971 if (NULL == bm0.getPixels() || NULL == bm1.getPixels()) {
Chris Craik32054b02014-05-09 13:58:56 -0700972 return JNI_FALSE;
973 }
974
Chris Craik32054b02014-05-09 13:58:56 -0700975 // now compare each scanline. We can't do the entire buffer at once,
976 // since we don't care about the pixel values that might extend beyond
977 // the width (since the scanline might be larger than the logical width)
John Reckf29ed282015-04-07 07:32:03 -0700978 const int h = bm0.height();
979 const size_t size = bm0.width() * bm0.bytesPerPixel();
Chris Craik32054b02014-05-09 13:58:56 -0700980 for (int y = 0; y < h; y++) {
henry.uh_chen53001ca2014-07-03 20:40:22 +0800981 // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config
982 // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0
983 // and bm1 both have pixel data() (have passed NULL == getPixels() check),
984 // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE
985 // to warn user those 2 unrecognized config bitmaps may be different.
John Reckf29ed282015-04-07 07:32:03 -0700986 void *bm0Addr = bm0.getAddr(0, y);
987 void *bm1Addr = bm1.getAddr(0, y);
henry.uh_chen53001ca2014-07-03 20:40:22 +0800988
989 if(bm0Addr == NULL || bm1Addr == NULL) {
990 return JNI_FALSE;
991 }
992
993 if (memcmp(bm0Addr, bm1Addr, size) != 0) {
Chris Craik32054b02014-05-09 13:58:56 -0700994 return JNI_FALSE;
995 }
996 }
997 return JNI_TRUE;
998}
999
John Reck43871902016-08-01 14:39:24 -07001000static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapPtr) {
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +01001001#ifdef __ANDROID__ // Layoutlib does not support render thread
John Reck43871902016-08-01 14:39:24 -07001002 LocalScopedBitmap bitmapHandle(bitmapPtr);
1003 if (!bitmapHandle.valid()) return;
sergeyvec4a4b12016-10-20 18:39:04 -07001004 android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmapHandle->bitmap());
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +01001005#endif
John Reck43871902016-08-01 14:39:24 -07001006}
1007
sergeyv45082182016-09-29 18:25:40 -07001008static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr) {
1009 LocalScopedBitmap bitmapHandle(bitmapPtr);
1010 return static_cast<jint>(bitmapHandle->getAllocationByteCount());
1011}
1012
sergeyv6e3658a2017-01-04 16:57:51 -08001013static jobject Bitmap_copyPreserveInternalConfig(JNIEnv* env, jobject, jlong bitmapPtr) {
sergeyv81f97ee2016-12-27 18:08:01 -08001014 LocalScopedBitmap bitmapHandle(bitmapPtr);
1015 LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
1016 "Hardware config is only supported config in Bitmap_nativeCopyPreserveInternalConfig");
1017 Bitmap& hwuiBitmap = bitmapHandle->bitmap();
1018 SkBitmap src;
1019 hwuiBitmap.getSkBitmap(&src);
1020
Derek Sollenbergere2169482018-11-20 10:57:20 -05001021 if (src.pixelRef() == nullptr) {
sergeyv81f97ee2016-12-27 18:08:01 -08001022 doThrowRE(env, "Could not copy a hardware bitmap.");
1023 return NULL;
1024 }
Derek Sollenbergere2169482018-11-20 10:57:20 -05001025
1026 sk_sp<Bitmap> bitmap = Bitmap::createFrom(src.info(), *src.pixelRef());
1027 return createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false));
sergeyv81f97ee2016-12-27 18:08:01 -08001028}
1029
Leon Scroggins III898ce752020-02-18 12:22:17 -05001030#ifdef __ANDROID__ // Layoutlib does not support graphic buffer
1031typedef AHardwareBuffer* (*AHB_from_HB)(JNIEnv*, jobject);
1032AHB_from_HB AHardwareBuffer_fromHardwareBuffer;
Leon Scroggins III5a190b12020-02-18 13:52:18 -05001033
1034typedef jobject (*AHB_to_HB)(JNIEnv*, AHardwareBuffer*);
1035AHB_to_HB AHardwareBuffer_toHardwareBuffer;
Leon Scroggins III898ce752020-02-18 12:22:17 -05001036#endif
1037
rennb2e9f522018-09-26 10:49:00 -07001038static jobject Bitmap_wrapHardwareBufferBitmap(JNIEnv* env, jobject, jobject hardwareBuffer,
Leon Scroggins III0e443d12018-12-19 11:38:35 -05001039 jlong colorSpacePtr) {
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +01001040#ifdef __ANDROID__ // Layoutlib does not support graphic buffer
Leon Scroggins III898ce752020-02-18 12:22:17 -05001041 AHardwareBuffer* buffer = AHardwareBuffer_fromHardwareBuffer(env, hardwareBuffer);
Derek Sollenbergere78f7c92019-07-31 15:18:47 -04001042 sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer,
1043 GraphicsJNI::getNativeColorSpace(colorSpacePtr));
rennb2e9f522018-09-26 10:49:00 -07001044 if (!bitmap.get()) {
1045 ALOGW("failed to create hardware bitmap from hardware buffer");
1046 return NULL;
1047 }
1048 return bitmap::createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false));
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +01001049#else
1050 return NULL;
1051#endif
rennb2e9f522018-09-26 10:49:00 -07001052}
1053
sergeyv6e3658a2017-01-04 16:57:51 -08001054static jobject Bitmap_createGraphicBufferHandle(JNIEnv* env, jobject, jlong bitmapPtr) {
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +01001055#ifdef __ANDROID__ // Layoutlib does not support graphic buffer
sergeyv6e3658a2017-01-04 16:57:51 -08001056 LocalScopedBitmap bitmapHandle(bitmapPtr);
1057 LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
1058 "Hardware config is only supported config in Bitmap_getGraphicBuffer");
1059
Derek Sollenbergere78f7c92019-07-31 15:18:47 -04001060 Bitmap& bitmap = bitmapHandle->bitmap();
1061 return android_graphics_GraphicBuffer_createFromAHardwareBuffer(env, bitmap.hardwareBuffer());
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +01001062#else
1063 return NULL;
1064#endif
sergeyv6e3658a2017-01-04 16:57:51 -08001065}
1066
Leon Scroggins III5a190b12020-02-18 13:52:18 -05001067static jobject Bitmap_getHardwareBuffer(JNIEnv* env, jobject, jlong bitmapPtr) {
1068#ifdef __ANDROID__ // Layoutlib does not support graphic buffer
1069 LocalScopedBitmap bitmapHandle(bitmapPtr);
1070 LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
1071 "Hardware config is only supported config in Bitmap_getHardwareBuffer");
1072
1073 Bitmap& bitmap = bitmapHandle->bitmap();
1074 return AHardwareBuffer_toHardwareBuffer(env, bitmap.hardwareBuffer());
1075#else
1076 return NULL;
1077#endif
1078}
1079
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +01001080static jboolean Bitmap_isImmutable(CRITICAL_JNI_PARAMS_COMMA jlong bitmapHandle) {
Nader Jawade7b51292018-04-12 17:55:31 -07001081 LocalScopedBitmap bitmapHolder(bitmapHandle);
1082 if (!bitmapHolder.valid()) return JNI_FALSE;
1083
1084 return bitmapHolder->bitmap().isImmutable() ? JNI_TRUE : JNI_FALSE;
1085}
1086
1087static void Bitmap_setImmutable(JNIEnv* env, jobject, jlong bitmapHandle) {
1088 LocalScopedBitmap bitmapHolder(bitmapHandle);
1089 if (!bitmapHolder.valid()) return;
1090
1091 return bitmapHolder->bitmap().setImmutable();
1092}
1093
Chris Craik32054b02014-05-09 13:58:56 -07001094///////////////////////////////////////////////////////////////////////////////
1095
Daniel Micay76f6a862015-09-19 17:31:01 -04001096static const JNINativeMethod gBitmapMethods[] = {
Leon Scroggins III0e443d12018-12-19 11:38:35 -05001097 { "nativeCreate", "([IIIIIIZJ)Landroid/graphics/Bitmap;",
Chris Craik32054b02014-05-09 13:58:56 -07001098 (void*)Bitmap_creator },
1099 { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;",
1100 (void*)Bitmap_copy },
Riley Andrews721ae5f2015-05-11 16:08:22 -07001101 { "nativeCopyAshmem", "(J)Landroid/graphics/Bitmap;",
1102 (void*)Bitmap_copyAshmem },
Winsona5fdde92016-04-14 15:27:15 -07001103 { "nativeCopyAshmemConfig", "(JI)Landroid/graphics/Bitmap;",
1104 (void*)Bitmap_copyAshmemConfig },
Richard Uhler775873a2015-12-29 12:37:39 -08001105 { "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer },
Leon Scroggins IIIf8adae12018-05-24 15:25:08 -04001106 { "nativeRecycle", "(J)V", (void*)Bitmap_recycle },
sergeyv45082182016-09-29 18:25:40 -07001107 { "nativeReconfigure", "(JIIIZ)V", (void*)Bitmap_reconfigure },
Chris Craik32054b02014-05-09 13:58:56 -07001108 { "nativeCompress", "(JIILjava/io/OutputStream;[B)Z",
1109 (void*)Bitmap_compress },
1110 { "nativeErase", "(JI)V", (void*)Bitmap_erase },
Leon Scroggins III94ba1002019-01-17 13:34:51 -05001111 { "nativeErase", "(JJJ)V", (void*)Bitmap_eraseLong },
Chris Craik32054b02014-05-09 13:58:56 -07001112 { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes },
1113 { "nativeConfig", "(J)I", (void*)Bitmap_config },
1114 { "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha },
Leon Scroggins III57ee6202014-06-04 18:51:07 -04001115 { "nativeIsPremultiplied", "(J)Z", (void*)Bitmap_isPremultiplied},
1116 { "nativeSetHasAlpha", "(JZZ)V", (void*)Bitmap_setHasAlpha},
1117 { "nativeSetPremultiplied", "(JZ)V", (void*)Bitmap_setPremultiplied},
Chris Craik32054b02014-05-09 13:58:56 -07001118 { "nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap },
1119 { "nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap },
1120 { "nativeCreateFromParcel",
1121 "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
1122 (void*)Bitmap_createFromParcel },
John Reckefac0522020-01-24 16:04:26 -08001123 { "nativeWriteToParcel", "(JILandroid/os/Parcel;)Z",
Chris Craik32054b02014-05-09 13:58:56 -07001124 (void*)Bitmap_writeToParcel },
1125 { "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;",
1126 (void*)Bitmap_extractAlpha },
1127 { "nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId },
Leon Scroggins III57ee6202014-06-04 18:51:07 -04001128 { "nativeGetPixel", "(JII)I", (void*)Bitmap_getPixel },
Leon Scroggins III870053d2019-01-24 08:37:27 -05001129 { "nativeGetColor", "(JII)J", (void*)Bitmap_getColor },
Leon Scroggins III57ee6202014-06-04 18:51:07 -04001130 { "nativeGetPixels", "(J[IIIIIII)V", (void*)Bitmap_getPixels },
1131 { "nativeSetPixel", "(JIII)V", (void*)Bitmap_setPixel },
1132 { "nativeSetPixels", "(J[IIIIIII)V", (void*)Bitmap_setPixels },
Chris Craik32054b02014-05-09 13:58:56 -07001133 { "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V",
1134 (void*)Bitmap_copyPixelsToBuffer },
1135 { "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V",
1136 (void*)Bitmap_copyPixelsFromBuffer },
1137 { "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs },
John Reck43871902016-08-01 14:39:24 -07001138 { "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw },
sergeyv45082182016-09-29 18:25:40 -07001139 { "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount },
sergeyv81f97ee2016-12-27 18:08:01 -08001140 { "nativeCopyPreserveInternalConfig", "(J)Landroid/graphics/Bitmap;",
sergeyv6e3658a2017-01-04 16:57:51 -08001141 (void*)Bitmap_copyPreserveInternalConfig },
Leon Scroggins III0e443d12018-12-19 11:38:35 -05001142 { "nativeWrapHardwareBufferBitmap", "(Landroid/hardware/HardwareBuffer;J)Landroid/graphics/Bitmap;",
rennb2e9f522018-09-26 10:49:00 -07001143 (void*) Bitmap_wrapHardwareBufferBitmap },
sergeyv6e3658a2017-01-04 16:57:51 -08001144 { "nativeCreateGraphicBufferHandle", "(J)Landroid/graphics/GraphicBuffer;",
Romain Guyefb4b062017-02-27 11:00:04 -08001145 (void*) Bitmap_createGraphicBufferHandle },
Leon Scroggins III5a190b12020-02-18 13:52:18 -05001146 { "nativeGetHardwareBuffer", "(J)Landroid/hardware/HardwareBuffer;",
1147 (void*) Bitmap_getHardwareBuffer },
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -05001148 { "nativeComputeColorSpace", "(J)Landroid/graphics/ColorSpace;", (void*)Bitmap_computeColorSpace },
Derek Sollenberger202084c2019-01-14 13:55:08 -05001149 { "nativeSetColorSpace", "(JJ)V", (void*)Bitmap_setColorSpace },
Romain Guyefb4b062017-02-27 11:00:04 -08001150 { "nativeIsSRGB", "(J)Z", (void*)Bitmap_isSRGB },
Leon Scroggins IIIce89a6e2018-03-13 15:39:39 -04001151 { "nativeIsSRGBLinear", "(J)Z", (void*)Bitmap_isSRGBLinear},
Nader Jawade7b51292018-04-12 17:55:31 -07001152 { "nativeSetImmutable", "(J)V", (void*)Bitmap_setImmutable},
1153
1154 // ------------ @CriticalNative ----------------
1155 { "nativeIsImmutable", "(J)Z", (void*)Bitmap_isImmutable}
1156
Chris Craik32054b02014-05-09 13:58:56 -07001157};
1158
Chris Craik32054b02014-05-09 13:58:56 -07001159int register_android_graphics_Bitmap(JNIEnv* env)
1160{
Romain Guy95648b82017-04-13 18:43:42 -07001161 gBitmap_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Bitmap"));
1162 gBitmap_nativePtr = GetFieldIDOrDie(env, gBitmap_class, "mNativePtr", "J");
Leon Scroggins IIIbbdb7312019-01-31 14:35:54 -05001163 gBitmap_constructorMethodID = GetMethodIDOrDie(env, gBitmap_class, "<init>", "(JIIIZ[BLandroid/graphics/NinePatch$InsetStruct;Z)V");
Romain Guy95648b82017-04-13 18:43:42 -07001164 gBitmap_reinitMethodID = GetMethodIDOrDie(env, gBitmap_class, "reinit", "(IIZ)V");
Leon Scroggins III898ce752020-02-18 12:22:17 -05001165
1166#ifdef __ANDROID__ // Layoutlib does not support graphic buffer
1167 void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
1168 AHardwareBuffer_fromHardwareBuffer =
1169 (AHB_from_HB)dlsym(handle_, "AHardwareBuffer_fromHardwareBuffer");
1170 LOG_ALWAYS_FATAL_IF(AHardwareBuffer_fromHardwareBuffer == nullptr,
1171 "Failed to find required symbol AHardwareBuffer_fromHardwareBuffer!");
Leon Scroggins III5a190b12020-02-18 13:52:18 -05001172
1173 AHardwareBuffer_toHardwareBuffer = (AHB_to_HB)dlsym(handle_, "AHardwareBuffer_toHardwareBuffer");
1174 LOG_ALWAYS_FATAL_IF(AHardwareBuffer_toHardwareBuffer == nullptr,
1175 " Failed to find required symbol AHardwareBuffer_toHardwareBuffer!");
Leon Scroggins III898ce752020-02-18 12:22:17 -05001176#endif
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001177 return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods,
1178 NELEM(gBitmapMethods));
John Reck9192d5e2016-10-31 10:32:09 -07001179}