blob: 010c4e8dfb3a6e43e75665b7ac66c85edbac1e6c [file] [log] [blame]
Sally Qide6041b2023-02-01 23:43:09 -08001// #define LOG_NDEBUG 0
John Reckf29ed282015-04-07 07:32:03 -07002#include "Bitmap.h"
3
Jerome Gaillard8ab756d2024-04-02 17:38:20 +01004#include <android-base/unique_fd.h>
Nader Jawada3521852023-01-30 20:23:46 -08005#include <hwui/Bitmap.h>
6#include <hwui/Paint.h>
Jerome Gaillard8ab756d2024-04-02 17:38:20 +01007#include <inttypes.h>
8#include <renderthread/RenderProxy.h>
9#include <string.h>
10
11#include <memory>
Nader Jawada3521852023-01-30 20:23:46 -080012
13#include "CreateJavaOutputStreamAdaptor.h"
John Reck5bd537e2023-01-24 20:13:45 -050014#include "Gainmap.h"
Kevin Lubick1175dc02022-02-28 12:41:27 -050015#include "GraphicsJNI.h"
Nader Jawada3521852023-01-30 20:23:46 -080016#include "HardwareBufferHelpers.h"
Sally Qi9d2d9342023-02-06 11:11:31 -080017#include "ScopedParcel.h"
Chris Craik32054b02014-05-09 13:58:56 -070018#include "SkBitmap.h"
Kevin Lubick1175dc02022-02-28 12:41:27 -050019#include "SkBlendMode.h"
John Reckbe671952021-01-13 22:39:32 -050020#include "SkCanvas.h"
21#include "SkColor.h"
22#include "SkColorSpace.h"
Kevin Lubick1175dc02022-02-28 12:41:27 -050023#include "SkData.h"
Leon Scroggins III57ee6202014-06-04 18:51:07 -040024#include "SkImageInfo.h"
Kevin Lubick1175dc02022-02-28 12:41:27 -050025#include "SkPaint.h"
Kevin Lubick1175dc02022-02-28 12:41:27 -050026#include "SkPixmap.h"
27#include "SkPoint.h"
28#include "SkRefCnt.h"
Chris Craik32054b02014-05-09 13:58:56 -070029#include "SkStream.h"
Kevin Lubick1175dc02022-02-28 12:41:27 -050030#include "SkTypes.h"
Chris Craik32054b02014-05-09 13:58:56 -070031#include "android_nio_utils.h"
Chris Craik32054b02014-05-09 13:58:56 -070032
Jeff Browna316c5d2015-06-05 15:14:06 -070033#define DEBUG_PARCEL 0
34
sergeyvc69853c2016-10-07 14:14:09 -070035static jclass gBitmap_class;
sergeyvc69853c2016-10-07 14:14:09 -070036
John Reckf29ed282015-04-07 07:32:03 -070037namespace android {
38
John Reck5bd537e2023-01-24 20:13:45 -050039jobject Gainmap_extractFromBitmap(JNIEnv* env, const Bitmap& bitmap);
40
sergeyvc1c54062016-10-19 18:47:26 -070041class BitmapWrapper {
John Reckf29ed282015-04-07 07:32:03 -070042public:
Chih-Hung Hsieh0727be12018-12-20 13:43:46 -080043 explicit BitmapWrapper(Bitmap* bitmap)
sergeyvc1c54062016-10-19 18:47:26 -070044 : mBitmap(bitmap) { }
sergeyvc69853c2016-10-07 14:14:09 -070045
46 void freePixels() {
sergeyvc1c54062016-10-19 18:47:26 -070047 mInfo = mBitmap->info();
48 mHasHardwareMipMap = mBitmap->hasHardwareMipMap();
49 mAllocationSize = mBitmap->getAllocationByteCount();
50 mRowBytes = mBitmap->rowBytes();
51 mGenerationId = mBitmap->getGenerationID();
sergeyv15a10852016-12-27 14:32:03 -080052 mIsHardware = mBitmap->isHardware();
sergeyvc1c54062016-10-19 18:47:26 -070053 mBitmap.reset();
John Reckf29ed282015-04-07 07:32:03 -070054 }
55
sergeyvc69853c2016-10-07 14:14:09 -070056 bool valid() {
Ben Wagner6b62ac02018-05-29 14:16:02 -040057 return mBitmap != nullptr;
John Reckf29ed282015-04-07 07:32:03 -070058 }
59
sergeyvaed7f582016-10-14 16:30:21 -070060 Bitmap& bitmap() {
61 assertValid();
62 return *mBitmap;
63 }
sergeyvc69853c2016-10-07 14:14:09 -070064
65 void assertValid() {
66 LOG_ALWAYS_FATAL_IF(!valid(), "Error, cannot access an invalid/free'd bitmap here!");
67 }
68
69 void getSkBitmap(SkBitmap* outBitmap) {
70 assertValid();
sergeyvc1c54062016-10-19 18:47:26 -070071 mBitmap->getSkBitmap(outBitmap);
sergeyvc69853c2016-10-07 14:14:09 -070072 }
73
74 bool hasHardwareMipMap() {
sergeyvc1c54062016-10-19 18:47:26 -070075 if (mBitmap) {
76 return mBitmap->hasHardwareMipMap();
John Reckf29ed282015-04-07 07:32:03 -070077 }
John Reckf29ed282015-04-07 07:32:03 -070078 return mHasHardwareMipMap;
79 }
80
81 void setHasHardwareMipMap(bool hasMipMap) {
sergeyvc69853c2016-10-07 14:14:09 -070082 assertValid();
sergeyvc1c54062016-10-19 18:47:26 -070083 mBitmap->setHasHardwareMipMap(hasMipMap);
John Reckf29ed282015-04-07 07:32:03 -070084 }
85
sergeyvc69853c2016-10-07 14:14:09 -070086 void setAlphaType(SkAlphaType alphaType) {
87 assertValid();
sergeyvc1c54062016-10-19 18:47:26 -070088 mBitmap->setAlphaType(alphaType);
John Reckf29ed282015-04-07 07:32:03 -070089 }
90
Derek Sollenberger202084c2019-01-14 13:55:08 -050091 void setColorSpace(sk_sp<SkColorSpace> colorSpace) {
92 assertValid();
93 mBitmap->setColorSpace(colorSpace);
94 }
95
sergeyvc69853c2016-10-07 14:14:09 -070096 const SkImageInfo& info() {
sergeyvc1c54062016-10-19 18:47:26 -070097 if (mBitmap) {
98 return mBitmap->info();
sergeyvc69853c2016-10-07 14:14:09 -070099 }
100 return mInfo;
John Reckf29ed282015-04-07 07:32:03 -0700101 }
102
sergeyvc69853c2016-10-07 14:14:09 -0700103 size_t getAllocationByteCount() const {
sergeyvc1c54062016-10-19 18:47:26 -0700104 if (mBitmap) {
105 return mBitmap->getAllocationByteCount();
sergeyvc69853c2016-10-07 14:14:09 -0700106 }
107 return mAllocationSize;
John Reckf29ed282015-04-07 07:32:03 -0700108 }
109
sergeyvc69853c2016-10-07 14:14:09 -0700110 size_t rowBytes() const {
sergeyvc1c54062016-10-19 18:47:26 -0700111 if (mBitmap) {
112 return mBitmap->rowBytes();
sergeyvc69853c2016-10-07 14:14:09 -0700113 }
114 return mRowBytes;
115 }
116
117 uint32_t getGenerationID() const {
sergeyvc1c54062016-10-19 18:47:26 -0700118 if (mBitmap) {
119 return mBitmap->getGenerationID();
sergeyvc69853c2016-10-07 14:14:09 -0700120 }
121 return mGenerationId;
122 }
123
sergeyv15a10852016-12-27 14:32:03 -0800124 bool isHardware() {
125 if (mBitmap) {
126 return mBitmap->isHardware();
127 }
128 return mIsHardware;
129 }
130
sergeyvc1c54062016-10-19 18:47:26 -0700131 ~BitmapWrapper() { }
sergeyvc69853c2016-10-07 14:14:09 -0700132
John Reckf29ed282015-04-07 07:32:03 -0700133private:
sergeyvc1c54062016-10-19 18:47:26 -0700134 sk_sp<Bitmap> mBitmap;
sergeyvc69853c2016-10-07 14:14:09 -0700135 SkImageInfo mInfo;
136 bool mHasHardwareMipMap;
137 size_t mAllocationSize;
138 size_t mRowBytes;
139 uint32_t mGenerationId;
sergeyv15a10852016-12-27 14:32:03 -0800140 bool mIsHardware;
John Reckf29ed282015-04-07 07:32:03 -0700141};
142
John Reckf29ed282015-04-07 07:32:03 -0700143// Convenience class that does not take a global ref on the pixels, relying
144// on the caller already having a local JNI ref
145class LocalScopedBitmap {
146public:
Chih-Hung Hsiehc6baf562016-04-27 11:29:23 -0700147 explicit LocalScopedBitmap(jlong bitmapHandle)
sergeyvc1c54062016-10-19 18:47:26 -0700148 : mBitmapWrapper(reinterpret_cast<BitmapWrapper*>(bitmapHandle)) {}
John Reckf29ed282015-04-07 07:32:03 -0700149
sergeyvc1c54062016-10-19 18:47:26 -0700150 BitmapWrapper* operator->() {
151 return mBitmapWrapper;
John Reckf29ed282015-04-07 07:32:03 -0700152 }
153
154 void* pixels() {
sergeyvaed7f582016-10-14 16:30:21 -0700155 return mBitmapWrapper->bitmap().pixels();
John Reckf29ed282015-04-07 07:32:03 -0700156 }
157
158 bool valid() {
sergeyvc1c54062016-10-19 18:47:26 -0700159 return mBitmapWrapper && mBitmapWrapper->valid();
John Reckf29ed282015-04-07 07:32:03 -0700160 }
161
162private:
sergeyvc1c54062016-10-19 18:47:26 -0700163 BitmapWrapper* mBitmapWrapper;
John Reckf29ed282015-04-07 07:32:03 -0700164};
165
sergeyvc69853c2016-10-07 14:14:09 -0700166namespace bitmap {
167
168// Assert that bitmap's SkAlphaType is consistent with isPremultiplied.
169static void assert_premultiplied(const SkImageInfo& info, bool isPremultiplied) {
170 // kOpaque_SkAlphaType and kIgnore_SkAlphaType mean that isPremultiplied is
171 // irrelevant. This just tests to ensure that the SkAlphaType is not
172 // opposite of isPremultiplied.
173 if (isPremultiplied) {
174 SkASSERT(info.alphaType() != kUnpremul_SkAlphaType);
175 } else {
176 SkASSERT(info.alphaType() != kPremul_SkAlphaType);
177 }
178}
179
180void reinitBitmap(JNIEnv* env, jobject javaBitmap, const SkImageInfo& info,
181 bool isPremultiplied)
182{
Eric Miao6e5ce892024-07-10 17:11:10 -0700183 static jmethodID gBitmap_reinitMethodID =
184 GetMethodIDOrDie(env, gBitmap_class, "reinit", "(IIZ)V");
185
sergeyvc69853c2016-10-07 14:14:09 -0700186 // The caller needs to have already set the alpha type properly, so the
187 // native SkBitmap stays in sync with the Java Bitmap.
188 assert_premultiplied(info, isPremultiplied);
189
190 env->CallVoidMethod(javaBitmap, gBitmap_reinitMethodID,
191 info.width(), info.height(), isPremultiplied);
192}
193
sergeyvc1c54062016-10-19 18:47:26 -0700194jobject createBitmap(JNIEnv* env, Bitmap* bitmap,
sergeyvc69853c2016-10-07 14:14:09 -0700195 int bitmapCreateFlags, jbyteArray ninePatchChunk, jobject ninePatchInsets,
196 int density) {
Eric Miao6e5ce892024-07-10 17:11:10 -0700197 static jmethodID gBitmap_constructorMethodID =
198 GetMethodIDOrDie(env, gBitmap_class,
199 "<init>", "(JIIIZ[BLandroid/graphics/NinePatch$InsetStruct;Z)V");
200
sergeyvc69853c2016-10-07 14:14:09 -0700201 bool isMutable = bitmapCreateFlags & kBitmapCreateFlag_Mutable;
202 bool isPremultiplied = bitmapCreateFlags & kBitmapCreateFlag_Premultiplied;
203 // The caller needs to have already set the alpha type properly, so the
204 // native SkBitmap stays in sync with the Java Bitmap.
sergeyvc1c54062016-10-19 18:47:26 -0700205 assert_premultiplied(bitmap->info(), isPremultiplied);
Leon Scroggins IIIbbdb7312019-01-31 14:35:54 -0500206 bool fromMalloc = bitmap->pixelStorageType() == PixelStorageType::Heap;
sergeyvc1c54062016-10-19 18:47:26 -0700207 BitmapWrapper* bitmapWrapper = new BitmapWrapper(bitmap);
Nader Jawade7b51292018-04-12 17:55:31 -0700208 if (!isMutable) {
209 bitmapWrapper->bitmap().setImmutable();
210 }
sergeyvc69853c2016-10-07 14:14:09 -0700211 jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
sergeyvc1c54062016-10-19 18:47:26 -0700212 reinterpret_cast<jlong>(bitmapWrapper), bitmap->width(), bitmap->height(), density,
Leon Scroggins IIIbbdb7312019-01-31 14:35:54 -0500213 isPremultiplied, ninePatchChunk, ninePatchInsets, fromMalloc);
sergeyvc69853c2016-10-07 14:14:09 -0700214
215 if (env->ExceptionCheck() != 0) {
216 ALOGE("*** Uncaught exception returned from Java call!\n");
217 env->ExceptionDescribe();
218 }
219 return obj;
220}
221
222void toSkBitmap(jlong bitmapHandle, SkBitmap* outBitmap) {
223 LocalScopedBitmap bitmap(bitmapHandle);
224 bitmap->getSkBitmap(outBitmap);
225}
226
Leon Scroggins III71fae622019-03-26 16:28:41 -0400227Bitmap& toBitmap(jlong bitmapHandle) {
sergeyv5fd2a1c2016-10-20 15:04:28 -0700228 LocalScopedBitmap localBitmap(bitmapHandle);
229 return localBitmap->bitmap();
230}
231
sergeyvc69853c2016-10-07 14:14:09 -0700232} // namespace bitmap
233
234} // namespace android
235
236using namespace android;
237using namespace android::bitmap;
238
Eric Miao6e5ce892024-07-10 17:11:10 -0700239static inline jlong getNativePtr(JNIEnv* env, jobject bitmap) {
240 static jfieldID gBitmap_nativePtr =
241 GetFieldIDOrDie(env, gBitmap_class, "mNativePtr", "J");
242 return env->GetLongField(bitmap, gBitmap_nativePtr);
243}
244
Derek Sollenberger6c41ab12019-11-08 08:50:58 -0500245Bitmap* GraphicsJNI::getNativeBitmap(JNIEnv* env, jobject bitmap) {
246 SkASSERT(env);
247 SkASSERT(bitmap);
248 SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
Eric Miao6e5ce892024-07-10 17:11:10 -0700249 jlong bitmapHandle = getNativePtr(env, bitmap);
Derek Sollenberger6c41ab12019-11-08 08:50:58 -0500250 LocalScopedBitmap localBitmap(bitmapHandle);
251 return localBitmap.valid() ? &localBitmap->bitmap() : nullptr;
252}
253
Leon Scroggins III84a2afc2020-01-19 19:27:16 -0500254SkImageInfo GraphicsJNI::getBitmapInfo(JNIEnv* env, jobject bitmap, uint32_t* outRowBytes,
255 bool* isHardware) {
Derek Sollenberger6c41ab12019-11-08 08:50:58 -0500256 SkASSERT(env);
257 SkASSERT(bitmap);
258 SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
Eric Miao6e5ce892024-07-10 17:11:10 -0700259 jlong bitmapHandle = getNativePtr(env, bitmap);
Derek Sollenberger6c41ab12019-11-08 08:50:58 -0500260 LocalScopedBitmap localBitmap(bitmapHandle);
261 if (outRowBytes) {
262 *outRowBytes = localBitmap->rowBytes();
263 }
Leon Scroggins III84a2afc2020-01-19 19:27:16 -0500264 if (isHardware) {
265 *isHardware = localBitmap->isHardware();
266 }
Derek Sollenberger6c41ab12019-11-08 08:50:58 -0500267 return localBitmap->info();
268}
269
Chris Craik32054b02014-05-09 13:58:56 -0700270bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride,
Brian Osman91c9c282018-08-17 16:57:15 -0400271 int x, int y, int width, int height, SkBitmap* dstBitmap) {
Chris Craik32054b02014-05-09 13:58:56 -0700272 const jint* array = env->GetIntArrayElements(srcColors, NULL);
273 const SkColor* src = (const SkColor*)array + srcOffset;
274
Brian Osman91c9c282018-08-17 16:57:15 -0400275 auto sRGB = SkColorSpace::MakeSRGB();
276 SkImageInfo srcInfo = SkImageInfo::Make(
277 width, height, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
278 SkPixmap srcPM(srcInfo, src, srcStride * 4);
Romain Guyce217fa2017-03-08 15:58:06 -0800279
Brian Osman91c9c282018-08-17 16:57:15 -0400280 dstBitmap->writePixels(srcPM, x, y);
Chris Craik32054b02014-05-09 13:58:56 -0700281
Romain Guy9505a652016-12-14 09:43:50 -0800282 env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array), JNI_ABORT);
Chris Craik32054b02014-05-09 13:58:56 -0700283 return true;
284}
285
Chris Craik32054b02014-05-09 13:58:56 -0700286///////////////////////////////////////////////////////////////////////////////
287///////////////////////////////////////////////////////////////////////////////
288
289static int getPremulBitmapCreateFlags(bool isMutable) {
sergeyvc69853c2016-10-07 14:14:09 -0700290 int flags = android::bitmap::kBitmapCreateFlag_Premultiplied;
291 if (isMutable) flags |= android::bitmap::kBitmapCreateFlag_Mutable;
Chris Craik32054b02014-05-09 13:58:56 -0700292 return flags;
293}
294
295static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
296 jint offset, jint stride, jint width, jint height,
Romain Guy82426562017-04-04 19:38:50 -0700297 jint configHandle, jboolean isMutable,
Leon Scroggins III0e443d12018-12-19 11:38:35 -0500298 jlong colorSpacePtr) {
Mike Reed1103b322014-07-08 12:36:44 -0400299 SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700300 if (NULL != jColors) {
301 size_t n = env->GetArrayLength(jColors);
302 if (n < SkAbs32(stride) * (size_t)height) {
303 doThrowAIOOBE(env);
304 return NULL;
305 }
306 }
307
308 // ARGB_4444 is a deprecated format, convert automatically to 8888
Mike Reedb933055c2014-06-16 17:31:48 -0400309 if (colorType == kARGB_4444_SkColorType) {
310 colorType = kN32_SkColorType;
Chris Craik32054b02014-05-09 13:58:56 -0700311 }
312
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500313 sk_sp<SkColorSpace> colorSpace;
314 if (colorType == kAlpha_8_SkColorType) {
315 colorSpace = nullptr;
316 } else {
317 colorSpace = GraphicsJNI::getNativeColorSpace(colorSpacePtr);
318 }
319
Chris Craik32054b02014-05-09 13:58:56 -0700320 SkBitmap bitmap;
Leon Scroggins III0e443d12018-12-19 11:38:35 -0500321 bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType,
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500322 colorSpace));
Chris Craik32054b02014-05-09 13:58:56 -0700323
Leon Scroggins IIIf51a80d2017-07-12 10:46:35 -0400324 sk_sp<Bitmap> nativeBitmap = Bitmap::allocateHeapBitmap(&bitmap);
John Reckf29ed282015-04-07 07:32:03 -0700325 if (!nativeBitmap) {
Leon Scroggins IIIf3a02992017-10-03 14:00:20 -0400326 ALOGE("OOM allocating Bitmap with dimensions %i x %i", width, height);
327 doThrowOOME(env);
Chris Craik32054b02014-05-09 13:58:56 -0700328 return NULL;
329 }
330
331 if (jColors != NULL) {
Brian Osman91c9c282018-08-17 16:57:15 -0400332 GraphicsJNI::SetPixels(env, jColors, offset, stride, 0, 0, width, height, &bitmap);
Chris Craik32054b02014-05-09 13:58:56 -0700333 }
334
sergeyvc36bd6c2016-10-11 15:49:16 -0700335 return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable));
Chris Craik32054b02014-05-09 13:58:56 -0700336}
337
Matt Sarett5320a722017-03-20 13:51:29 -0400338static bool bitmapCopyTo(SkBitmap* dst, SkColorType dstCT, const SkBitmap& src,
339 SkBitmap::Allocator* alloc) {
Matt Sarette9834402017-04-25 13:49:42 -0400340 SkPixmap srcPM;
341 if (!src.peekPixels(&srcPM)) {
342 return false;
343 }
344
345 SkImageInfo dstInfo = srcPM.info().makeColorType(dstCT);
346 switch (dstCT) {
347 case kRGB_565_SkColorType:
Brian Osmanbaf13e82018-09-21 11:21:30 -0400348 dstInfo = dstInfo.makeAlphaType(kOpaque_SkAlphaType);
Matt Sarette9834402017-04-25 13:49:42 -0400349 break;
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500350 case kAlpha_8_SkColorType:
351 dstInfo = dstInfo.makeColorSpace(nullptr);
Matt Sarette9834402017-04-25 13:49:42 -0400352 break;
353 default:
354 break;
355 }
356
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500357 if (!dstInfo.colorSpace() && dstCT != kAlpha_8_SkColorType) {
358 dstInfo = dstInfo.makeColorSpace(SkColorSpace::MakeSRGB());
359 }
360
Matt Sarette9834402017-04-25 13:49:42 -0400361 if (!dst->setInfo(dstInfo)) {
362 return false;
363 }
Mike Reed81397c42017-07-18 17:04:16 -0400364 if (!dst->tryAllocPixels(alloc)) {
Matt Sarette9834402017-04-25 13:49:42 -0400365 return false;
366 }
367
Matt Sarette9834402017-04-25 13:49:42 -0400368 SkPixmap dstPM;
369 if (!dst->peekPixels(&dstPM)) {
370 return false;
371 }
372
Matt Sarette9834402017-04-25 13:49:42 -0400373 return srcPM.readPixels(dstPM);
Matt Sarett5320a722017-03-20 13:51:29 -0400374}
375
Sally Qide6041b2023-02-01 23:43:09 -0800376static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle, jint dstConfigHandle,
377 jboolean isMutable) {
378 LocalScopedBitmap bitmapHolder(srcHandle);
379 if (!bitmapHolder.valid()) {
380 return NULL;
381 }
382 const Bitmap& original = bitmapHolder->bitmap();
383 const bool hasGainmap = original.hasGainmap();
John Reckf29ed282015-04-07 07:32:03 -0700384 SkBitmap src;
Sally Qide6041b2023-02-01 23:43:09 -0800385 bitmapHolder->getSkBitmap(&src);
386
sergeyv05126d12016-12-15 19:50:15 -0800387 if (dstConfigHandle == GraphicsJNI::hardwareLegacyBitmapConfig()) {
388 sk_sp<Bitmap> bitmap(Bitmap::allocateHardwareBitmap(src));
389 if (!bitmap.get()) {
390 return NULL;
391 }
Sally Qide6041b2023-02-01 23:43:09 -0800392 if (hasGainmap) {
Sally Qi587fb572023-03-03 15:50:06 -0800393 auto gm = uirenderer::Gainmap::allocateHardwareGainmap(original.gainmap());
394 if (gm) {
395 bitmap->setGainmap(std::move(gm));
Sally Qide6041b2023-02-01 23:43:09 -0800396 }
Sally Qide6041b2023-02-01 23:43:09 -0800397 }
sergeyv656117b2017-02-28 15:25:10 -0800398 return createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(isMutable));
sergeyv05126d12016-12-15 19:50:15 -0800399 }
400
Mike Reed1103b322014-07-08 12:36:44 -0400401 SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
sergeyv45082182016-09-29 18:25:40 -0700402 SkBitmap result;
403 HeapAllocator allocator;
Chris Craik32054b02014-05-09 13:58:56 -0700404
Matt Sarett5320a722017-03-20 13:51:29 -0400405 if (!bitmapCopyTo(&result, dstCT, src, &allocator)) {
Chris Craik32054b02014-05-09 13:58:56 -0700406 return NULL;
407 }
sergeyvc1c54062016-10-19 18:47:26 -0700408 auto bitmap = allocator.getStorageObjAndReset();
Sally Qide6041b2023-02-01 23:43:09 -0800409 if (hasGainmap) {
410 auto gainmap = sp<uirenderer::Gainmap>::make();
411 gainmap->info = original.gainmap()->info;
412 const SkBitmap skSrcBitmap = original.gainmap()->bitmap->getSkBitmap();
413 SkBitmap skDestBitmap;
414 HeapAllocator destAllocator;
415 if (!bitmapCopyTo(&skDestBitmap, dstCT, skSrcBitmap, &destAllocator)) {
416 return NULL;
417 }
418 gainmap->bitmap = sk_sp<Bitmap>(destAllocator.getStorageObjAndReset());
Sally Qi9f240c12023-02-13 21:19:18 +0000419 bitmap->setGainmap(std::move(gainmap));
Sally Qide6041b2023-02-01 23:43:09 -0800420 }
sergeyvc1c54062016-10-19 18:47:26 -0700421 return createBitmap(env, bitmap, getPremulBitmapCreateFlags(isMutable));
Chris Craik32054b02014-05-09 13:58:56 -0700422}
423
sergeyvc1c54062016-10-19 18:47:26 -0700424static Bitmap* Bitmap_copyAshmemImpl(JNIEnv* env, SkBitmap& src, SkColorType& dstCT) {
Riley Andrews721ae5f2015-05-11 16:08:22 -0700425 SkBitmap result;
426
427 AshmemPixelAllocator allocator(env);
Matt Sarett5320a722017-03-20 13:51:29 -0400428 if (!bitmapCopyTo(&result, dstCT, src, &allocator)) {
Riley Andrews721ae5f2015-05-11 16:08:22 -0700429 return NULL;
430 }
sergeyvc1c54062016-10-19 18:47:26 -0700431 auto bitmap = allocator.getStorageObjAndReset();
432 bitmap->setImmutable();
433 return bitmap;
Winsona5fdde92016-04-14 15:27:15 -0700434}
435
436static jobject Bitmap_copyAshmem(JNIEnv* env, jobject, jlong srcHandle) {
437 SkBitmap src;
sergeyvc1c54062016-10-19 18:47:26 -0700438 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
Winsona5fdde92016-04-14 15:27:15 -0700439 SkColorType dstCT = src.colorType();
sergeyvc1c54062016-10-19 18:47:26 -0700440 auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
441 jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
Winsona5fdde92016-04-14 15:27:15 -0700442 return ret;
443}
444
445static jobject Bitmap_copyAshmemConfig(JNIEnv* env, jobject, jlong srcHandle, jint dstConfigHandle) {
446 SkBitmap src;
sergeyvc1c54062016-10-19 18:47:26 -0700447 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
Winsona5fdde92016-04-14 15:27:15 -0700448 SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
sergeyvc1c54062016-10-19 18:47:26 -0700449 auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
450 jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
Riley Andrews721ae5f2015-05-11 16:08:22 -0700451 return ret;
452}
453
Derek Sollenberger3a269b02022-12-12 15:22:07 -0500454static jint Bitmap_getAshmemFd(JNIEnv* env, jobject, jlong bitmapHandle) {
455 LocalScopedBitmap bitmap(bitmapHandle);
456 return (bitmap.valid()) ? bitmap->bitmap().getAshmemFd() : -1;
457}
458
sergeyvc1c54062016-10-19 18:47:26 -0700459static void Bitmap_destruct(BitmapWrapper* bitmap) {
sergeyvc69853c2016-10-07 14:14:09 -0700460 delete bitmap;
Chris Craik32054b02014-05-09 13:58:56 -0700461}
462
Richard Uhler775873a2015-12-29 12:37:39 -0800463static jlong Bitmap_getNativeFinalizer(JNIEnv*, jobject) {
464 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Bitmap_destruct));
465}
466
Leon Scroggins IIIf8adae12018-05-24 15:25:08 -0400467static void Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700468 LocalScopedBitmap bitmap(bitmapHandle);
469 bitmap->freePixels();
Chris Craik32054b02014-05-09 13:58:56 -0700470}
471
472static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
sergeyv45082182016-09-29 18:25:40 -0700473 jint width, jint height, jint configHandle, jboolean requestPremul) {
John Reckf29ed282015-04-07 07:32:03 -0700474 LocalScopedBitmap bitmap(bitmapHandle);
sergeyvc69853c2016-10-07 14:14:09 -0700475 bitmap->assertValid();
Mike Reed1103b322014-07-08 12:36:44 -0400476 SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
Leon Scroggins III17a8bfc2014-06-03 16:15:15 -0400477
478 // ARGB_4444 is a deprecated format, convert automatically to 8888
479 if (colorType == kARGB_4444_SkColorType) {
480 colorType = kN32_SkColorType;
481 }
sergeyv45082182016-09-29 18:25:40 -0700482 size_t requestedSize = width * height * SkColorTypeBytesPerPixel(colorType);
483 if (requestedSize > bitmap->getAllocationByteCount()) {
Chris Craik32054b02014-05-09 13:58:56 -0700484 // done in native as there's no way to get BytesPerPixel in Java
485 doThrowIAE(env, "Bitmap not large enough to support new configuration");
486 return;
487 }
Leon Scroggins III17a8bfc2014-06-03 16:15:15 -0400488 SkAlphaType alphaType;
John Reckf29ed282015-04-07 07:32:03 -0700489 if (bitmap->info().colorType() != kRGB_565_SkColorType
490 && bitmap->info().alphaType() == kOpaque_SkAlphaType) {
Leon Scroggins III17a8bfc2014-06-03 16:15:15 -0400491 // If the original bitmap was set to opaque, keep that setting, unless it
492 // was 565, which is required to be opaque.
493 alphaType = kOpaque_SkAlphaType;
494 } else {
495 // Otherwise respect the premultiplied request.
496 alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
497 }
sergeyvaed7f582016-10-14 16:30:21 -0700498 bitmap->bitmap().reconfigure(SkImageInfo::Make(width, height, colorType, alphaType,
sergeyv7d5219f2016-11-03 16:18:16 -0700499 sk_ref_sp(bitmap->info().colorSpace())));
Chris Craik32054b02014-05-09 13:58:56 -0700500}
501
Chris Craik32054b02014-05-09 13:58:56 -0700502static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle,
503 jint format, jint quality,
504 jobject jstream, jbyteArray jstorage) {
Hal Canary10219fb2016-11-23 20:41:22 -0500505 LocalScopedBitmap bitmap(bitmapHandle);
John Reckf29ed282015-04-07 07:32:03 -0700506 if (!bitmap.valid()) {
507 return JNI_FALSE;
508 }
509
John Reckf29ed282015-04-07 07:32:03 -0700510 std::unique_ptr<SkWStream> strm(CreateJavaOutputStreamAdaptor(env, jstream, jstorage));
511 if (!strm.get()) {
512 return JNI_FALSE;
513 }
Chris Craik32054b02014-05-09 13:58:56 -0700514
Leon Scroggins III9010e8b2019-08-20 11:27:17 -0400515 auto fm = static_cast<Bitmap::JavaCompressFormat>(format);
Leon Scroggins III949c6002020-01-23 16:20:39 -0500516 return bitmap->bitmap().compress(fm, quality, strm.get()) ? JNI_TRUE : JNI_FALSE;
Chris Craik32054b02014-05-09 13:58:56 -0700517}
518
Leon Scroggins III4c4259b2018-12-17 10:40:07 -0500519static inline void bitmapErase(SkBitmap bitmap, const SkColor4f& color,
520 const sk_sp<SkColorSpace>& colorSpace) {
521 SkPaint p;
522 p.setColor4f(color, colorSpace.get());
523 p.setBlendMode(SkBlendMode::kSrc);
524 SkCanvas canvas(bitmap);
525 canvas.drawPaint(p);
526}
527
Chris Craik32054b02014-05-09 13:58:56 -0700528static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) {
John Reckf29ed282015-04-07 07:32:03 -0700529 LocalScopedBitmap bitmap(bitmapHandle);
530 SkBitmap skBitmap;
531 bitmap->getSkBitmap(&skBitmap);
Leon Scroggins III4c4259b2018-12-17 10:40:07 -0500532 bitmapErase(skBitmap, SkColor4f::FromColor(color), SkColorSpace::MakeSRGB());
533}
534
Leon Scroggins III94ba1002019-01-17 13:34:51 -0500535static void Bitmap_eraseLong(JNIEnv* env, jobject, jlong bitmapHandle,
536 jlong colorSpaceHandle, jlong colorLong) {
Leon Scroggins III4c4259b2018-12-17 10:40:07 -0500537 LocalScopedBitmap bitmap(bitmapHandle);
538 SkBitmap skBitmap;
539 bitmap->getSkBitmap(&skBitmap);
Leon Scroggins III0e443d12018-12-19 11:38:35 -0500540
Leon Scroggins III94ba1002019-01-17 13:34:51 -0500541 SkColor4f color = GraphicsJNI::convertColorLong(colorLong);
Leon Scroggins III0e443d12018-12-19 11:38:35 -0500542 sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
Leon Scroggins III4c4259b2018-12-17 10:40:07 -0500543 bitmapErase(skBitmap, color, cs);
Chris Craik32054b02014-05-09 13:58:56 -0700544}
545
546static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700547 LocalScopedBitmap bitmap(bitmapHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700548 return static_cast<jint>(bitmap->rowBytes());
549}
550
551static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700552 LocalScopedBitmap bitmap(bitmapHandle);
sergeyv15a10852016-12-27 14:32:03 -0800553 if (bitmap->isHardware()) {
sergeyv19b4b012016-12-13 16:06:00 -0800554 return GraphicsJNI::hardwareLegacyBitmapConfig();
555 }
John Reckf29ed282015-04-07 07:32:03 -0700556 return GraphicsJNI::colorTypeToLegacyBitmapConfig(bitmap->info().colorType());
Chris Craik32054b02014-05-09 13:58:56 -0700557}
558
559static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700560 LocalScopedBitmap bitmap(bitmapHandle);
sergeyvc69853c2016-10-07 14:14:09 -0700561 return static_cast<jint>(bitmap->getGenerationID());
Chris Craik32054b02014-05-09 13:58:56 -0700562}
563
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400564static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700565 LocalScopedBitmap bitmap(bitmapHandle);
566 if (bitmap->info().alphaType() == kPremul_SkAlphaType) {
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400567 return JNI_TRUE;
568 }
569 return JNI_FALSE;
570}
571
Chris Craik32054b02014-05-09 13:58:56 -0700572static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700573 LocalScopedBitmap bitmap(bitmapHandle);
574 return !bitmap->info().isOpaque() ? JNI_TRUE : JNI_FALSE;
Chris Craik32054b02014-05-09 13:58:56 -0700575}
576
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400577static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle,
578 jboolean hasAlpha, jboolean requestPremul) {
John Reckf29ed282015-04-07 07:32:03 -0700579 LocalScopedBitmap bitmap(bitmapHandle);
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400580 if (hasAlpha) {
John Reck0781a2f2015-05-27 16:29:17 -0700581 bitmap->setAlphaType(
John Reckf29ed282015-04-07 07:32:03 -0700582 requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
Chris Craik32054b02014-05-09 13:58:56 -0700583 } else {
John Reck0781a2f2015-05-27 16:29:17 -0700584 bitmap->setAlphaType(kOpaque_SkAlphaType);
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400585 }
586}
587
588static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
589 jboolean isPremul) {
John Reckf29ed282015-04-07 07:32:03 -0700590 LocalScopedBitmap bitmap(bitmapHandle);
591 if (!bitmap->info().isOpaque()) {
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400592 if (isPremul) {
John Reck0781a2f2015-05-27 16:29:17 -0700593 bitmap->setAlphaType(kPremul_SkAlphaType);
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400594 } else {
John Reck0781a2f2015-05-27 16:29:17 -0700595 bitmap->setAlphaType(kUnpremul_SkAlphaType);
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400596 }
Chris Craik32054b02014-05-09 13:58:56 -0700597 }
598}
599
600static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700601 LocalScopedBitmap bitmap(bitmapHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700602 return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE;
603}
604
605static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle,
606 jboolean hasMipMap) {
John Reckf29ed282015-04-07 07:32:03 -0700607 LocalScopedBitmap bitmap(bitmapHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700608 bitmap->setHasHardwareMipMap(hasMipMap);
609}
610
611///////////////////////////////////////////////////////////////////////////////
612
John Recka18d7c82020-03-02 09:41:33 -0800613// TODO: Move somewhere else
Sally Qi9d2d9342023-02-06 11:11:31 -0800614#ifdef __ANDROID__ // Layoutlib does not support parcel
John Recka18d7c82020-03-02 09:41:33 -0800615#define ON_ERROR_RETURN(X) \
616 if ((error = (X)) != STATUS_OK) return error
617
618template <typename T, typename U>
619static binder_status_t readBlob(AParcel* parcel, T inPlaceCallback, U ashmemCallback) {
620 binder_status_t error = STATUS_OK;
621 BlobType type;
622 static_assert(sizeof(BlobType) == sizeof(int32_t));
623 ON_ERROR_RETURN(AParcel_readInt32(parcel, (int32_t*)&type));
624 if (type == BlobType::IN_PLACE) {
625 struct Data {
626 std::unique_ptr<int8_t[]> ptr = nullptr;
627 int32_t size = 0;
628 } data;
629 ON_ERROR_RETURN(
630 AParcel_readByteArray(parcel, &data,
631 [](void* arrayData, int32_t length, int8_t** outBuffer) {
632 Data* data = reinterpret_cast<Data*>(arrayData);
633 if (length > 0) {
634 data->ptr = std::make_unique<int8_t[]>(length);
635 data->size = length;
636 *outBuffer = data->ptr.get();
637 }
638 return data->ptr != nullptr;
639 }));
John Reckaca134f2022-01-18 13:23:00 -0500640 return inPlaceCallback(std::move(data.ptr), data.size);
John Recka18d7c82020-03-02 09:41:33 -0800641 } else if (type == BlobType::ASHMEM) {
642 int rawFd = -1;
643 int32_t size = 0;
644 ON_ERROR_RETURN(AParcel_readInt32(parcel, &size));
645 ON_ERROR_RETURN(AParcel_readParcelFileDescriptor(parcel, &rawFd));
646 android::base::unique_fd fd(rawFd);
John Reckaca134f2022-01-18 13:23:00 -0500647 return ashmemCallback(std::move(fd), size);
John Recka18d7c82020-03-02 09:41:33 -0800648 } else {
649 // Although the above if/else was "exhaustive" guard against unknown types
650 return STATUS_UNKNOWN_ERROR;
651 }
Derek Sollenberger42c50042020-02-18 14:51:17 -0500652}
John Recka18d7c82020-03-02 09:41:33 -0800653
654static constexpr size_t BLOB_INPLACE_LIMIT = 12 * 1024;
655// Fail fast if we can't use ashmem and the size exceeds this limit - the binder transaction
656// wouldn't go through, anyway
657// TODO: Can we get this from somewhere?
658static constexpr size_t BLOB_MAX_INPLACE_LIMIT = 1 * 1024 * 1024;
659static constexpr bool shouldUseAshmem(AParcel* parcel, int32_t size) {
660 return size > BLOB_INPLACE_LIMIT && AParcel_getAllowFds(parcel);
661}
662
663static binder_status_t writeBlobFromFd(AParcel* parcel, int32_t size, int fd) {
664 binder_status_t error = STATUS_OK;
665 ON_ERROR_RETURN(AParcel_writeInt32(parcel, static_cast<int32_t>(BlobType::ASHMEM)));
666 ON_ERROR_RETURN(AParcel_writeInt32(parcel, size));
667 ON_ERROR_RETURN(AParcel_writeParcelFileDescriptor(parcel, fd));
668 return STATUS_OK;
669}
670
John Reck6a93b4f2020-04-10 17:12:00 -0700671static binder_status_t writeBlob(AParcel* parcel, const int32_t size, const void* data, bool immutable) {
John Recka18d7c82020-03-02 09:41:33 -0800672 if (size <= 0 || data == nullptr) {
673 return STATUS_NOT_ENOUGH_DATA;
674 }
675 binder_status_t error = STATUS_OK;
676 if (shouldUseAshmem(parcel, size)) {
677 // Create new ashmem region with read/write priv
678 base::unique_fd fd(ashmem_create_region("bitmap", size));
679 if (fd.get() < 0) {
680 return STATUS_NO_MEMORY;
681 }
682
683 {
684 void* dest = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd.get(), 0);
685 if (dest == MAP_FAILED) {
686 return STATUS_NO_MEMORY;
687 }
688 memcpy(dest, data, size);
689 munmap(dest, size);
690 }
691
John Reck6a93b4f2020-04-10 17:12:00 -0700692 if (immutable && ashmem_set_prot_region(fd.get(), PROT_READ) < 0) {
John Recka18d7c82020-03-02 09:41:33 -0800693 return STATUS_UNKNOWN_ERROR;
694 }
695 // Workaround b/149851140 in AParcel_writeParcelFileDescriptor
696 int rawFd = fd.release();
697 error = writeBlobFromFd(parcel, size, rawFd);
698 close(rawFd);
699 return error;
700 } else {
701 if (size > BLOB_MAX_INPLACE_LIMIT) {
702 return STATUS_FAILED_TRANSACTION;
703 }
704 ON_ERROR_RETURN(AParcel_writeInt32(parcel, static_cast<int32_t>(BlobType::IN_PLACE)));
705 ON_ERROR_RETURN(AParcel_writeByteArray(parcel, static_cast<const int8_t*>(data), size));
706 return STATUS_OK;
707 }
708}
709
710#undef ON_ERROR_RETURN
711
712#endif // __ANDROID__ // Layoutlib does not support parcel
Derek Sollenberger42c50042020-02-18 14:51:17 -0500713
Matt Sarett3ca39752017-05-26 10:55:38 -0400714// This is the maximum possible size because the SkColorSpace must be
715// representable (and therefore serializable) using a matrix and numerical
716// transfer function. If we allow more color space representations in the
717// framework, we may need to update this maximum size.
John Recka18d7c82020-03-02 09:41:33 -0800718static constexpr size_t kMaxColorSpaceSerializedBytes = 80;
719
John Reckaca134f2022-01-18 13:23:00 -0500720static constexpr auto BadParcelableException = "android/os/BadParcelableException";
John Recka18d7c82020-03-02 09:41:33 -0800721
722static bool validateImageInfo(const SkImageInfo& info, int32_t rowBytes) {
723 // TODO: Can we avoid making a SkBitmap for this?
724 return SkBitmap().setInfo(info, rowBytes);
725}
Matt Sarett3ca39752017-05-26 10:55:38 -0400726
Chris Craik32054b02014-05-09 13:58:56 -0700727static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100728#ifdef __ANDROID__ // Layoutlib does not support parcel
Chris Craik32054b02014-05-09 13:58:56 -0700729 if (parcel == NULL) {
John Recka18d7c82020-03-02 09:41:33 -0800730 jniThrowNullPointerException(env, "parcel cannot be null");
Chris Craik32054b02014-05-09 13:58:56 -0700731 return NULL;
732 }
733
John Recka18d7c82020-03-02 09:41:33 -0800734 ScopedParcel p(env, parcel);
Chris Craik32054b02014-05-09 13:58:56 -0700735
John Reck6a93b4f2020-04-10 17:12:00 -0700736 const bool isMutable = p.readInt32();
John Recka18d7c82020-03-02 09:41:33 -0800737 const SkColorType colorType = static_cast<SkColorType>(p.readInt32());
738 const SkAlphaType alphaType = static_cast<SkAlphaType>(p.readInt32());
Romain Guy5acc4762017-03-07 15:29:27 -0800739 sk_sp<SkColorSpace> colorSpace;
John Recka18d7c82020-03-02 09:41:33 -0800740 const auto optColorSpaceData = p.readData();
741 if (optColorSpaceData) {
742 const auto& colorSpaceData = *optColorSpaceData;
743 if (colorSpaceData->size() > kMaxColorSpaceSerializedBytes) {
Matt Sarett3ca39752017-05-26 10:55:38 -0400744 ALOGD("Bitmap_createFromParcel: Serialized SkColorSpace is larger than expected: "
John Recka18d7c82020-03-02 09:41:33 -0800745 "%zu bytes (max: %zu)\n",
746 colorSpaceData->size(), kMaxColorSpaceSerializedBytes);
Matt Sarett3ca39752017-05-26 10:55:38 -0400747 }
748
John Recka18d7c82020-03-02 09:41:33 -0800749 colorSpace = SkColorSpace::Deserialize(colorSpaceData->data(), colorSpaceData->size());
Romain Guy5acc4762017-03-07 15:29:27 -0800750 }
John Recka18d7c82020-03-02 09:41:33 -0800751 const int32_t width = p.readInt32();
752 const int32_t height = p.readInt32();
753 const int32_t rowBytes = p.readInt32();
754 const int32_t density = p.readInt32();
Chris Craik32054b02014-05-09 13:58:56 -0700755
Mike Reedb933055c2014-06-16 17:31:48 -0400756 if (kN32_SkColorType != colorType &&
Romain Guy9505a652016-12-14 09:43:50 -0800757 kRGBA_F16_SkColorType != colorType &&
Mike Reedb933055c2014-06-16 17:31:48 -0400758 kRGB_565_SkColorType != colorType &&
759 kARGB_4444_SkColorType != colorType &&
Mike Reedb933055c2014-06-16 17:31:48 -0400760 kAlpha_8_SkColorType != colorType) {
John Reckaca134f2022-01-18 13:23:00 -0500761 jniThrowExceptionFmt(env, BadParcelableException,
John Recka18d7c82020-03-02 09:41:33 -0800762 "Bitmap_createFromParcel unknown colortype: %d\n", colorType);
Chris Craik32054b02014-05-09 13:58:56 -0700763 return NULL;
764 }
765
John Recka18d7c82020-03-02 09:41:33 -0800766 auto imageInfo = SkImageInfo::Make(width, height, colorType, alphaType, colorSpace);
767 size_t allocationSize = 0;
768 if (!validateImageInfo(imageInfo, rowBytes)) {
769 jniThrowRuntimeException(env, "Received bad SkImageInfo");
Leon Scroggins IIIec419e02015-03-11 13:12:06 -0400770 return NULL;
771 }
John Recka18d7c82020-03-02 09:41:33 -0800772 if (!Bitmap::computeAllocationSize(rowBytes, height, &allocationSize)) {
John Reckaca134f2022-01-18 13:23:00 -0500773 jniThrowExceptionFmt(env, BadParcelableException,
John Recka18d7c82020-03-02 09:41:33 -0800774 "Received bad bitmap size: width=%d, height=%d, rowBytes=%d", width,
775 height, rowBytes);
Chris Craik32054b02014-05-09 13:58:56 -0700776 return NULL;
777 }
sergeyvc1c54062016-10-19 18:47:26 -0700778 sk_sp<Bitmap> nativeBitmap;
John Recka18d7c82020-03-02 09:41:33 -0800779 binder_status_t error = readBlob(
780 p.get(),
781 // In place callback
782 [&](std::unique_ptr<int8_t[]> buffer, int32_t size) {
John Reckaca134f2022-01-18 13:23:00 -0500783 if (allocationSize > size) {
784 android_errorWriteLog(0x534e4554, "213169612");
785 return STATUS_BAD_VALUE;
786 }
John Recka18d7c82020-03-02 09:41:33 -0800787 nativeBitmap = Bitmap::allocateHeapBitmap(allocationSize, imageInfo, rowBytes);
788 if (nativeBitmap) {
John Reckaca134f2022-01-18 13:23:00 -0500789 memcpy(nativeBitmap->pixels(), buffer.get(), allocationSize);
790 return STATUS_OK;
John Recka18d7c82020-03-02 09:41:33 -0800791 }
John Reckaca134f2022-01-18 13:23:00 -0500792 return STATUS_NO_MEMORY;
John Recka18d7c82020-03-02 09:41:33 -0800793 },
794 // Ashmem callback
795 [&](android::base::unique_fd fd, int32_t size) {
John Reckaca134f2022-01-18 13:23:00 -0500796 if (allocationSize > size) {
797 android_errorWriteLog(0x534e4554, "213169612");
798 return STATUS_BAD_VALUE;
799 }
John Reck6a93b4f2020-04-10 17:12:00 -0700800 int flags = PROT_READ;
801 if (isMutable) {
802 flags |= PROT_WRITE;
803 }
804 void* addr = mmap(nullptr, size, flags, MAP_SHARED, fd.get(), 0);
John Recka18d7c82020-03-02 09:41:33 -0800805 if (addr == MAP_FAILED) {
John Reck6a93b4f2020-04-10 17:12:00 -0700806 const int err = errno;
807 ALOGW("mmap failed, error %d (%s)", err, strerror(err));
John Reckaca134f2022-01-18 13:23:00 -0500808 return STATUS_NO_MEMORY;
John Recka18d7c82020-03-02 09:41:33 -0800809 }
810 nativeBitmap =
John Reck6a93b4f2020-04-10 17:12:00 -0700811 Bitmap::createFrom(imageInfo, rowBytes, fd.release(), addr, size, !isMutable);
John Reckaca134f2022-01-18 13:23:00 -0500812 return STATUS_OK;
John Recka18d7c82020-03-02 09:41:33 -0800813 });
John Reckaca134f2022-01-18 13:23:00 -0500814
815 if (error != STATUS_OK && error != STATUS_NO_MEMORY) {
John Recka18d7c82020-03-02 09:41:33 -0800816 // TODO: Stringify the error, see signalExceptionForError in android_util_Binder.cpp
John Reckaca134f2022-01-18 13:23:00 -0500817 jniThrowExceptionFmt(env, BadParcelableException, "Failed to read from Parcel, error=%d",
818 error);
John Recka18d7c82020-03-02 09:41:33 -0800819 return nullptr;
820 }
John Reckaca134f2022-01-18 13:23:00 -0500821 if (error == STATUS_NO_MEMORY || !nativeBitmap) {
822 jniThrowRuntimeException(env, "Could not allocate bitmap data.");
John Recka18d7c82020-03-02 09:41:33 -0800823 return nullptr;
Chris Craik32054b02014-05-09 13:58:56 -0700824 }
Chris Craik32054b02014-05-09 13:58:56 -0700825
John Reck6a93b4f2020-04-10 17:12:00 -0700826 return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable), nullptr,
John Recka18d7c82020-03-02 09:41:33 -0800827 nullptr, density);
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100828#else
John Recka18d7c82020-03-02 09:41:33 -0800829 jniThrowRuntimeException(env, "Cannot use parcels outside of Android");
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100830 return NULL;
831#endif
Chris Craik32054b02014-05-09 13:58:56 -0700832}
833
834static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
John Reckefac0522020-01-24 16:04:26 -0800835 jlong bitmapHandle, jint density, jobject parcel) {
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100836#ifdef __ANDROID__ // Layoutlib does not support parcel
Chris Craik32054b02014-05-09 13:58:56 -0700837 if (parcel == NULL) {
Sally Qi7e3f93b2021-07-15 00:00:54 +0000838 ALOGD("------- writeToParcel null parcel\n");
Chris Craik32054b02014-05-09 13:58:56 -0700839 return JNI_FALSE;
840 }
841
John Recka18d7c82020-03-02 09:41:33 -0800842 ScopedParcel p(env, parcel);
John Reckf29ed282015-04-07 07:32:03 -0700843 SkBitmap bitmap;
Riley Andrews39d7f302014-11-13 17:43:25 -0800844
sergeyvc1c54062016-10-19 18:47:26 -0700845 auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle);
846 bitmapWrapper->getSkBitmap(&bitmap);
Chris Craik32054b02014-05-09 13:58:56 -0700847
John Reck6a93b4f2020-04-10 17:12:00 -0700848 p.writeInt32(!bitmap.isImmutable());
John Recka18d7c82020-03-02 09:41:33 -0800849 p.writeInt32(bitmap.colorType());
850 p.writeInt32(bitmap.alphaType());
Romain Guy5acc4762017-03-07 15:29:27 -0800851 SkColorSpace* colorSpace = bitmap.colorSpace();
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500852 if (colorSpace != nullptr) {
John Recka18d7c82020-03-02 09:41:33 -0800853 p.writeData(colorSpace->serialize());
Romain Guy5acc4762017-03-07 15:29:27 -0800854 } else {
John Recka18d7c82020-03-02 09:41:33 -0800855 p.writeData(std::nullopt);
Romain Guy5acc4762017-03-07 15:29:27 -0800856 }
John Recka18d7c82020-03-02 09:41:33 -0800857 p.writeInt32(bitmap.width());
858 p.writeInt32(bitmap.height());
859 p.writeInt32(bitmap.rowBytes());
860 p.writeInt32(density);
Chris Craik32054b02014-05-09 13:58:56 -0700861
Jeff Browna316c5d2015-06-05 15:14:06 -0700862 // Transfer the underlying ashmem region if we have one and it's immutable.
John Recka18d7c82020-03-02 09:41:33 -0800863 binder_status_t status;
sergeyvaed7f582016-10-14 16:30:21 -0700864 int fd = bitmapWrapper->bitmap().getAshmemFd();
John Reck6a93b4f2020-04-10 17:12:00 -0700865 if (fd >= 0 && p.allowFds() && bitmap.isImmutable()) {
Jeff Browna316c5d2015-06-05 15:14:06 -0700866#if DEBUG_PARCEL
867 ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as "
John Recka18d7c82020-03-02 09:41:33 -0800868 "immutable blob (fds %s)",
869 p.allowFds() ? "allowed" : "forbidden");
Jeff Browna316c5d2015-06-05 15:14:06 -0700870#endif
871
John Recka18d7c82020-03-02 09:41:33 -0800872 status = writeBlobFromFd(p.get(), bitmapWrapper->bitmap().getAllocationByteCount(), fd);
873 if (status != STATUS_OK) {
Jeff Browna316c5d2015-06-05 15:14:06 -0700874 doThrowRE(env, "Could not write bitmap blob file descriptor.");
Riley Andrews39d7f302014-11-13 17:43:25 -0800875 return JNI_FALSE;
876 }
Jeff Browna316c5d2015-06-05 15:14:06 -0700877 return JNI_TRUE;
Riley Andrews39d7f302014-11-13 17:43:25 -0800878 }
Jeff Browna316c5d2015-06-05 15:14:06 -0700879
880 // Copy the bitmap to a new blob.
Jeff Browna316c5d2015-06-05 15:14:06 -0700881#if DEBUG_PARCEL
John Reckefac0522020-01-24 16:04:26 -0800882 ALOGD("Bitmap.writeToParcel: copying bitmap into new blob (fds %s)",
John Recka18d7c82020-03-02 09:41:33 -0800883 p.allowFds() ? "allowed" : "forbidden");
Jeff Browna316c5d2015-06-05 15:14:06 -0700884#endif
885
Mike Reed7569de02017-10-06 16:25:49 -0400886 size_t size = bitmap.computeByteSize();
John Reck6a93b4f2020-04-10 17:12:00 -0700887 status = writeBlob(p.get(), size, bitmap.getPixels(), bitmap.isImmutable());
Jeff Browna316c5d2015-06-05 15:14:06 -0700888 if (status) {
889 doThrowRE(env, "Could not copy bitmap to parcel blob.");
890 return JNI_FALSE;
891 }
Chris Craik32054b02014-05-09 13:58:56 -0700892 return JNI_TRUE;
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +0100893#else
894 doThrowRE(env, "Cannot use parcels outside of Android");
895 return JNI_FALSE;
896#endif
Chris Craik32054b02014-05-09 13:58:56 -0700897}
898
899static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
900 jlong srcHandle, jlong paintHandle,
901 jintArray offsetXY) {
John Reckf29ed282015-04-07 07:32:03 -0700902 SkBitmap src;
sergeyvc1c54062016-10-19 18:47:26 -0700903 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400904 const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700905 SkIPoint offset;
John Reckf29ed282015-04-07 07:32:03 -0700906 SkBitmap dst;
sergeyv45082182016-09-29 18:25:40 -0700907 HeapAllocator allocator;
Chris Craik32054b02014-05-09 13:58:56 -0700908
John Reckf29ed282015-04-07 07:32:03 -0700909 src.extractAlpha(&dst, paint, &allocator, &offset);
Chris Craik32054b02014-05-09 13:58:56 -0700910 // If Skia can't allocate pixels for destination bitmap, it resets
911 // it, that is set its pixels buffer to NULL, and zero width and height.
John Reckf29ed282015-04-07 07:32:03 -0700912 if (dst.getPixels() == NULL && src.getPixels() != NULL) {
Chris Craik32054b02014-05-09 13:58:56 -0700913 doThrowOOME(env, "failed to allocate pixels for alpha");
914 return NULL;
915 }
916 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
917 int* array = env->GetIntArrayElements(offsetXY, NULL);
918 array[0] = offset.fX;
919 array[1] = offset.fY;
920 env->ReleaseIntArrayElements(offsetXY, array, 0);
921 }
922
sergeyvc69853c2016-10-07 14:14:09 -0700923 return createBitmap(env, allocator.getStorageObjAndReset(),
John Reckf29ed282015-04-07 07:32:03 -0700924 getPremulBitmapCreateFlags(true));
Chris Craik32054b02014-05-09 13:58:56 -0700925}
926
927///////////////////////////////////////////////////////////////////////////////
928
Romain Guyefb4b062017-02-27 11:00:04 -0800929static jboolean Bitmap_isSRGB(JNIEnv* env, jobject, jlong bitmapHandle) {
930 LocalScopedBitmap bitmapHolder(bitmapHandle);
931 if (!bitmapHolder.valid()) return JNI_TRUE;
932
933 SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
Brian Osman91c9c282018-08-17 16:57:15 -0400934 return colorSpace == nullptr || colorSpace->isSRGB();
Romain Guyefb4b062017-02-27 11:00:04 -0800935}
936
Leon Scroggins IIIce89a6e2018-03-13 15:39:39 -0400937static jboolean Bitmap_isSRGBLinear(JNIEnv* env, jobject, jlong bitmapHandle) {
938 LocalScopedBitmap bitmapHolder(bitmapHandle);
939 if (!bitmapHolder.valid()) return JNI_FALSE;
940
941 SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
942 sk_sp<SkColorSpace> srgbLinear = SkColorSpace::MakeSRGBLinear();
943 return colorSpace == srgbLinear.get() ? JNI_TRUE : JNI_FALSE;
944}
945
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500946static jobject Bitmap_computeColorSpace(JNIEnv* env, jobject, jlong bitmapHandle) {
Romain Guyefb4b062017-02-27 11:00:04 -0800947 LocalScopedBitmap bitmapHolder(bitmapHandle);
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500948 if (!bitmapHolder.valid()) return nullptr;
Romain Guyefb4b062017-02-27 11:00:04 -0800949
950 SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500951 if (colorSpace == nullptr) return nullptr;
Romain Guyefb4b062017-02-27 11:00:04 -0800952
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500953 return GraphicsJNI::getColorSpace(env, colorSpace, bitmapHolder->info().colorType());
Romain Guyefb4b062017-02-27 11:00:04 -0800954}
955
Derek Sollenberger202084c2019-01-14 13:55:08 -0500956static void Bitmap_setColorSpace(JNIEnv* env, jobject, jlong bitmapHandle, jlong colorSpacePtr) {
957 LocalScopedBitmap bitmapHolder(bitmapHandle);
958 sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(colorSpacePtr);
959 bitmapHolder->setColorSpace(cs);
960}
961
Romain Guyefb4b062017-02-27 11:00:04 -0800962///////////////////////////////////////////////////////////////////////////////
963
Chris Craik32054b02014-05-09 13:58:56 -0700964static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400965 jint x, jint y) {
John Reckf29ed282015-04-07 07:32:03 -0700966 SkBitmap bitmap;
sergeyvc1c54062016-10-19 18:47:26 -0700967 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
Chris Craik32054b02014-05-09 13:58:56 -0700968
Brian Osman91c9c282018-08-17 16:57:15 -0400969 auto sRGB = SkColorSpace::MakeSRGB();
970 SkImageInfo dstInfo = SkImageInfo::Make(
971 1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
Chris Craik32054b02014-05-09 13:58:56 -0700972
Brian Osman91c9c282018-08-17 16:57:15 -0400973 SkColor dst;
974 bitmap.readPixels(dstInfo, &dst, dstInfo.minRowBytes(), x, y);
975 return static_cast<jint>(dst);
Chris Craik32054b02014-05-09 13:58:56 -0700976}
977
Leon Scroggins III870053d2019-01-24 08:37:27 -0500978static jlong Bitmap_getColor(JNIEnv* env, jobject, jlong bitmapHandle,
979 jint x, jint y) {
980 SkBitmap bitmap;
981 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
982
983 SkImageInfo dstInfo = SkImageInfo::Make(
984 1, 1, kRGBA_F16_SkColorType, kUnpremul_SkAlphaType, bitmap.refColorSpace());
985
986 uint64_t dst;
987 bitmap.readPixels(dstInfo, &dst, dstInfo.minRowBytes(), x, y);
988 return static_cast<jlong>(dst);
989}
990
Chris Craik32054b02014-05-09 13:58:56 -0700991static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,
992 jintArray pixelArray, jint offset, jint stride,
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400993 jint x, jint y, jint width, jint height) {
John Reckf29ed282015-04-07 07:32:03 -0700994 SkBitmap bitmap;
sergeyvc1c54062016-10-19 18:47:26 -0700995 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
Chris Craik32054b02014-05-09 13:58:56 -0700996
Brian Osman91c9c282018-08-17 16:57:15 -0400997 auto sRGB = SkColorSpace::MakeSRGB();
998 SkImageInfo dstInfo = SkImageInfo::Make(
999 width, height, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
Chris Craik32054b02014-05-09 13:58:56 -07001000
Chris Craik32054b02014-05-09 13:58:56 -07001001 jint* dst = env->GetIntArrayElements(pixelArray, NULL);
Brian Osman91c9c282018-08-17 16:57:15 -04001002 bitmap.readPixels(dstInfo, dst + offset, stride * 4, x, y);
Chris Craik32054b02014-05-09 13:58:56 -07001003 env->ReleaseIntArrayElements(pixelArray, dst, 0);
1004}
1005
1006///////////////////////////////////////////////////////////////////////////////
1007
1008static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle,
Leon Scroggins III57ee6202014-06-04 18:51:07 -04001009 jint x, jint y, jint colorHandle) {
John Reckf29ed282015-04-07 07:32:03 -07001010 SkBitmap bitmap;
sergeyvc1c54062016-10-19 18:47:26 -07001011 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001012 SkColor color = static_cast<SkColor>(colorHandle);
Chris Craik32054b02014-05-09 13:58:56 -07001013
Brian Osman91c9c282018-08-17 16:57:15 -04001014 auto sRGB = SkColorSpace::MakeSRGB();
1015 SkImageInfo srcInfo = SkImageInfo::Make(
1016 1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType, sRGB);
1017 SkPixmap srcPM(srcInfo, &color, srcInfo.minRowBytes());
Chris Craik32054b02014-05-09 13:58:56 -07001018
Brian Osman91c9c282018-08-17 16:57:15 -04001019 bitmap.writePixels(srcPM, x, y);
Chris Craik32054b02014-05-09 13:58:56 -07001020}
1021
1022static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,
1023 jintArray pixelArray, jint offset, jint stride,
Leon Scroggins III57ee6202014-06-04 18:51:07 -04001024 jint x, jint y, jint width, jint height) {
John Reckf29ed282015-04-07 07:32:03 -07001025 SkBitmap bitmap;
sergeyvc1c54062016-10-19 18:47:26 -07001026 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001027 GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
Brian Osman91c9c282018-08-17 16:57:15 -04001028 x, y, width, height, &bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001029}
1030
1031static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
1032 jlong bitmapHandle, jobject jbuffer) {
John Reckf29ed282015-04-07 07:32:03 -07001033 SkBitmap bitmap;
sergeyvc1c54062016-10-19 18:47:26 -07001034 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
John Reckf29ed282015-04-07 07:32:03 -07001035 const void* src = bitmap.getPixels();
Chris Craik32054b02014-05-09 13:58:56 -07001036
1037 if (NULL != src) {
1038 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
1039
1040 // the java side has already checked that buffer is large enough
Mike Reed7569de02017-10-06 16:25:49 -04001041 memcpy(abp.pointer(), src, bitmap.computeByteSize());
Chris Craik32054b02014-05-09 13:58:56 -07001042 }
1043}
1044
1045static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,
1046 jlong bitmapHandle, jobject jbuffer) {
John Reckf29ed282015-04-07 07:32:03 -07001047 SkBitmap bitmap;
sergeyvc1c54062016-10-19 18:47:26 -07001048 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
John Reckf29ed282015-04-07 07:32:03 -07001049 void* dst = bitmap.getPixels();
Chris Craik32054b02014-05-09 13:58:56 -07001050
1051 if (NULL != dst) {
1052 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);
1053 // the java side has already checked that buffer is large enough
Mike Reed7569de02017-10-06 16:25:49 -04001054 memcpy(dst, abp.pointer(), bitmap.computeByteSize());
John Reckf29ed282015-04-07 07:32:03 -07001055 bitmap.notifyPixelsChanged();
Chris Craik32054b02014-05-09 13:58:56 -07001056 }
1057}
1058
Chris Craik795bd0f2016-12-16 15:22:31 -08001059static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle, jlong bm1Handle) {
John Reckf29ed282015-04-07 07:32:03 -07001060 SkBitmap bm0;
1061 SkBitmap bm1;
sergeyv1eabed32016-12-14 14:19:47 -08001062
1063 LocalScopedBitmap bitmap0(bm0Handle);
1064 LocalScopedBitmap bitmap1(bm1Handle);
1065
1066 // Paying the price for making Hardware Bitmap as Config:
1067 // later check for colorType will pass successfully,
1068 // because Hardware Config internally may be RGBA8888 or smth like that.
sergeyv15a10852016-12-27 14:32:03 -08001069 if (bitmap0->isHardware() != bitmap1->isHardware()) {
sergeyv1eabed32016-12-14 14:19:47 -08001070 return JNI_FALSE;
1071 }
1072
1073 bitmap0->bitmap().getSkBitmap(&bm0);
1074 bitmap1->bitmap().getSkBitmap(&bm1);
Chris Craik795bd0f2016-12-16 15:22:31 -08001075 if (bm0.width() != bm1.width()
1076 || bm0.height() != bm1.height()
1077 || bm0.colorType() != bm1.colorType()
1078 || bm0.alphaType() != bm1.alphaType()
1079 || !SkColorSpace::Equals(bm0.colorSpace(), bm1.colorSpace())) {
Chris Craik32054b02014-05-09 13:58:56 -07001080 return JNI_FALSE;
1081 }
1082
Chris Craik32054b02014-05-09 13:58:56 -07001083 // if we can't load the pixels, return false
John Reckf29ed282015-04-07 07:32:03 -07001084 if (NULL == bm0.getPixels() || NULL == bm1.getPixels()) {
Chris Craik32054b02014-05-09 13:58:56 -07001085 return JNI_FALSE;
1086 }
1087
Chris Craik32054b02014-05-09 13:58:56 -07001088 // now compare each scanline. We can't do the entire buffer at once,
1089 // since we don't care about the pixel values that might extend beyond
1090 // the width (since the scanline might be larger than the logical width)
John Reckf29ed282015-04-07 07:32:03 -07001091 const int h = bm0.height();
1092 const size_t size = bm0.width() * bm0.bytesPerPixel();
Chris Craik32054b02014-05-09 13:58:56 -07001093 for (int y = 0; y < h; y++) {
henry.uh_chen53001ca2014-07-03 20:40:22 +08001094 // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config
1095 // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0
1096 // and bm1 both have pixel data() (have passed NULL == getPixels() check),
1097 // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE
1098 // to warn user those 2 unrecognized config bitmaps may be different.
John Reckf29ed282015-04-07 07:32:03 -07001099 void *bm0Addr = bm0.getAddr(0, y);
1100 void *bm1Addr = bm1.getAddr(0, y);
henry.uh_chen53001ca2014-07-03 20:40:22 +08001101
1102 if(bm0Addr == NULL || bm1Addr == NULL) {
1103 return JNI_FALSE;
1104 }
1105
1106 if (memcmp(bm0Addr, bm1Addr, size) != 0) {
Chris Craik32054b02014-05-09 13:58:56 -07001107 return JNI_FALSE;
1108 }
1109 }
1110 return JNI_TRUE;
1111}
1112
John Reck43871902016-08-01 14:39:24 -07001113static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapPtr) {
1114 LocalScopedBitmap bitmapHandle(bitmapPtr);
1115 if (!bitmapHandle.valid()) return;
sergeyvec4a4b12016-10-20 18:39:04 -07001116 android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmapHandle->bitmap());
John Reck43871902016-08-01 14:39:24 -07001117}
1118
sergeyv45082182016-09-29 18:25:40 -07001119static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr) {
1120 LocalScopedBitmap bitmapHandle(bitmapPtr);
1121 return static_cast<jint>(bitmapHandle->getAllocationByteCount());
1122}
1123
sergeyv6e3658a2017-01-04 16:57:51 -08001124static jobject Bitmap_copyPreserveInternalConfig(JNIEnv* env, jobject, jlong bitmapPtr) {
sergeyv81f97ee2016-12-27 18:08:01 -08001125 LocalScopedBitmap bitmapHandle(bitmapPtr);
1126 LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
1127 "Hardware config is only supported config in Bitmap_nativeCopyPreserveInternalConfig");
1128 Bitmap& hwuiBitmap = bitmapHandle->bitmap();
1129 SkBitmap src;
1130 hwuiBitmap.getSkBitmap(&src);
1131
Derek Sollenbergere2169482018-11-20 10:57:20 -05001132 if (src.pixelRef() == nullptr) {
sergeyv81f97ee2016-12-27 18:08:01 -08001133 doThrowRE(env, "Could not copy a hardware bitmap.");
1134 return NULL;
1135 }
Derek Sollenbergere2169482018-11-20 10:57:20 -05001136
1137 sk_sp<Bitmap> bitmap = Bitmap::createFrom(src.info(), *src.pixelRef());
1138 return createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false));
sergeyv81f97ee2016-12-27 18:08:01 -08001139}
1140
rennb2e9f522018-09-26 10:49:00 -07001141static jobject Bitmap_wrapHardwareBufferBitmap(JNIEnv* env, jobject, jobject hardwareBuffer,
Leon Scroggins III0e443d12018-12-19 11:38:35 -05001142 jlong colorSpacePtr) {
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +01001143#ifdef __ANDROID__ // Layoutlib does not support graphic buffer
Nader Jawada3521852023-01-30 20:23:46 -08001144 AHardwareBuffer* buffer = uirenderer::HardwareBufferHelpers::AHardwareBuffer_fromHardwareBuffer(
1145 env, hardwareBuffer);
Derek Sollenbergere78f7c92019-07-31 15:18:47 -04001146 sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer,
1147 GraphicsJNI::getNativeColorSpace(colorSpacePtr));
rennb2e9f522018-09-26 10:49:00 -07001148 if (!bitmap.get()) {
1149 ALOGW("failed to create hardware bitmap from hardware buffer");
1150 return NULL;
1151 }
1152 return bitmap::createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false));
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +01001153#else
1154 return NULL;
1155#endif
rennb2e9f522018-09-26 10:49:00 -07001156}
1157
Leon Scroggins III5a190b12020-02-18 13:52:18 -05001158static jobject Bitmap_getHardwareBuffer(JNIEnv* env, jobject, jlong bitmapPtr) {
1159#ifdef __ANDROID__ // Layoutlib does not support graphic buffer
1160 LocalScopedBitmap bitmapHandle(bitmapPtr);
Leon Scroggins IIIa72a7ff2020-02-28 15:41:56 -05001161 if (!bitmapHandle->isHardware()) {
1162 jniThrowException(env, "java/lang/IllegalStateException",
Leon Scroggins III5a190b12020-02-18 13:52:18 -05001163 "Hardware config is only supported config in Bitmap_getHardwareBuffer");
Leon Scroggins IIIa72a7ff2020-02-28 15:41:56 -05001164 return nullptr;
1165 }
Leon Scroggins III5a190b12020-02-18 13:52:18 -05001166
1167 Bitmap& bitmap = bitmapHandle->bitmap();
Nader Jawada3521852023-01-30 20:23:46 -08001168 return uirenderer::HardwareBufferHelpers::AHardwareBuffer_toHardwareBuffer(
1169 env, bitmap.hardwareBuffer());
Leon Scroggins III5a190b12020-02-18 13:52:18 -05001170#else
Leon Scroggins IIIa72a7ff2020-02-28 15:41:56 -05001171 return nullptr;
Leon Scroggins III5a190b12020-02-18 13:52:18 -05001172#endif
1173}
1174
Jerome Gaillard21e7e2d2019-05-14 14:34:46 +01001175static jboolean Bitmap_isImmutable(CRITICAL_JNI_PARAMS_COMMA jlong bitmapHandle) {
Nader Jawade7b51292018-04-12 17:55:31 -07001176 LocalScopedBitmap bitmapHolder(bitmapHandle);
1177 if (!bitmapHolder.valid()) return JNI_FALSE;
1178
1179 return bitmapHolder->bitmap().isImmutable() ? JNI_TRUE : JNI_FALSE;
1180}
1181
Leon Scroggins III3eb98432020-03-11 15:38:12 -04001182static jboolean Bitmap_isBackedByAshmem(CRITICAL_JNI_PARAMS_COMMA jlong bitmapHandle) {
1183 LocalScopedBitmap bitmapHolder(bitmapHandle);
1184 if (!bitmapHolder.valid()) return JNI_FALSE;
1185
1186 return bitmapHolder->bitmap().pixelStorageType() == PixelStorageType::Ashmem ? JNI_TRUE
1187 : JNI_FALSE;
1188}
1189
Nader Jawade7b51292018-04-12 17:55:31 -07001190static void Bitmap_setImmutable(JNIEnv* env, jobject, jlong bitmapHandle) {
1191 LocalScopedBitmap bitmapHolder(bitmapHandle);
1192 if (!bitmapHolder.valid()) return;
1193
1194 return bitmapHolder->bitmap().setImmutable();
1195}
1196
John Reck5bd537e2023-01-24 20:13:45 -05001197static jboolean Bitmap_hasGainmap(CRITICAL_JNI_PARAMS_COMMA jlong bitmapHandle) {
1198 LocalScopedBitmap bitmapHolder(bitmapHandle);
1199 if (!bitmapHolder.valid()) return false;
1200
1201 return bitmapHolder->bitmap().hasGainmap();
1202}
1203
1204static jobject Bitmap_extractGainmap(JNIEnv* env, jobject, jlong bitmapHandle) {
1205 LocalScopedBitmap bitmapHolder(bitmapHandle);
1206 if (!bitmapHolder.valid()) return nullptr;
1207 if (!bitmapHolder->bitmap().hasGainmap()) return nullptr;
1208
1209 return Gainmap_extractFromBitmap(env, bitmapHolder->bitmap());
1210}
1211
John Reck3e98bce2023-02-07 13:38:28 -05001212static void Bitmap_setGainmap(JNIEnv*, jobject, jlong bitmapHandle, jlong gainmapPtr) {
1213 LocalScopedBitmap bitmapHolder(bitmapHandle);
1214 if (!bitmapHolder.valid()) return;
1215 uirenderer::Gainmap* gainmap = reinterpret_cast<uirenderer::Gainmap*>(gainmapPtr);
1216 bitmapHolder->bitmap().setGainmap(sp<uirenderer::Gainmap>::fromExisting(gainmap));
1217}
1218
Chris Craik32054b02014-05-09 13:58:56 -07001219///////////////////////////////////////////////////////////////////////////////
1220
Daniel Micay76f6a862015-09-19 17:31:01 -04001221static const JNINativeMethod gBitmapMethods[] = {
John Reck5bd537e2023-01-24 20:13:45 -05001222 {"nativeCreate", "([IIIIIIZJ)Landroid/graphics/Bitmap;", (void*)Bitmap_creator},
1223 {"nativeCopy", "(JIZ)Landroid/graphics/Bitmap;", (void*)Bitmap_copy},
1224 {"nativeCopyAshmem", "(J)Landroid/graphics/Bitmap;", (void*)Bitmap_copyAshmem},
1225 {"nativeCopyAshmemConfig", "(JI)Landroid/graphics/Bitmap;", (void*)Bitmap_copyAshmemConfig},
1226 {"nativeGetAshmemFD", "(J)I", (void*)Bitmap_getAshmemFd},
1227 {"nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer},
1228 {"nativeRecycle", "(J)V", (void*)Bitmap_recycle},
1229 {"nativeReconfigure", "(JIIIZ)V", (void*)Bitmap_reconfigure},
1230 {"nativeCompress", "(JIILjava/io/OutputStream;[B)Z", (void*)Bitmap_compress},
1231 {"nativeErase", "(JI)V", (void*)Bitmap_erase},
1232 {"nativeErase", "(JJJ)V", (void*)Bitmap_eraseLong},
1233 {"nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes},
1234 {"nativeConfig", "(J)I", (void*)Bitmap_config},
1235 {"nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha},
1236 {"nativeIsPremultiplied", "(J)Z", (void*)Bitmap_isPremultiplied},
1237 {"nativeSetHasAlpha", "(JZZ)V", (void*)Bitmap_setHasAlpha},
1238 {"nativeSetPremultiplied", "(JZ)V", (void*)Bitmap_setPremultiplied},
1239 {"nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap},
1240 {"nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap},
1241 {"nativeCreateFromParcel", "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
1242 (void*)Bitmap_createFromParcel},
1243 {"nativeWriteToParcel", "(JILandroid/os/Parcel;)Z", (void*)Bitmap_writeToParcel},
1244 {"nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;", (void*)Bitmap_extractAlpha},
1245 {"nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId},
1246 {"nativeGetPixel", "(JII)I", (void*)Bitmap_getPixel},
1247 {"nativeGetColor", "(JII)J", (void*)Bitmap_getColor},
1248 {"nativeGetPixels", "(J[IIIIIII)V", (void*)Bitmap_getPixels},
1249 {"nativeSetPixel", "(JIII)V", (void*)Bitmap_setPixel},
1250 {"nativeSetPixels", "(J[IIIIIII)V", (void*)Bitmap_setPixels},
1251 {"nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V", (void*)Bitmap_copyPixelsToBuffer},
1252 {"nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V", (void*)Bitmap_copyPixelsFromBuffer},
1253 {"nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs},
1254 {"nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw},
1255 {"nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount},
1256 {"nativeCopyPreserveInternalConfig", "(J)Landroid/graphics/Bitmap;",
1257 (void*)Bitmap_copyPreserveInternalConfig},
1258 {"nativeWrapHardwareBufferBitmap",
1259 "(Landroid/hardware/HardwareBuffer;J)Landroid/graphics/Bitmap;",
1260 (void*)Bitmap_wrapHardwareBufferBitmap},
1261 {"nativeGetHardwareBuffer", "(J)Landroid/hardware/HardwareBuffer;",
1262 (void*)Bitmap_getHardwareBuffer},
1263 {"nativeComputeColorSpace", "(J)Landroid/graphics/ColorSpace;",
1264 (void*)Bitmap_computeColorSpace},
1265 {"nativeSetColorSpace", "(JJ)V", (void*)Bitmap_setColorSpace},
1266 {"nativeIsSRGB", "(J)Z", (void*)Bitmap_isSRGB},
1267 {"nativeIsSRGBLinear", "(J)Z", (void*)Bitmap_isSRGBLinear},
1268 {"nativeSetImmutable", "(J)V", (void*)Bitmap_setImmutable},
1269 {"nativeExtractGainmap", "(J)Landroid/graphics/Gainmap;", (void*)Bitmap_extractGainmap},
John Reck3e98bce2023-02-07 13:38:28 -05001270 {"nativeSetGainmap", "(JJ)V", (void*)Bitmap_setGainmap},
Nader Jawade7b51292018-04-12 17:55:31 -07001271
John Reck5bd537e2023-01-24 20:13:45 -05001272 // ------------ @CriticalNative ----------------
1273 {"nativeIsImmutable", "(J)Z", (void*)Bitmap_isImmutable},
1274 {"nativeIsBackedByAshmem", "(J)Z", (void*)Bitmap_isBackedByAshmem},
1275 {"nativeHasGainmap", "(J)Z", (void*)Bitmap_hasGainmap},
Nader Jawade7b51292018-04-12 17:55:31 -07001276
Chris Craik32054b02014-05-09 13:58:56 -07001277};
1278
Chris Craik32054b02014-05-09 13:58:56 -07001279int register_android_graphics_Bitmap(JNIEnv* env)
1280{
Romain Guy95648b82017-04-13 18:43:42 -07001281 gBitmap_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Bitmap"));
Nader Jawada3521852023-01-30 20:23:46 -08001282 uirenderer::HardwareBufferHelpers::init();
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001283 return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods,
1284 NELEM(gBitmapMethods));
John Reck9192d5e2016-10-31 10:32:09 -07001285}