blob: 6419aa43dd4e2642697b3c45e7365eee9273f461 [file] [log] [blame]
John Reckf29ed282015-04-07 07:32:03 -07001#define LOG_TAG "Bitmap"
John Reckf29ed282015-04-07 07:32:03 -07002#include "Bitmap.h"
3
Chris Craik32054b02014-05-09 13:58:56 -07004#include "SkBitmap.h"
5#include "SkPixelRef.h"
6#include "SkImageEncoder.h"
Leon Scroggins III57ee6202014-06-04 18:51:07 -04007#include "SkImageInfo.h"
Chris Craik32054b02014-05-09 13:58:56 -07008#include "SkColorPriv.h"
9#include "GraphicsJNI.h"
10#include "SkDither.h"
11#include "SkUnPreMultiply.h"
12#include "SkStream.h"
13
14#include <binder/Parcel.h>
15#include "android_os_Parcel.h"
16#include "android_util_Binder.h"
17#include "android_nio_utils.h"
18#include "CreateJavaOutputStreamAdaptor.h"
sergeyvdccca442016-03-21 15:38:21 -070019#include <hwui/Paint.h>
sergeyvc1c54062016-10-19 18:47:26 -070020#include <hwui/Bitmap.h>
John Reck43871902016-08-01 14:39:24 -070021#include <renderthread/RenderProxy.h>
Chris Craik32054b02014-05-09 13:58:56 -070022
Andreas Gampeed6b9df2014-11-20 22:02:20 -080023#include "core_jni_helpers.h"
24
Chris Craik32054b02014-05-09 13:58:56 -070025#include <jni.h>
Riley Andrews39d7f302014-11-13 17:43:25 -080026#include <memory>
27#include <string>
Chris Craik32054b02014-05-09 13:58:56 -070028
Jeff Browna316c5d2015-06-05 15:14:06 -070029#define DEBUG_PARCEL 0
Riley Andrews8cee7c12015-11-01 23:36:04 -080030#define ASHMEM_BITMAP_MIN_SIZE (128 * (1 << 10))
Jeff Browna316c5d2015-06-05 15:14:06 -070031
sergeyvc69853c2016-10-07 14:14:09 -070032static jclass gBitmap_class;
33static jfieldID gBitmap_nativePtr;
34static jmethodID gBitmap_constructorMethodID;
35static jmethodID gBitmap_reinitMethodID;
36static jmethodID gBitmap_getAllocationByteCountMethodID;
37
John Reckf29ed282015-04-07 07:32:03 -070038namespace android {
39
sergeyvc1c54062016-10-19 18:47:26 -070040class BitmapWrapper {
John Reckf29ed282015-04-07 07:32:03 -070041public:
sergeyvc1c54062016-10-19 18:47:26 -070042 BitmapWrapper(Bitmap* bitmap)
43 : mBitmap(bitmap) { }
sergeyvc69853c2016-10-07 14:14:09 -070044
45 void freePixels() {
sergeyvc1c54062016-10-19 18:47:26 -070046 mInfo = mBitmap->info();
47 mHasHardwareMipMap = mBitmap->hasHardwareMipMap();
48 mAllocationSize = mBitmap->getAllocationByteCount();
49 mRowBytes = mBitmap->rowBytes();
50 mGenerationId = mBitmap->getGenerationID();
51 mBitmap.reset();
John Reckf29ed282015-04-07 07:32:03 -070052 }
53
sergeyvc69853c2016-10-07 14:14:09 -070054 bool valid() {
sergeyvc1c54062016-10-19 18:47:26 -070055 return !!mBitmap;
John Reckf29ed282015-04-07 07:32:03 -070056 }
57
sergeyvaed7f582016-10-14 16:30:21 -070058 Bitmap& bitmap() {
59 assertValid();
60 return *mBitmap;
61 }
sergeyvc69853c2016-10-07 14:14:09 -070062
63 void assertValid() {
64 LOG_ALWAYS_FATAL_IF(!valid(), "Error, cannot access an invalid/free'd bitmap here!");
65 }
66
67 void getSkBitmap(SkBitmap* outBitmap) {
68 assertValid();
sergeyvc1c54062016-10-19 18:47:26 -070069 mBitmap->getSkBitmap(outBitmap);
sergeyvc69853c2016-10-07 14:14:09 -070070 }
71
72 bool hasHardwareMipMap() {
sergeyvc1c54062016-10-19 18:47:26 -070073 if (mBitmap) {
74 return mBitmap->hasHardwareMipMap();
John Reckf29ed282015-04-07 07:32:03 -070075 }
John Reckf29ed282015-04-07 07:32:03 -070076 return mHasHardwareMipMap;
77 }
78
79 void setHasHardwareMipMap(bool hasMipMap) {
sergeyvc69853c2016-10-07 14:14:09 -070080 assertValid();
sergeyvc1c54062016-10-19 18:47:26 -070081 mBitmap->setHasHardwareMipMap(hasMipMap);
John Reckf29ed282015-04-07 07:32:03 -070082 }
83
sergeyvc69853c2016-10-07 14:14:09 -070084 void setAlphaType(SkAlphaType alphaType) {
85 assertValid();
sergeyvc1c54062016-10-19 18:47:26 -070086 mBitmap->setAlphaType(alphaType);
John Reckf29ed282015-04-07 07:32:03 -070087 }
88
sergeyvc69853c2016-10-07 14:14:09 -070089 const SkImageInfo& info() {
sergeyvc1c54062016-10-19 18:47:26 -070090 if (mBitmap) {
91 return mBitmap->info();
sergeyvc69853c2016-10-07 14:14:09 -070092 }
93 return mInfo;
John Reckf29ed282015-04-07 07:32:03 -070094 }
95
sergeyvc69853c2016-10-07 14:14:09 -070096 size_t getAllocationByteCount() const {
sergeyvc1c54062016-10-19 18:47:26 -070097 if (mBitmap) {
98 return mBitmap->getAllocationByteCount();
sergeyvc69853c2016-10-07 14:14:09 -070099 }
100 return mAllocationSize;
John Reckf29ed282015-04-07 07:32:03 -0700101 }
102
sergeyvc69853c2016-10-07 14:14:09 -0700103 size_t rowBytes() const {
sergeyvc1c54062016-10-19 18:47:26 -0700104 if (mBitmap) {
105 return mBitmap->rowBytes();
sergeyvc69853c2016-10-07 14:14:09 -0700106 }
107 return mRowBytes;
108 }
109
110 uint32_t getGenerationID() const {
sergeyvc1c54062016-10-19 18:47:26 -0700111 if (mBitmap) {
112 return mBitmap->getGenerationID();
sergeyvc69853c2016-10-07 14:14:09 -0700113 }
114 return mGenerationId;
115 }
116
sergeyvc1c54062016-10-19 18:47:26 -0700117 ~BitmapWrapper() { }
sergeyvc69853c2016-10-07 14:14:09 -0700118
John Reckf29ed282015-04-07 07:32:03 -0700119private:
sergeyvc1c54062016-10-19 18:47:26 -0700120 sk_sp<Bitmap> mBitmap;
sergeyvc69853c2016-10-07 14:14:09 -0700121 SkImageInfo mInfo;
122 bool mHasHardwareMipMap;
123 size_t mAllocationSize;
124 size_t mRowBytes;
125 uint32_t mGenerationId;
John Reckf29ed282015-04-07 07:32:03 -0700126};
127
John Reckf29ed282015-04-07 07:32:03 -0700128// Convenience class that does not take a global ref on the pixels, relying
129// on the caller already having a local JNI ref
130class LocalScopedBitmap {
131public:
Chih-Hung Hsiehc6baf562016-04-27 11:29:23 -0700132 explicit LocalScopedBitmap(jlong bitmapHandle)
sergeyvc1c54062016-10-19 18:47:26 -0700133 : mBitmapWrapper(reinterpret_cast<BitmapWrapper*>(bitmapHandle)) {}
John Reckf29ed282015-04-07 07:32:03 -0700134
sergeyvc1c54062016-10-19 18:47:26 -0700135 BitmapWrapper* operator->() {
136 return mBitmapWrapper;
John Reckf29ed282015-04-07 07:32:03 -0700137 }
138
139 void* pixels() {
sergeyvaed7f582016-10-14 16:30:21 -0700140 return mBitmapWrapper->bitmap().pixels();
John Reckf29ed282015-04-07 07:32:03 -0700141 }
142
143 bool valid() {
sergeyvc1c54062016-10-19 18:47:26 -0700144 return mBitmapWrapper && mBitmapWrapper->valid();
John Reckf29ed282015-04-07 07:32:03 -0700145 }
146
147private:
sergeyvc1c54062016-10-19 18:47:26 -0700148 BitmapWrapper* mBitmapWrapper;
John Reckf29ed282015-04-07 07:32:03 -0700149};
150
sergeyvc69853c2016-10-07 14:14:09 -0700151namespace bitmap {
152
153// Assert that bitmap's SkAlphaType is consistent with isPremultiplied.
154static void assert_premultiplied(const SkImageInfo& info, bool isPremultiplied) {
155 // kOpaque_SkAlphaType and kIgnore_SkAlphaType mean that isPremultiplied is
156 // irrelevant. This just tests to ensure that the SkAlphaType is not
157 // opposite of isPremultiplied.
158 if (isPremultiplied) {
159 SkASSERT(info.alphaType() != kUnpremul_SkAlphaType);
160 } else {
161 SkASSERT(info.alphaType() != kPremul_SkAlphaType);
162 }
163}
164
165void reinitBitmap(JNIEnv* env, jobject javaBitmap, const SkImageInfo& info,
166 bool isPremultiplied)
167{
168 // The caller needs to have already set the alpha type properly, so the
169 // native SkBitmap stays in sync with the Java Bitmap.
170 assert_premultiplied(info, isPremultiplied);
171
172 env->CallVoidMethod(javaBitmap, gBitmap_reinitMethodID,
173 info.width(), info.height(), isPremultiplied);
174}
175
176int getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap)
177{
178 return env->CallIntMethod(javaBitmap, gBitmap_getAllocationByteCountMethodID);
179}
180
sergeyvc1c54062016-10-19 18:47:26 -0700181jobject createBitmap(JNIEnv* env, Bitmap* bitmap,
sergeyvc69853c2016-10-07 14:14:09 -0700182 int bitmapCreateFlags, jbyteArray ninePatchChunk, jobject ninePatchInsets,
183 int density) {
184 bool isMutable = bitmapCreateFlags & kBitmapCreateFlag_Mutable;
185 bool isPremultiplied = bitmapCreateFlags & kBitmapCreateFlag_Premultiplied;
186 // The caller needs to have already set the alpha type properly, so the
187 // native SkBitmap stays in sync with the Java Bitmap.
sergeyvc1c54062016-10-19 18:47:26 -0700188 assert_premultiplied(bitmap->info(), isPremultiplied);
189 BitmapWrapper* bitmapWrapper = new BitmapWrapper(bitmap);
sergeyvc69853c2016-10-07 14:14:09 -0700190 jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
sergeyvc1c54062016-10-19 18:47:26 -0700191 reinterpret_cast<jlong>(bitmapWrapper), bitmap->width(), bitmap->height(), density,
192 isMutable, isPremultiplied, ninePatchChunk, ninePatchInsets);
sergeyvc69853c2016-10-07 14:14:09 -0700193
194 if (env->ExceptionCheck() != 0) {
195 ALOGE("*** Uncaught exception returned from Java call!\n");
196 env->ExceptionDescribe();
197 }
198 return obj;
199}
200
201void toSkBitmap(jlong bitmapHandle, SkBitmap* outBitmap) {
202 LocalScopedBitmap bitmap(bitmapHandle);
203 bitmap->getSkBitmap(outBitmap);
204}
205
sergeyvaed7f582016-10-14 16:30:21 -0700206Bitmap& toBitmap(JNIEnv* env, jobject bitmap) {
sergeyvc69853c2016-10-07 14:14:09 -0700207 SkASSERT(env);
208 SkASSERT(bitmap);
209 SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
210 jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
211 LocalScopedBitmap localBitmap(bitmapHandle);
sergeyvc1c54062016-10-19 18:47:26 -0700212 return localBitmap->bitmap();
sergeyvc69853c2016-10-07 14:14:09 -0700213}
214
215} // namespace bitmap
216
217} // namespace android
218
219using namespace android;
220using namespace android::bitmap;
221
Chris Craik32054b02014-05-09 13:58:56 -0700222///////////////////////////////////////////////////////////////////////////////
223// Conversions to/from SkColor, for get/setPixels, and the create method, which
224// is basically like setPixels
225
226typedef void (*FromColorProc)(void* dst, const SkColor src[], int width,
227 int x, int y);
228
229static void FromColor_D32(void* dst, const SkColor src[], int width,
230 int, int) {
231 SkPMColor* d = (SkPMColor*)dst;
232
233 for (int i = 0; i < width; i++) {
234 *d++ = SkPreMultiplyColor(*src++);
235 }
236}
237
238static void FromColor_D32_Raw(void* dst, const SkColor src[], int width,
239 int, int) {
Dan Albert46d84442014-11-18 16:07:51 -0800240 // Needed to thwart the unreachable code detection from clang.
241 static const bool sk_color_ne_zero = SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER;
242
Chris Craik32054b02014-05-09 13:58:56 -0700243 // SkColor's ordering may be different from SkPMColor
Dan Albert46d84442014-11-18 16:07:51 -0800244 if (sk_color_ne_zero) {
Chris Craik32054b02014-05-09 13:58:56 -0700245 memcpy(dst, src, width * sizeof(SkColor));
246 return;
247 }
248
249 // order isn't same, repack each pixel manually
250 SkPMColor* d = (SkPMColor*)dst;
251 for (int i = 0; i < width; i++) {
252 SkColor c = *src++;
253 *d++ = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
254 SkColorGetG(c), SkColorGetB(c));
255 }
256}
257
258static void FromColor_D565(void* dst, const SkColor src[], int width,
259 int x, int y) {
260 uint16_t* d = (uint16_t*)dst;
261
262 DITHER_565_SCAN(y);
263 for (int stop = x + width; x < stop; x++) {
264 SkColor c = *src++;
265 *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c),
266 DITHER_VALUE(x));
267 }
268}
269
270static void FromColor_D4444(void* dst, const SkColor src[], int width,
271 int x, int y) {
272 SkPMColor16* d = (SkPMColor16*)dst;
273
274 DITHER_4444_SCAN(y);
275 for (int stop = x + width; x < stop; x++) {
276 SkPMColor pmc = SkPreMultiplyColor(*src++);
277 *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
278// *d++ = SkPixel32ToPixel4444(pmc);
279 }
280}
281
282static void FromColor_D4444_Raw(void* dst, const SkColor src[], int width,
283 int x, int y) {
284 SkPMColor16* d = (SkPMColor16*)dst;
285
286 DITHER_4444_SCAN(y);
287 for (int stop = x + width; x < stop; x++) {
288 SkColor c = *src++;
289
290 // SkPMColor is used because the ordering is ARGB32, even though the target actually premultiplied
291 SkPMColor pmc = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
292 SkColorGetG(c), SkColorGetB(c));
293 *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
294// *d++ = SkPixel32ToPixel4444(pmc);
295 }
296}
297
Chris Craik6260b222015-07-24 15:17:29 -0700298static void FromColor_DA8(void* dst, const SkColor src[], int width, int x, int y) {
299 uint8_t* d = (uint8_t*)dst;
300
301 for (int stop = x + width; x < stop; x++) {
302 *d++ = SkColorGetA(*src++);
303 }
304}
305
Chris Craik32054b02014-05-09 13:58:56 -0700306// can return NULL
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400307static FromColorProc ChooseFromColorProc(const SkBitmap& bitmap) {
308 switch (bitmap.colorType()) {
309 case kN32_SkColorType:
310 return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D32 : FromColor_D32_Raw;
311 case kARGB_4444_SkColorType:
312 return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D4444 :
313 FromColor_D4444_Raw;
314 case kRGB_565_SkColorType:
Chris Craik32054b02014-05-09 13:58:56 -0700315 return FromColor_D565;
Chris Craik6260b222015-07-24 15:17:29 -0700316 case kAlpha_8_SkColorType:
317 return FromColor_DA8;
Chris Craik32054b02014-05-09 13:58:56 -0700318 default:
319 break;
320 }
321 return NULL;
322}
323
324bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride,
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400325 int x, int y, int width, int height, const SkBitmap& dstBitmap) {
Chris Craik32054b02014-05-09 13:58:56 -0700326 SkAutoLockPixels alp(dstBitmap);
327 void* dst = dstBitmap.getPixels();
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400328 FromColorProc proc = ChooseFromColorProc(dstBitmap);
Chris Craik32054b02014-05-09 13:58:56 -0700329
330 if (NULL == dst || NULL == proc) {
331 return false;
332 }
333
334 const jint* array = env->GetIntArrayElements(srcColors, NULL);
335 const SkColor* src = (const SkColor*)array + srcOffset;
336
337 // reset to to actual choice from caller
338 dst = dstBitmap.getAddr(x, y);
339 // now copy/convert each scanline
340 for (int y = 0; y < height; y++) {
341 proc(dst, src, width, x, y);
342 src += srcStride;
343 dst = (char*)dst + dstBitmap.rowBytes();
344 }
345
346 dstBitmap.notifyPixelsChanged();
347
348 env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array),
349 JNI_ABORT);
350 return true;
351}
352
353//////////////////// ToColor procs
354
355typedef void (*ToColorProc)(SkColor dst[], const void* src, int width,
356 SkColorTable*);
357
358static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width,
359 SkColorTable*) {
360 SkASSERT(width > 0);
361 const SkPMColor* s = (const SkPMColor*)src;
362 do {
363 *dst++ = SkUnPreMultiply::PMColorToColor(*s++);
364 } while (--width != 0);
365}
366
367static void ToColor_S32_Raw(SkColor dst[], const void* src, int width,
368 SkColorTable*) {
369 SkASSERT(width > 0);
370 const SkPMColor* s = (const SkPMColor*)src;
371 do {
372 SkPMColor c = *s++;
373 *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
374 SkGetPackedG32(c), SkGetPackedB32(c));
375 } while (--width != 0);
376}
377
378static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width,
379 SkColorTable*) {
380 SkASSERT(width > 0);
381 const SkPMColor* s = (const SkPMColor*)src;
382 do {
383 SkPMColor c = *s++;
384 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
385 SkGetPackedB32(c));
386 } while (--width != 0);
387}
388
389static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width,
390 SkColorTable*) {
391 SkASSERT(width > 0);
392 const SkPMColor16* s = (const SkPMColor16*)src;
393 do {
394 *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++));
395 } while (--width != 0);
396}
397
398static void ToColor_S4444_Raw(SkColor dst[], const void* src, int width,
399 SkColorTable*) {
400 SkASSERT(width > 0);
401 const SkPMColor16* s = (const SkPMColor16*)src;
402 do {
403 SkPMColor c = SkPixel4444ToPixel32(*s++);
404 *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
405 SkGetPackedG32(c), SkGetPackedB32(c));
406 } while (--width != 0);
407}
408
409static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width,
410 SkColorTable*) {
411 SkASSERT(width > 0);
412 const SkPMColor16* s = (const SkPMColor16*)src;
413 do {
414 SkPMColor c = SkPixel4444ToPixel32(*s++);
415 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
416 SkGetPackedB32(c));
417 } while (--width != 0);
418}
419
420static void ToColor_S565(SkColor dst[], const void* src, int width,
421 SkColorTable*) {
422 SkASSERT(width > 0);
423 const uint16_t* s = (const uint16_t*)src;
424 do {
425 uint16_t c = *s++;
426 *dst++ = SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c),
427 SkPacked16ToB32(c));
428 } while (--width != 0);
429}
430
431static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width,
432 SkColorTable* ctable) {
433 SkASSERT(width > 0);
434 const uint8_t* s = (const uint8_t*)src;
Mike Reed71487eb2014-11-19 16:13:20 -0500435 const SkPMColor* colors = ctable->readColors();
Chris Craik32054b02014-05-09 13:58:56 -0700436 do {
437 *dst++ = SkUnPreMultiply::PMColorToColor(colors[*s++]);
438 } while (--width != 0);
Chris Craik32054b02014-05-09 13:58:56 -0700439}
440
441static void ToColor_SI8_Raw(SkColor dst[], const void* src, int width,
442 SkColorTable* ctable) {
443 SkASSERT(width > 0);
444 const uint8_t* s = (const uint8_t*)src;
Mike Reed71487eb2014-11-19 16:13:20 -0500445 const SkPMColor* colors = ctable->readColors();
Chris Craik32054b02014-05-09 13:58:56 -0700446 do {
447 SkPMColor c = colors[*s++];
448 *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
449 SkGetPackedG32(c), SkGetPackedB32(c));
450 } while (--width != 0);
Chris Craik32054b02014-05-09 13:58:56 -0700451}
452
453static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width,
454 SkColorTable* ctable) {
455 SkASSERT(width > 0);
456 const uint8_t* s = (const uint8_t*)src;
Mike Reed71487eb2014-11-19 16:13:20 -0500457 const SkPMColor* colors = ctable->readColors();
Chris Craik32054b02014-05-09 13:58:56 -0700458 do {
459 SkPMColor c = colors[*s++];
460 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
461 SkGetPackedB32(c));
462 } while (--width != 0);
Chris Craik32054b02014-05-09 13:58:56 -0700463}
464
Chris Craik6260b222015-07-24 15:17:29 -0700465static void ToColor_SA8(SkColor dst[], const void* src, int width, SkColorTable*) {
466 SkASSERT(width > 0);
467 const uint8_t* s = (const uint8_t*)src;
468 do {
469 uint8_t c = *s++;
470 *dst++ = SkColorSetARGB(c, c, c, c);
471 } while (--width != 0);
472}
473
Chris Craik32054b02014-05-09 13:58:56 -0700474// can return NULL
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400475static ToColorProc ChooseToColorProc(const SkBitmap& src) {
Mike Reedb9330552014-06-16 17:31:48 -0400476 switch (src.colorType()) {
477 case kN32_SkColorType:
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400478 switch (src.alphaType()) {
479 case kOpaque_SkAlphaType:
480 return ToColor_S32_Opaque;
481 case kPremul_SkAlphaType:
482 return ToColor_S32_Alpha;
483 case kUnpremul_SkAlphaType:
484 return ToColor_S32_Raw;
485 default:
486 return NULL;
487 }
Mike Reedb9330552014-06-16 17:31:48 -0400488 case kARGB_4444_SkColorType:
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400489 switch (src.alphaType()) {
490 case kOpaque_SkAlphaType:
491 return ToColor_S4444_Opaque;
492 case kPremul_SkAlphaType:
493 return ToColor_S4444_Alpha;
494 case kUnpremul_SkAlphaType:
495 return ToColor_S4444_Raw;
496 default:
497 return NULL;
498 }
Mike Reedb9330552014-06-16 17:31:48 -0400499 case kRGB_565_SkColorType:
Chris Craik32054b02014-05-09 13:58:56 -0700500 return ToColor_S565;
Mike Reedb9330552014-06-16 17:31:48 -0400501 case kIndex_8_SkColorType:
Chris Craik32054b02014-05-09 13:58:56 -0700502 if (src.getColorTable() == NULL) {
503 return NULL;
504 }
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400505 switch (src.alphaType()) {
506 case kOpaque_SkAlphaType:
507 return ToColor_SI8_Opaque;
508 case kPremul_SkAlphaType:
509 return ToColor_SI8_Alpha;
510 case kUnpremul_SkAlphaType:
511 return ToColor_SI8_Raw;
512 default:
513 return NULL;
514 }
Chris Craik6260b222015-07-24 15:17:29 -0700515 case kAlpha_8_SkColorType:
516 return ToColor_SA8;
Chris Craik32054b02014-05-09 13:58:56 -0700517 default:
518 break;
519 }
520 return NULL;
521}
522
523///////////////////////////////////////////////////////////////////////////////
524///////////////////////////////////////////////////////////////////////////////
525
526static int getPremulBitmapCreateFlags(bool isMutable) {
sergeyvc69853c2016-10-07 14:14:09 -0700527 int flags = android::bitmap::kBitmapCreateFlag_Premultiplied;
528 if (isMutable) flags |= android::bitmap::kBitmapCreateFlag_Mutable;
Chris Craik32054b02014-05-09 13:58:56 -0700529 return flags;
530}
531
532static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
533 jint offset, jint stride, jint width, jint height,
534 jint configHandle, jboolean isMutable) {
Mike Reed1103b322014-07-08 12:36:44 -0400535 SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700536 if (NULL != jColors) {
537 size_t n = env->GetArrayLength(jColors);
538 if (n < SkAbs32(stride) * (size_t)height) {
539 doThrowAIOOBE(env);
540 return NULL;
541 }
542 }
543
544 // ARGB_4444 is a deprecated format, convert automatically to 8888
Mike Reedb9330552014-06-16 17:31:48 -0400545 if (colorType == kARGB_4444_SkColorType) {
546 colorType = kN32_SkColorType;
Chris Craik32054b02014-05-09 13:58:56 -0700547 }
548
549 SkBitmap bitmap;
Romain Guy253f2c22016-09-28 17:34:42 -0700550 bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType,
551 GraphicsJNI::defaultColorSpace()));
Chris Craik32054b02014-05-09 13:58:56 -0700552
sergeyvc1c54062016-10-19 18:47:26 -0700553 sk_sp<Bitmap> nativeBitmap = Bitmap::allocateHeapBitmap(&bitmap, NULL);
John Reckf29ed282015-04-07 07:32:03 -0700554 if (!nativeBitmap) {
Chris Craik32054b02014-05-09 13:58:56 -0700555 return NULL;
556 }
557
558 if (jColors != NULL) {
559 GraphicsJNI::SetPixels(env, jColors, offset, stride,
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400560 0, 0, width, height, bitmap);
Chris Craik32054b02014-05-09 13:58:56 -0700561 }
562
sergeyvc36bd6c2016-10-11 15:49:16 -0700563 return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable));
Chris Craik32054b02014-05-09 13:58:56 -0700564}
565
566static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle,
567 jint dstConfigHandle, jboolean isMutable) {
John Reckf29ed282015-04-07 07:32:03 -0700568 SkBitmap src;
sergeyvc1c54062016-10-19 18:47:26 -0700569 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
Mike Reed1103b322014-07-08 12:36:44 -0400570 SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
sergeyv45082182016-09-29 18:25:40 -0700571 SkBitmap result;
572 HeapAllocator allocator;
Chris Craik32054b02014-05-09 13:58:56 -0700573
John Reckf29ed282015-04-07 07:32:03 -0700574 if (!src.copyTo(&result, dstCT, &allocator)) {
Chris Craik32054b02014-05-09 13:58:56 -0700575 return NULL;
576 }
sergeyvc1c54062016-10-19 18:47:26 -0700577 auto bitmap = allocator.getStorageObjAndReset();
578 return createBitmap(env, bitmap, getPremulBitmapCreateFlags(isMutable));
Chris Craik32054b02014-05-09 13:58:56 -0700579}
580
sergeyvc1c54062016-10-19 18:47:26 -0700581static Bitmap* Bitmap_copyAshmemImpl(JNIEnv* env, SkBitmap& src, SkColorType& dstCT) {
Riley Andrews721ae5f2015-05-11 16:08:22 -0700582 SkBitmap result;
583
584 AshmemPixelAllocator allocator(env);
Winsona5fdde92016-04-14 15:27:15 -0700585 if (!src.copyTo(&result, dstCT, &allocator)) {
Riley Andrews721ae5f2015-05-11 16:08:22 -0700586 return NULL;
587 }
sergeyvc1c54062016-10-19 18:47:26 -0700588 auto bitmap = allocator.getStorageObjAndReset();
589 bitmap->setImmutable();
590 return bitmap;
Winsona5fdde92016-04-14 15:27:15 -0700591}
592
593static jobject Bitmap_copyAshmem(JNIEnv* env, jobject, jlong srcHandle) {
594 SkBitmap src;
sergeyvc1c54062016-10-19 18:47:26 -0700595 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
Winsona5fdde92016-04-14 15:27:15 -0700596 SkColorType dstCT = src.colorType();
sergeyvc1c54062016-10-19 18:47:26 -0700597 auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
598 jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
Winsona5fdde92016-04-14 15:27:15 -0700599 return ret;
600}
601
602static jobject Bitmap_copyAshmemConfig(JNIEnv* env, jobject, jlong srcHandle, jint dstConfigHandle) {
603 SkBitmap src;
sergeyvc1c54062016-10-19 18:47:26 -0700604 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
Winsona5fdde92016-04-14 15:27:15 -0700605 SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
sergeyvc1c54062016-10-19 18:47:26 -0700606 auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
607 jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
Riley Andrews721ae5f2015-05-11 16:08:22 -0700608 return ret;
609}
610
sergeyvc1c54062016-10-19 18:47:26 -0700611static void Bitmap_destruct(BitmapWrapper* bitmap) {
sergeyvc69853c2016-10-07 14:14:09 -0700612 delete bitmap;
Chris Craik32054b02014-05-09 13:58:56 -0700613}
614
Richard Uhler775873a2015-12-29 12:37:39 -0800615static jlong Bitmap_getNativeFinalizer(JNIEnv*, jobject) {
616 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Bitmap_destruct));
617}
618
Chris Craik32054b02014-05-09 13:58:56 -0700619static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700620 LocalScopedBitmap bitmap(bitmapHandle);
621 bitmap->freePixels();
Chris Craik32054b02014-05-09 13:58:56 -0700622 return JNI_TRUE;
623}
624
625static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
sergeyv45082182016-09-29 18:25:40 -0700626 jint width, jint height, jint configHandle, jboolean requestPremul) {
John Reckf29ed282015-04-07 07:32:03 -0700627 LocalScopedBitmap bitmap(bitmapHandle);
sergeyvc69853c2016-10-07 14:14:09 -0700628 bitmap->assertValid();
Mike Reed1103b322014-07-08 12:36:44 -0400629 SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
Leon Scroggins III17a8bfc2014-06-03 16:15:15 -0400630
631 // ARGB_4444 is a deprecated format, convert automatically to 8888
632 if (colorType == kARGB_4444_SkColorType) {
633 colorType = kN32_SkColorType;
634 }
sergeyv45082182016-09-29 18:25:40 -0700635 size_t requestedSize = width * height * SkColorTypeBytesPerPixel(colorType);
636 if (requestedSize > bitmap->getAllocationByteCount()) {
Chris Craik32054b02014-05-09 13:58:56 -0700637 // done in native as there's no way to get BytesPerPixel in Java
638 doThrowIAE(env, "Bitmap not large enough to support new configuration");
639 return;
640 }
Leon Scroggins III17a8bfc2014-06-03 16:15:15 -0400641 SkAlphaType alphaType;
John Reckf29ed282015-04-07 07:32:03 -0700642 if (bitmap->info().colorType() != kRGB_565_SkColorType
643 && bitmap->info().alphaType() == kOpaque_SkAlphaType) {
Leon Scroggins III17a8bfc2014-06-03 16:15:15 -0400644 // If the original bitmap was set to opaque, keep that setting, unless it
645 // was 565, which is required to be opaque.
646 alphaType = kOpaque_SkAlphaType;
647 } else {
648 // Otherwise respect the premultiplied request.
649 alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
650 }
sergeyvaed7f582016-10-14 16:30:21 -0700651 bitmap->bitmap().reconfigure(SkImageInfo::Make(width, height, colorType, alphaType,
Romain Guy253f2c22016-09-28 17:34:42 -0700652 sk_sp<SkColorSpace>(bitmap->info().colorSpace())));
Chris Craik32054b02014-05-09 13:58:56 -0700653}
654
655// These must match the int values in Bitmap.java
656enum JavaEncodeFormat {
657 kJPEG_JavaEncodeFormat = 0,
658 kPNG_JavaEncodeFormat = 1,
659 kWEBP_JavaEncodeFormat = 2
660};
661
662static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle,
663 jint format, jint quality,
664 jobject jstream, jbyteArray jstorage) {
John Reckf29ed282015-04-07 07:32:03 -0700665
666 LocalScopedBitmap bitmap(bitmapHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700667 SkImageEncoder::Type fm;
668
669 switch (format) {
670 case kJPEG_JavaEncodeFormat:
671 fm = SkImageEncoder::kJPEG_Type;
672 break;
673 case kPNG_JavaEncodeFormat:
674 fm = SkImageEncoder::kPNG_Type;
675 break;
676 case kWEBP_JavaEncodeFormat:
677 fm = SkImageEncoder::kWEBP_Type;
678 break;
679 default:
680 return JNI_FALSE;
681 }
682
John Reckf29ed282015-04-07 07:32:03 -0700683 if (!bitmap.valid()) {
684 return JNI_FALSE;
685 }
686
Chris Craik32054b02014-05-09 13:58:56 -0700687 bool success = false;
Chris Craik32054b02014-05-09 13:58:56 -0700688
John Reckf29ed282015-04-07 07:32:03 -0700689 std::unique_ptr<SkWStream> strm(CreateJavaOutputStreamAdaptor(env, jstream, jstorage));
690 if (!strm.get()) {
691 return JNI_FALSE;
692 }
Chris Craik32054b02014-05-09 13:58:56 -0700693
John Reckf29ed282015-04-07 07:32:03 -0700694 std::unique_ptr<SkImageEncoder> encoder(SkImageEncoder::Create(fm));
695 if (encoder.get()) {
696 SkBitmap skbitmap;
697 bitmap->getSkBitmap(&skbitmap);
698 success = encoder->encodeStream(strm.get(), skbitmap, quality);
Chris Craik32054b02014-05-09 13:58:56 -0700699 }
700 return success ? JNI_TRUE : JNI_FALSE;
701}
702
703static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) {
John Reckf29ed282015-04-07 07:32:03 -0700704 LocalScopedBitmap bitmap(bitmapHandle);
705 SkBitmap skBitmap;
706 bitmap->getSkBitmap(&skBitmap);
707 skBitmap.eraseColor(color);
Chris Craik32054b02014-05-09 13:58:56 -0700708}
709
710static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700711 LocalScopedBitmap bitmap(bitmapHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700712 return static_cast<jint>(bitmap->rowBytes());
713}
714
715static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700716 LocalScopedBitmap bitmap(bitmapHandle);
717 return GraphicsJNI::colorTypeToLegacyBitmapConfig(bitmap->info().colorType());
Chris Craik32054b02014-05-09 13:58:56 -0700718}
719
720static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700721 LocalScopedBitmap bitmap(bitmapHandle);
sergeyvc69853c2016-10-07 14:14:09 -0700722 return static_cast<jint>(bitmap->getGenerationID());
Chris Craik32054b02014-05-09 13:58:56 -0700723}
724
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400725static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700726 LocalScopedBitmap bitmap(bitmapHandle);
727 if (bitmap->info().alphaType() == kPremul_SkAlphaType) {
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400728 return JNI_TRUE;
729 }
730 return JNI_FALSE;
731}
732
Chris Craik32054b02014-05-09 13:58:56 -0700733static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700734 LocalScopedBitmap bitmap(bitmapHandle);
735 return !bitmap->info().isOpaque() ? JNI_TRUE : JNI_FALSE;
Chris Craik32054b02014-05-09 13:58:56 -0700736}
737
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400738static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle,
739 jboolean hasAlpha, jboolean requestPremul) {
John Reckf29ed282015-04-07 07:32:03 -0700740 LocalScopedBitmap bitmap(bitmapHandle);
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400741 if (hasAlpha) {
John Reck0781a2f2015-05-27 16:29:17 -0700742 bitmap->setAlphaType(
John Reckf29ed282015-04-07 07:32:03 -0700743 requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
Chris Craik32054b02014-05-09 13:58:56 -0700744 } else {
John Reck0781a2f2015-05-27 16:29:17 -0700745 bitmap->setAlphaType(kOpaque_SkAlphaType);
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400746 }
747}
748
749static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
750 jboolean isPremul) {
John Reckf29ed282015-04-07 07:32:03 -0700751 LocalScopedBitmap bitmap(bitmapHandle);
752 if (!bitmap->info().isOpaque()) {
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400753 if (isPremul) {
John Reck0781a2f2015-05-27 16:29:17 -0700754 bitmap->setAlphaType(kPremul_SkAlphaType);
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400755 } else {
John Reck0781a2f2015-05-27 16:29:17 -0700756 bitmap->setAlphaType(kUnpremul_SkAlphaType);
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400757 }
Chris Craik32054b02014-05-09 13:58:56 -0700758 }
759}
760
761static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700762 LocalScopedBitmap bitmap(bitmapHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700763 return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE;
764}
765
766static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle,
767 jboolean hasMipMap) {
John Reckf29ed282015-04-07 07:32:03 -0700768 LocalScopedBitmap bitmap(bitmapHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700769 bitmap->setHasHardwareMipMap(hasMipMap);
770}
771
772///////////////////////////////////////////////////////////////////////////////
773
774static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
775 if (parcel == NULL) {
776 SkDebugf("-------- unparcel parcel is NULL\n");
777 return NULL;
778 }
779
780 android::Parcel* p = android::parcelForJavaObject(env, parcel);
781
Mike Reedb9330552014-06-16 17:31:48 -0400782 const bool isMutable = p->readInt32() != 0;
783 const SkColorType colorType = (SkColorType)p->readInt32();
784 const SkAlphaType alphaType = (SkAlphaType)p->readInt32();
Romain Guy253f2c22016-09-28 17:34:42 -0700785 const bool isSRGB = p->readInt32() != 0;
Mike Reedb9330552014-06-16 17:31:48 -0400786 const int width = p->readInt32();
787 const int height = p->readInt32();
788 const int rowBytes = p->readInt32();
789 const int density = p->readInt32();
Chris Craik32054b02014-05-09 13:58:56 -0700790
Mike Reedb9330552014-06-16 17:31:48 -0400791 if (kN32_SkColorType != colorType &&
792 kRGB_565_SkColorType != colorType &&
793 kARGB_4444_SkColorType != colorType &&
794 kIndex_8_SkColorType != colorType &&
795 kAlpha_8_SkColorType != colorType) {
796 SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType);
Chris Craik32054b02014-05-09 13:58:56 -0700797 return NULL;
798 }
799
Leon Scroggins IIIec419e02015-03-11 13:12:06 -0400800 std::unique_ptr<SkBitmap> bitmap(new SkBitmap);
Chris Craik32054b02014-05-09 13:58:56 -0700801
Romain Guy253f2c22016-09-28 17:34:42 -0700802 if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType,
803 isSRGB ? SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named) : nullptr), rowBytes)) {
Leon Scroggins IIIec419e02015-03-11 13:12:06 -0400804 return NULL;
805 }
Chris Craik32054b02014-05-09 13:58:56 -0700806
807 SkColorTable* ctable = NULL;
Mike Reedb9330552014-06-16 17:31:48 -0400808 if (colorType == kIndex_8_SkColorType) {
Chris Craik32054b02014-05-09 13:58:56 -0700809 int count = p->readInt32();
Leon Scroggins IIIec419e02015-03-11 13:12:06 -0400810 if (count < 0 || count > 256) {
811 // The data is corrupt, since SkColorTable enforces a value between 0 and 256,
812 // inclusive.
813 return NULL;
814 }
Chris Craik32054b02014-05-09 13:58:56 -0700815 if (count > 0) {
816 size_t size = count * sizeof(SkPMColor);
817 const SkPMColor* src = (const SkPMColor*)p->readInplace(size);
Leon Scroggins IIIec419e02015-03-11 13:12:06 -0400818 if (src == NULL) {
819 return NULL;
820 }
Chris Craik32054b02014-05-09 13:58:56 -0700821 ctable = new SkColorTable(src, count);
822 }
823 }
824
Jeff Browna316c5d2015-06-05 15:14:06 -0700825 // Read the bitmap blob.
826 size_t size = bitmap->getSize();
827 android::Parcel::ReadableBlob blob;
828 android::status_t status = p->readBlob(size, &blob);
829 if (status) {
Chris Craik32054b02014-05-09 13:58:56 -0700830 SkSafeUnref(ctable);
Jeff Browna316c5d2015-06-05 15:14:06 -0700831 doThrowRE(env, "Could not read bitmap blob.");
Chris Craik32054b02014-05-09 13:58:56 -0700832 return NULL;
833 }
834
Jeff Browna316c5d2015-06-05 15:14:06 -0700835 // Map the bitmap in place from the ashmem region if possible otherwise copy.
sergeyvc1c54062016-10-19 18:47:26 -0700836 sk_sp<Bitmap> nativeBitmap;
Riley Andrews8cee7c12015-11-01 23:36:04 -0800837 if (blob.fd() >= 0 && (blob.isMutable() || !isMutable) && (size >= ASHMEM_BITMAP_MIN_SIZE)) {
Jeff Browna316c5d2015-06-05 15:14:06 -0700838#if DEBUG_PARCEL
839 ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob "
840 "(fds %s)",
841 isMutable ? "mutable" : "immutable",
842 blob.isMutable() ? "mutable" : "immutable",
843 p->allowFds() ? "allowed" : "forbidden");
844#endif
845 // Dup the file descriptor so we can keep a reference to it after the Parcel
846 // is disposed.
847 int dupFd = dup(blob.fd());
848 if (dupFd < 0) {
Erik Wolsheimer211abad2015-11-13 11:54:47 -0800849 ALOGE("Error allocating dup fd. Error:%d", errno);
Jeff Browna316c5d2015-06-05 15:14:06 -0700850 blob.release();
851 SkSafeUnref(ctable);
852 doThrowRE(env, "Could not allocate dup blob fd.");
853 return NULL;
854 }
855
856 // Map the pixels in place and take ownership of the ashmem region.
sergeyvc1c54062016-10-19 18:47:26 -0700857 nativeBitmap = sk_sp<Bitmap>(GraphicsJNI::mapAshmemBitmap(env, bitmap.get(),
sergeyvc36bd6c2016-10-11 15:49:16 -0700858 ctable, dupFd, const_cast<void*>(blob.data()), size, !isMutable));
Jeff Browna316c5d2015-06-05 15:14:06 -0700859 SkSafeUnref(ctable);
860 if (!nativeBitmap) {
861 close(dupFd);
862 blob.release();
863 doThrowRE(env, "Could not allocate ashmem pixel ref.");
864 return NULL;
865 }
866
867 // Clear the blob handle, don't release it.
868 blob.clear();
869 } else {
870#if DEBUG_PARCEL
871 if (blob.fd() >= 0) {
872 ALOGD("Bitmap.createFromParcel: copied contents of mutable bitmap "
873 "from immutable blob (fds %s)",
874 p->allowFds() ? "allowed" : "forbidden");
875 } else {
876 ALOGD("Bitmap.createFromParcel: copied contents from %s blob "
877 "(fds %s)",
878 blob.isMutable() ? "mutable" : "immutable",
879 p->allowFds() ? "allowed" : "forbidden");
880 }
881#endif
882
883 // Copy the pixels into a new buffer.
sergeyvc1c54062016-10-19 18:47:26 -0700884 nativeBitmap = Bitmap::allocateHeapBitmap(bitmap.get(), ctable);
Jeff Browna316c5d2015-06-05 15:14:06 -0700885 SkSafeUnref(ctable);
886 if (!nativeBitmap) {
887 blob.release();
888 doThrowRE(env, "Could not allocate java pixel ref.");
889 return NULL;
890 }
891 bitmap->lockPixels();
892 memcpy(bitmap->getPixels(), blob.data(), size);
893 bitmap->unlockPixels();
894
895 // Release the blob handle.
896 blob.release();
Chris Craik32054b02014-05-09 13:58:56 -0700897 }
Chris Craik32054b02014-05-09 13:58:56 -0700898
sergeyvc36bd6c2016-10-11 15:49:16 -0700899 return createBitmap(env, nativeBitmap.release(),
Leon Scroggins IIIec419e02015-03-11 13:12:06 -0400900 getPremulBitmapCreateFlags(isMutable), NULL, NULL, density);
Chris Craik32054b02014-05-09 13:58:56 -0700901}
902
903static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
904 jlong bitmapHandle,
905 jboolean isMutable, jint density,
906 jobject parcel) {
Chris Craik32054b02014-05-09 13:58:56 -0700907 if (parcel == NULL) {
908 SkDebugf("------- writeToParcel null parcel\n");
909 return JNI_FALSE;
910 }
911
912 android::Parcel* p = android::parcelForJavaObject(env, parcel);
John Reckf29ed282015-04-07 07:32:03 -0700913 SkBitmap bitmap;
Riley Andrews39d7f302014-11-13 17:43:25 -0800914
sergeyvc1c54062016-10-19 18:47:26 -0700915 auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle);
916 bitmapWrapper->getSkBitmap(&bitmap);
Chris Craik32054b02014-05-09 13:58:56 -0700917
Romain Guy253f2c22016-09-28 17:34:42 -0700918 sk_sp<SkColorSpace> sRGB = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
919 bool isSRGB = bitmap.colorSpace() == sRGB.get();
920
Chris Craik32054b02014-05-09 13:58:56 -0700921 p->writeInt32(isMutable);
John Reckf29ed282015-04-07 07:32:03 -0700922 p->writeInt32(bitmap.colorType());
923 p->writeInt32(bitmap.alphaType());
Romain Guy253f2c22016-09-28 17:34:42 -0700924 p->writeInt32(isSRGB); // TODO: We should write the color space (b/32072280)
John Reckf29ed282015-04-07 07:32:03 -0700925 p->writeInt32(bitmap.width());
926 p->writeInt32(bitmap.height());
927 p->writeInt32(bitmap.rowBytes());
Chris Craik32054b02014-05-09 13:58:56 -0700928 p->writeInt32(density);
929
John Reckf29ed282015-04-07 07:32:03 -0700930 if (bitmap.colorType() == kIndex_8_SkColorType) {
Leon Scroggins III66ce1c32016-02-02 11:11:55 -0500931 // The bitmap needs to be locked to access its color table.
932 SkAutoLockPixels alp(bitmap);
John Reckf29ed282015-04-07 07:32:03 -0700933 SkColorTable* ctable = bitmap.getColorTable();
Chris Craik32054b02014-05-09 13:58:56 -0700934 if (ctable != NULL) {
935 int count = ctable->count();
936 p->writeInt32(count);
937 memcpy(p->writeInplace(count * sizeof(SkPMColor)),
Mike Reed71487eb2014-11-19 16:13:20 -0500938 ctable->readColors(), count * sizeof(SkPMColor));
Chris Craik32054b02014-05-09 13:58:56 -0700939 } else {
940 p->writeInt32(0); // indicate no ctable
941 }
942 }
943
Jeff Browna316c5d2015-06-05 15:14:06 -0700944 // Transfer the underlying ashmem region if we have one and it's immutable.
945 android::status_t status;
sergeyvaed7f582016-10-14 16:30:21 -0700946 int fd = bitmapWrapper->bitmap().getAshmemFd();
Jeff Browna316c5d2015-06-05 15:14:06 -0700947 if (fd >= 0 && !isMutable && p->allowFds()) {
948#if DEBUG_PARCEL
949 ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as "
950 "immutable blob (fds %s)",
951 p->allowFds() ? "allowed" : "forbidden");
952#endif
953
954 status = p->writeDupImmutableBlobFileDescriptor(fd);
955 if (status) {
956 doThrowRE(env, "Could not write bitmap blob file descriptor.");
Riley Andrews39d7f302014-11-13 17:43:25 -0800957 return JNI_FALSE;
958 }
Jeff Browna316c5d2015-06-05 15:14:06 -0700959 return JNI_TRUE;
Riley Andrews39d7f302014-11-13 17:43:25 -0800960 }
Jeff Browna316c5d2015-06-05 15:14:06 -0700961
962 // Copy the bitmap to a new blob.
963 bool mutableCopy = isMutable;
964#if DEBUG_PARCEL
965 ALOGD("Bitmap.writeToParcel: copying %s bitmap into new %s blob (fds %s)",
966 isMutable ? "mutable" : "immutable",
967 mutableCopy ? "mutable" : "immutable",
968 p->allowFds() ? "allowed" : "forbidden");
969#endif
970
971 size_t size = bitmap.getSize();
972 android::Parcel::WritableBlob blob;
973 status = p->writeBlob(size, mutableCopy, &blob);
974 if (status) {
975 doThrowRE(env, "Could not copy bitmap to parcel blob.");
976 return JNI_FALSE;
977 }
978
979 bitmap.lockPixels();
980 const void* pSrc = bitmap.getPixels();
981 if (pSrc == NULL) {
982 memset(blob.data(), 0, size);
983 } else {
984 memcpy(blob.data(), pSrc, size);
985 }
986 bitmap.unlockPixels();
987
988 blob.release();
Chris Craik32054b02014-05-09 13:58:56 -0700989 return JNI_TRUE;
990}
991
992static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
993 jlong srcHandle, jlong paintHandle,
994 jintArray offsetXY) {
John Reckf29ed282015-04-07 07:32:03 -0700995 SkBitmap src;
sergeyvc1c54062016-10-19 18:47:26 -0700996 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -0400997 const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700998 SkIPoint offset;
John Reckf29ed282015-04-07 07:32:03 -0700999 SkBitmap dst;
sergeyv45082182016-09-29 18:25:40 -07001000 HeapAllocator allocator;
Chris Craik32054b02014-05-09 13:58:56 -07001001
John Reckf29ed282015-04-07 07:32:03 -07001002 src.extractAlpha(&dst, paint, &allocator, &offset);
Chris Craik32054b02014-05-09 13:58:56 -07001003 // If Skia can't allocate pixels for destination bitmap, it resets
1004 // it, that is set its pixels buffer to NULL, and zero width and height.
John Reckf29ed282015-04-07 07:32:03 -07001005 if (dst.getPixels() == NULL && src.getPixels() != NULL) {
Chris Craik32054b02014-05-09 13:58:56 -07001006 doThrowOOME(env, "failed to allocate pixels for alpha");
1007 return NULL;
1008 }
1009 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
1010 int* array = env->GetIntArrayElements(offsetXY, NULL);
1011 array[0] = offset.fX;
1012 array[1] = offset.fY;
1013 env->ReleaseIntArrayElements(offsetXY, array, 0);
1014 }
1015
sergeyvc69853c2016-10-07 14:14:09 -07001016 return createBitmap(env, allocator.getStorageObjAndReset(),
John Reckf29ed282015-04-07 07:32:03 -07001017 getPremulBitmapCreateFlags(true));
Chris Craik32054b02014-05-09 13:58:56 -07001018}
1019
1020///////////////////////////////////////////////////////////////////////////////
1021
1022static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
Leon Scroggins III57ee6202014-06-04 18:51:07 -04001023 jint x, jint y) {
John Reckf29ed282015-04-07 07:32:03 -07001024 SkBitmap bitmap;
sergeyvc1c54062016-10-19 18:47:26 -07001025 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
John Reckf29ed282015-04-07 07:32:03 -07001026 SkAutoLockPixels alp(bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001027
John Reckf29ed282015-04-07 07:32:03 -07001028 ToColorProc proc = ChooseToColorProc(bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001029 if (NULL == proc) {
1030 return 0;
1031 }
John Reckf29ed282015-04-07 07:32:03 -07001032 const void* src = bitmap.getAddr(x, y);
Chris Craik32054b02014-05-09 13:58:56 -07001033 if (NULL == src) {
1034 return 0;
1035 }
1036
1037 SkColor dst[1];
John Reckf29ed282015-04-07 07:32:03 -07001038 proc(dst, src, 1, bitmap.getColorTable());
Chris Craik32054b02014-05-09 13:58:56 -07001039 return static_cast<jint>(dst[0]);
1040}
1041
1042static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,
1043 jintArray pixelArray, jint offset, jint stride,
Leon Scroggins III57ee6202014-06-04 18:51:07 -04001044 jint x, jint y, jint width, jint height) {
John Reckf29ed282015-04-07 07:32:03 -07001045 SkBitmap bitmap;
sergeyvc1c54062016-10-19 18:47:26 -07001046 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
John Reckf29ed282015-04-07 07:32:03 -07001047 SkAutoLockPixels alp(bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001048
John Reckf29ed282015-04-07 07:32:03 -07001049 ToColorProc proc = ChooseToColorProc(bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001050 if (NULL == proc) {
1051 return;
1052 }
John Reckf29ed282015-04-07 07:32:03 -07001053 const void* src = bitmap.getAddr(x, y);
Chris Craik32054b02014-05-09 13:58:56 -07001054 if (NULL == src) {
1055 return;
1056 }
1057
John Reckf29ed282015-04-07 07:32:03 -07001058 SkColorTable* ctable = bitmap.getColorTable();
Chris Craik32054b02014-05-09 13:58:56 -07001059 jint* dst = env->GetIntArrayElements(pixelArray, NULL);
1060 SkColor* d = (SkColor*)dst + offset;
1061 while (--height >= 0) {
1062 proc(d, src, width, ctable);
1063 d += stride;
John Reckf29ed282015-04-07 07:32:03 -07001064 src = (void*)((const char*)src + bitmap.rowBytes());
Chris Craik32054b02014-05-09 13:58:56 -07001065 }
1066 env->ReleaseIntArrayElements(pixelArray, dst, 0);
1067}
1068
1069///////////////////////////////////////////////////////////////////////////////
1070
1071static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle,
Leon Scroggins III57ee6202014-06-04 18:51:07 -04001072 jint x, jint y, jint colorHandle) {
John Reckf29ed282015-04-07 07:32:03 -07001073 SkBitmap bitmap;
sergeyvc1c54062016-10-19 18:47:26 -07001074 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001075 SkColor color = static_cast<SkColor>(colorHandle);
John Reckf29ed282015-04-07 07:32:03 -07001076 SkAutoLockPixels alp(bitmap);
1077 if (NULL == bitmap.getPixels()) {
Chris Craik32054b02014-05-09 13:58:56 -07001078 return;
1079 }
1080
John Reckf29ed282015-04-07 07:32:03 -07001081 FromColorProc proc = ChooseFromColorProc(bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001082 if (NULL == proc) {
1083 return;
1084 }
1085
John Reckf29ed282015-04-07 07:32:03 -07001086 proc(bitmap.getAddr(x, y), &color, 1, x, y);
1087 bitmap.notifyPixelsChanged();
Chris Craik32054b02014-05-09 13:58:56 -07001088}
1089
1090static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,
1091 jintArray pixelArray, jint offset, jint stride,
Leon Scroggins III57ee6202014-06-04 18:51:07 -04001092 jint x, jint y, jint width, jint height) {
John Reckf29ed282015-04-07 07:32:03 -07001093 SkBitmap bitmap;
sergeyvc1c54062016-10-19 18:47:26 -07001094 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001095 GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
John Reckf29ed282015-04-07 07:32:03 -07001096 x, y, width, height, bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001097}
1098
1099static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
1100 jlong bitmapHandle, jobject jbuffer) {
John Reckf29ed282015-04-07 07:32:03 -07001101 SkBitmap bitmap;
sergeyvc1c54062016-10-19 18:47:26 -07001102 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
John Reckf29ed282015-04-07 07:32:03 -07001103 SkAutoLockPixels alp(bitmap);
1104 const void* src = bitmap.getPixels();
Chris Craik32054b02014-05-09 13:58:56 -07001105
1106 if (NULL != src) {
1107 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
1108
1109 // the java side has already checked that buffer is large enough
John Reckf29ed282015-04-07 07:32:03 -07001110 memcpy(abp.pointer(), src, bitmap.getSize());
Chris Craik32054b02014-05-09 13:58:56 -07001111 }
1112}
1113
1114static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,
1115 jlong bitmapHandle, jobject jbuffer) {
John Reckf29ed282015-04-07 07:32:03 -07001116 SkBitmap bitmap;
sergeyvc1c54062016-10-19 18:47:26 -07001117 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
John Reckf29ed282015-04-07 07:32:03 -07001118 SkAutoLockPixels alp(bitmap);
1119 void* dst = bitmap.getPixels();
Chris Craik32054b02014-05-09 13:58:56 -07001120
1121 if (NULL != dst) {
1122 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);
1123 // the java side has already checked that buffer is large enough
John Reckf29ed282015-04-07 07:32:03 -07001124 memcpy(dst, abp.pointer(), bitmap.getSize());
1125 bitmap.notifyPixelsChanged();
Chris Craik32054b02014-05-09 13:58:56 -07001126 }
1127}
1128
1129static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle,
1130 jlong bm1Handle) {
John Reckf29ed282015-04-07 07:32:03 -07001131 SkBitmap bm0;
1132 SkBitmap bm1;
sergeyvc1c54062016-10-19 18:47:26 -07001133 reinterpret_cast<BitmapWrapper*>(bm0Handle)->getSkBitmap(&bm0);
1134 reinterpret_cast<BitmapWrapper*>(bm1Handle)->getSkBitmap(&bm1);
John Reckf29ed282015-04-07 07:32:03 -07001135 if (bm0.width() != bm1.width() ||
1136 bm0.height() != bm1.height() ||
Romain Guy253f2c22016-09-28 17:34:42 -07001137 bm0.colorType() != bm1.colorType() ||
1138 bm0.alphaType() != bm1.alphaType() ||
1139 bm0.colorSpace() != bm1.colorSpace()) {
Chris Craik32054b02014-05-09 13:58:56 -07001140 return JNI_FALSE;
1141 }
1142
John Reckf29ed282015-04-07 07:32:03 -07001143 SkAutoLockPixels alp0(bm0);
1144 SkAutoLockPixels alp1(bm1);
Chris Craik32054b02014-05-09 13:58:56 -07001145
1146 // if we can't load the pixels, return false
John Reckf29ed282015-04-07 07:32:03 -07001147 if (NULL == bm0.getPixels() || NULL == bm1.getPixels()) {
Chris Craik32054b02014-05-09 13:58:56 -07001148 return JNI_FALSE;
1149 }
1150
John Reckf29ed282015-04-07 07:32:03 -07001151 if (bm0.colorType() == kIndex_8_SkColorType) {
1152 SkColorTable* ct0 = bm0.getColorTable();
1153 SkColorTable* ct1 = bm1.getColorTable();
Chris Craik32054b02014-05-09 13:58:56 -07001154 if (NULL == ct0 || NULL == ct1) {
1155 return JNI_FALSE;
1156 }
1157 if (ct0->count() != ct1->count()) {
1158 return JNI_FALSE;
1159 }
1160
Chris Craik32054b02014-05-09 13:58:56 -07001161 const size_t size = ct0->count() * sizeof(SkPMColor);
Mike Reed71487eb2014-11-19 16:13:20 -05001162 if (memcmp(ct0->readColors(), ct1->readColors(), size) != 0) {
Chris Craik32054b02014-05-09 13:58:56 -07001163 return JNI_FALSE;
1164 }
1165 }
1166
1167 // now compare each scanline. We can't do the entire buffer at once,
1168 // since we don't care about the pixel values that might extend beyond
1169 // the width (since the scanline might be larger than the logical width)
John Reckf29ed282015-04-07 07:32:03 -07001170 const int h = bm0.height();
1171 const size_t size = bm0.width() * bm0.bytesPerPixel();
Chris Craik32054b02014-05-09 13:58:56 -07001172 for (int y = 0; y < h; y++) {
henry.uh_chen53001ca2014-07-03 20:40:22 +08001173 // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config
1174 // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0
1175 // and bm1 both have pixel data() (have passed NULL == getPixels() check),
1176 // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE
1177 // to warn user those 2 unrecognized config bitmaps may be different.
John Reckf29ed282015-04-07 07:32:03 -07001178 void *bm0Addr = bm0.getAddr(0, y);
1179 void *bm1Addr = bm1.getAddr(0, y);
henry.uh_chen53001ca2014-07-03 20:40:22 +08001180
1181 if(bm0Addr == NULL || bm1Addr == NULL) {
1182 return JNI_FALSE;
1183 }
1184
1185 if (memcmp(bm0Addr, bm1Addr, size) != 0) {
Chris Craik32054b02014-05-09 13:58:56 -07001186 return JNI_FALSE;
1187 }
1188 }
1189 return JNI_TRUE;
1190}
1191
Romain Guy1158b6d2016-10-12 10:55:08 -07001192static jlong Bitmap_refPixelRef(JNIEnv* env, jobject, jlong bitmapHandle) {
1193 LocalScopedBitmap bitmap(bitmapHandle);
sergeyvaed7f582016-10-14 16:30:21 -07001194 SkPixelRef& pixelRef = bitmap->bitmap();
1195 pixelRef.ref();
1196 return reinterpret_cast<jlong>(&pixelRef);
Romain Guy1158b6d2016-10-12 10:55:08 -07001197}
1198
John Reck43871902016-08-01 14:39:24 -07001199static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapPtr) {
1200 LocalScopedBitmap bitmapHandle(bitmapPtr);
1201 if (!bitmapHandle.valid()) return;
1202 SkBitmap bitmap;
1203 bitmapHandle->getSkBitmap(&bitmap);
1204 android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmap);
1205}
1206
sergeyv45082182016-09-29 18:25:40 -07001207static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr) {
1208 LocalScopedBitmap bitmapHandle(bitmapPtr);
1209 return static_cast<jint>(bitmapHandle->getAllocationByteCount());
1210}
1211
Chris Craik32054b02014-05-09 13:58:56 -07001212///////////////////////////////////////////////////////////////////////////////
sergeyvc69853c2016-10-07 14:14:09 -07001213static jclass make_globalref(JNIEnv* env, const char classname[])
1214{
1215 jclass c = env->FindClass(classname);
1216 SkASSERT(c);
1217 return (jclass) env->NewGlobalRef(c);
1218}
1219
1220static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
1221 const char fieldname[], const char type[])
1222{
1223 jfieldID id = env->GetFieldID(clazz, fieldname, type);
1224 SkASSERT(id);
1225 return id;
1226}
Chris Craik32054b02014-05-09 13:58:56 -07001227
Daniel Micay76f6a862015-09-19 17:31:01 -04001228static const JNINativeMethod gBitmapMethods[] = {
Chris Craik32054b02014-05-09 13:58:56 -07001229 { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;",
1230 (void*)Bitmap_creator },
1231 { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;",
1232 (void*)Bitmap_copy },
Riley Andrews721ae5f2015-05-11 16:08:22 -07001233 { "nativeCopyAshmem", "(J)Landroid/graphics/Bitmap;",
1234 (void*)Bitmap_copyAshmem },
Winsona5fdde92016-04-14 15:27:15 -07001235 { "nativeCopyAshmemConfig", "(JI)Landroid/graphics/Bitmap;",
1236 (void*)Bitmap_copyAshmemConfig },
Richard Uhler775873a2015-12-29 12:37:39 -08001237 { "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer },
Chris Craik32054b02014-05-09 13:58:56 -07001238 { "nativeRecycle", "(J)Z", (void*)Bitmap_recycle },
sergeyv45082182016-09-29 18:25:40 -07001239 { "nativeReconfigure", "(JIIIZ)V", (void*)Bitmap_reconfigure },
Chris Craik32054b02014-05-09 13:58:56 -07001240 { "nativeCompress", "(JIILjava/io/OutputStream;[B)Z",
1241 (void*)Bitmap_compress },
1242 { "nativeErase", "(JI)V", (void*)Bitmap_erase },
1243 { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes },
1244 { "nativeConfig", "(J)I", (void*)Bitmap_config },
1245 { "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha },
Leon Scroggins III57ee6202014-06-04 18:51:07 -04001246 { "nativeIsPremultiplied", "(J)Z", (void*)Bitmap_isPremultiplied},
1247 { "nativeSetHasAlpha", "(JZZ)V", (void*)Bitmap_setHasAlpha},
1248 { "nativeSetPremultiplied", "(JZ)V", (void*)Bitmap_setPremultiplied},
Chris Craik32054b02014-05-09 13:58:56 -07001249 { "nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap },
1250 { "nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap },
1251 { "nativeCreateFromParcel",
1252 "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
1253 (void*)Bitmap_createFromParcel },
1254 { "nativeWriteToParcel", "(JZILandroid/os/Parcel;)Z",
1255 (void*)Bitmap_writeToParcel },
1256 { "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;",
1257 (void*)Bitmap_extractAlpha },
1258 { "nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId },
Leon Scroggins III57ee6202014-06-04 18:51:07 -04001259 { "nativeGetPixel", "(JII)I", (void*)Bitmap_getPixel },
1260 { "nativeGetPixels", "(J[IIIIIII)V", (void*)Bitmap_getPixels },
1261 { "nativeSetPixel", "(JIII)V", (void*)Bitmap_setPixel },
1262 { "nativeSetPixels", "(J[IIIIIII)V", (void*)Bitmap_setPixels },
Chris Craik32054b02014-05-09 13:58:56 -07001263 { "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V",
1264 (void*)Bitmap_copyPixelsToBuffer },
1265 { "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V",
1266 (void*)Bitmap_copyPixelsFromBuffer },
1267 { "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs },
Romain Guy1158b6d2016-10-12 10:55:08 -07001268 { "nativeRefPixelRef", "(J)J", (void*)Bitmap_refPixelRef },
John Reck43871902016-08-01 14:39:24 -07001269 { "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw },
sergeyv45082182016-09-29 18:25:40 -07001270 { "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount },
Chris Craik32054b02014-05-09 13:58:56 -07001271};
1272
Chris Craik32054b02014-05-09 13:58:56 -07001273int register_android_graphics_Bitmap(JNIEnv* env)
1274{
sergeyvc69853c2016-10-07 14:14:09 -07001275 gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
1276 gBitmap_nativePtr = getFieldIDCheck(env, gBitmap_class, "mNativePtr", "J");
1277 gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
1278 gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "(IIZ)V");
1279 gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I");
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001280 return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods,
1281 NELEM(gBitmapMethods));
sergeyvc69853c2016-10-07 14:14:09 -07001282}