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