blob: 59cbc939890a02c6c059b8ac3606fd33eabdf0db [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"
Romain Guy9505a652016-12-14 09:43:50 -08008#include "SkColor.h"
Chris Craik32054b02014-05-09 13:58:56 -07009#include "SkColorPriv.h"
Romain Guy9505a652016-12-14 09:43:50 -080010#include "SkHalf.h"
11#include "SkPM4f.h"
12#include "SkPM4fPriv.h"
Chris Craik32054b02014-05-09 13:58:56 -070013#include "GraphicsJNI.h"
14#include "SkDither.h"
15#include "SkUnPreMultiply.h"
16#include "SkStream.h"
17
18#include <binder/Parcel.h>
19#include "android_os_Parcel.h"
20#include "android_util_Binder.h"
21#include "android_nio_utils.h"
22#include "CreateJavaOutputStreamAdaptor.h"
sergeyvdccca442016-03-21 15:38:21 -070023#include <hwui/Paint.h>
sergeyvc1c54062016-10-19 18:47:26 -070024#include <hwui/Bitmap.h>
John Reck43871902016-08-01 14:39:24 -070025#include <renderthread/RenderProxy.h>
Chris Craik32054b02014-05-09 13:58:56 -070026
Andreas Gampeed6b9df2014-11-20 22:02:20 -080027#include "core_jni_helpers.h"
28
Chris Craik32054b02014-05-09 13:58:56 -070029#include <jni.h>
Riley Andrews39d7f302014-11-13 17:43:25 -080030#include <memory>
31#include <string>
Chris Craik32054b02014-05-09 13:58:56 -070032
Jeff Browna316c5d2015-06-05 15:14:06 -070033#define DEBUG_PARCEL 0
Riley Andrews8cee7c12015-11-01 23:36:04 -080034#define ASHMEM_BITMAP_MIN_SIZE (128 * (1 << 10))
Jeff Browna316c5d2015-06-05 15:14:06 -070035
sergeyvc69853c2016-10-07 14:14:09 -070036static jclass gBitmap_class;
37static jfieldID gBitmap_nativePtr;
38static jmethodID gBitmap_constructorMethodID;
39static jmethodID gBitmap_reinitMethodID;
40static jmethodID gBitmap_getAllocationByteCountMethodID;
41
John Reckf29ed282015-04-07 07:32:03 -070042namespace android {
43
sergeyvc1c54062016-10-19 18:47:26 -070044class BitmapWrapper {
John Reckf29ed282015-04-07 07:32:03 -070045public:
sergeyvc1c54062016-10-19 18:47:26 -070046 BitmapWrapper(Bitmap* bitmap)
47 : mBitmap(bitmap) { }
sergeyvc69853c2016-10-07 14:14:09 -070048
49 void freePixels() {
sergeyvc1c54062016-10-19 18:47:26 -070050 mInfo = mBitmap->info();
51 mHasHardwareMipMap = mBitmap->hasHardwareMipMap();
52 mAllocationSize = mBitmap->getAllocationByteCount();
53 mRowBytes = mBitmap->rowBytes();
54 mGenerationId = mBitmap->getGenerationID();
sergeyv15a10852016-12-27 14:32:03 -080055 mIsHardware = mBitmap->isHardware();
sergeyvc1c54062016-10-19 18:47:26 -070056 mBitmap.reset();
John Reckf29ed282015-04-07 07:32:03 -070057 }
58
sergeyvc69853c2016-10-07 14:14:09 -070059 bool valid() {
sergeyvfc9999502016-10-17 13:07:38 -070060 return mBitmap;
John Reckf29ed282015-04-07 07:32:03 -070061 }
62
sergeyvaed7f582016-10-14 16:30:21 -070063 Bitmap& bitmap() {
64 assertValid();
65 return *mBitmap;
66 }
sergeyvc69853c2016-10-07 14:14:09 -070067
68 void assertValid() {
69 LOG_ALWAYS_FATAL_IF(!valid(), "Error, cannot access an invalid/free'd bitmap here!");
70 }
71
72 void getSkBitmap(SkBitmap* outBitmap) {
73 assertValid();
sergeyvc1c54062016-10-19 18:47:26 -070074 mBitmap->getSkBitmap(outBitmap);
sergeyvc69853c2016-10-07 14:14:09 -070075 }
76
77 bool hasHardwareMipMap() {
sergeyvc1c54062016-10-19 18:47:26 -070078 if (mBitmap) {
79 return mBitmap->hasHardwareMipMap();
John Reckf29ed282015-04-07 07:32:03 -070080 }
John Reckf29ed282015-04-07 07:32:03 -070081 return mHasHardwareMipMap;
82 }
83
84 void setHasHardwareMipMap(bool hasMipMap) {
sergeyvc69853c2016-10-07 14:14:09 -070085 assertValid();
sergeyvc1c54062016-10-19 18:47:26 -070086 mBitmap->setHasHardwareMipMap(hasMipMap);
John Reckf29ed282015-04-07 07:32:03 -070087 }
88
sergeyvc69853c2016-10-07 14:14:09 -070089 void setAlphaType(SkAlphaType alphaType) {
90 assertValid();
sergeyvc1c54062016-10-19 18:47:26 -070091 mBitmap->setAlphaType(alphaType);
John Reckf29ed282015-04-07 07:32:03 -070092 }
93
sergeyvc69853c2016-10-07 14:14:09 -070094 const SkImageInfo& info() {
sergeyvc1c54062016-10-19 18:47:26 -070095 if (mBitmap) {
96 return mBitmap->info();
sergeyvc69853c2016-10-07 14:14:09 -070097 }
98 return mInfo;
John Reckf29ed282015-04-07 07:32:03 -070099 }
100
sergeyvc69853c2016-10-07 14:14:09 -0700101 size_t getAllocationByteCount() const {
sergeyvc1c54062016-10-19 18:47:26 -0700102 if (mBitmap) {
103 return mBitmap->getAllocationByteCount();
sergeyvc69853c2016-10-07 14:14:09 -0700104 }
105 return mAllocationSize;
John Reckf29ed282015-04-07 07:32:03 -0700106 }
107
sergeyvc69853c2016-10-07 14:14:09 -0700108 size_t rowBytes() const {
sergeyvc1c54062016-10-19 18:47:26 -0700109 if (mBitmap) {
110 return mBitmap->rowBytes();
sergeyvc69853c2016-10-07 14:14:09 -0700111 }
112 return mRowBytes;
113 }
114
115 uint32_t getGenerationID() const {
sergeyvc1c54062016-10-19 18:47:26 -0700116 if (mBitmap) {
117 return mBitmap->getGenerationID();
sergeyvc69853c2016-10-07 14:14:09 -0700118 }
119 return mGenerationId;
120 }
121
sergeyv15a10852016-12-27 14:32:03 -0800122 bool isHardware() {
123 if (mBitmap) {
124 return mBitmap->isHardware();
125 }
126 return mIsHardware;
127 }
128
sergeyvc1c54062016-10-19 18:47:26 -0700129 ~BitmapWrapper() { }
sergeyvc69853c2016-10-07 14:14:09 -0700130
John Reckf29ed282015-04-07 07:32:03 -0700131private:
sergeyvc1c54062016-10-19 18:47:26 -0700132 sk_sp<Bitmap> mBitmap;
sergeyvc69853c2016-10-07 14:14:09 -0700133 SkImageInfo mInfo;
134 bool mHasHardwareMipMap;
135 size_t mAllocationSize;
136 size_t mRowBytes;
137 uint32_t mGenerationId;
sergeyv15a10852016-12-27 14:32:03 -0800138 bool mIsHardware;
John Reckf29ed282015-04-07 07:32:03 -0700139};
140
John Reckf29ed282015-04-07 07:32:03 -0700141// Convenience class that does not take a global ref on the pixels, relying
142// on the caller already having a local JNI ref
143class LocalScopedBitmap {
144public:
Chih-Hung Hsiehc6baf562016-04-27 11:29:23 -0700145 explicit LocalScopedBitmap(jlong bitmapHandle)
sergeyvc1c54062016-10-19 18:47:26 -0700146 : mBitmapWrapper(reinterpret_cast<BitmapWrapper*>(bitmapHandle)) {}
John Reckf29ed282015-04-07 07:32:03 -0700147
sergeyvc1c54062016-10-19 18:47:26 -0700148 BitmapWrapper* operator->() {
149 return mBitmapWrapper;
John Reckf29ed282015-04-07 07:32:03 -0700150 }
151
152 void* pixels() {
sergeyvaed7f582016-10-14 16:30:21 -0700153 return mBitmapWrapper->bitmap().pixels();
John Reckf29ed282015-04-07 07:32:03 -0700154 }
155
156 bool valid() {
sergeyvc1c54062016-10-19 18:47:26 -0700157 return mBitmapWrapper && mBitmapWrapper->valid();
John Reckf29ed282015-04-07 07:32:03 -0700158 }
159
160private:
sergeyvc1c54062016-10-19 18:47:26 -0700161 BitmapWrapper* mBitmapWrapper;
John Reckf29ed282015-04-07 07:32:03 -0700162};
163
sergeyvc69853c2016-10-07 14:14:09 -0700164namespace bitmap {
165
166// Assert that bitmap's SkAlphaType is consistent with isPremultiplied.
167static void assert_premultiplied(const SkImageInfo& info, bool isPremultiplied) {
168 // kOpaque_SkAlphaType and kIgnore_SkAlphaType mean that isPremultiplied is
169 // irrelevant. This just tests to ensure that the SkAlphaType is not
170 // opposite of isPremultiplied.
171 if (isPremultiplied) {
172 SkASSERT(info.alphaType() != kUnpremul_SkAlphaType);
173 } else {
174 SkASSERT(info.alphaType() != kPremul_SkAlphaType);
175 }
176}
177
178void reinitBitmap(JNIEnv* env, jobject javaBitmap, const SkImageInfo& info,
179 bool isPremultiplied)
180{
181 // The caller needs to have already set the alpha type properly, so the
182 // native SkBitmap stays in sync with the Java Bitmap.
183 assert_premultiplied(info, isPremultiplied);
184
185 env->CallVoidMethod(javaBitmap, gBitmap_reinitMethodID,
186 info.width(), info.height(), isPremultiplied);
187}
188
189int getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap)
190{
191 return env->CallIntMethod(javaBitmap, gBitmap_getAllocationByteCountMethodID);
192}
193
sergeyvc1c54062016-10-19 18:47:26 -0700194jobject createBitmap(JNIEnv* env, Bitmap* bitmap,
sergeyvc69853c2016-10-07 14:14:09 -0700195 int bitmapCreateFlags, jbyteArray ninePatchChunk, jobject ninePatchInsets,
196 int density) {
197 bool isMutable = bitmapCreateFlags & kBitmapCreateFlag_Mutable;
198 bool isPremultiplied = bitmapCreateFlags & kBitmapCreateFlag_Premultiplied;
199 // The caller needs to have already set the alpha type properly, so the
200 // native SkBitmap stays in sync with the Java Bitmap.
sergeyvc1c54062016-10-19 18:47:26 -0700201 assert_premultiplied(bitmap->info(), isPremultiplied);
202 BitmapWrapper* bitmapWrapper = new BitmapWrapper(bitmap);
sergeyvc69853c2016-10-07 14:14:09 -0700203 jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
sergeyvc1c54062016-10-19 18:47:26 -0700204 reinterpret_cast<jlong>(bitmapWrapper), bitmap->width(), bitmap->height(), density,
205 isMutable, isPremultiplied, ninePatchChunk, ninePatchInsets);
sergeyvc69853c2016-10-07 14:14:09 -0700206
207 if (env->ExceptionCheck() != 0) {
208 ALOGE("*** Uncaught exception returned from Java call!\n");
209 env->ExceptionDescribe();
210 }
211 return obj;
212}
213
214void toSkBitmap(jlong bitmapHandle, SkBitmap* outBitmap) {
215 LocalScopedBitmap bitmap(bitmapHandle);
216 bitmap->getSkBitmap(outBitmap);
217}
218
sergeyvaed7f582016-10-14 16:30:21 -0700219Bitmap& toBitmap(JNIEnv* env, jobject bitmap) {
sergeyvc69853c2016-10-07 14:14:09 -0700220 SkASSERT(env);
221 SkASSERT(bitmap);
222 SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
223 jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
224 LocalScopedBitmap localBitmap(bitmapHandle);
sergeyvc1c54062016-10-19 18:47:26 -0700225 return localBitmap->bitmap();
sergeyvc69853c2016-10-07 14:14:09 -0700226}
227
sergeyv5fd2a1c2016-10-20 15:04:28 -0700228Bitmap& toBitmap(JNIEnv* env, jlong bitmapHandle) {
229 SkASSERT(env);
230 LocalScopedBitmap localBitmap(bitmapHandle);
231 return localBitmap->bitmap();
232}
233
sergeyvc69853c2016-10-07 14:14:09 -0700234} // namespace bitmap
235
236} // namespace android
237
238using namespace android;
239using namespace android::bitmap;
240
Chris Craik32054b02014-05-09 13:58:56 -0700241///////////////////////////////////////////////////////////////////////////////
242// Conversions to/from SkColor, for get/setPixels, and the create method, which
243// is basically like setPixels
244
245typedef void (*FromColorProc)(void* dst, const SkColor src[], int width,
246 int x, int y);
247
Romain Guy9505a652016-12-14 09:43:50 -0800248static void FromColor_F16(void* dst, const SkColor src[], int width,
249 int, int) {
250 uint64_t* d = (uint64_t*)dst;
251
252 for (int i = 0; i < width; i++) {
253 *d++ = SkColor4f::FromColor(*src++).premul().toF16();
254 }
255}
256
257static void FromColor_F16_Raw(void* dst, const SkColor src[], int width,
258 int, int) {
259 uint64_t* d = (uint64_t*)dst;
260
261 for (int i = 0; i < width; i++) {
262 const float* color = SkColor4f::FromColor(*src++).vec();
263 uint16_t* scratch = reinterpret_cast<uint16_t*>(d++);
264 for (int i = 0; i < 4; ++i) {
265 scratch[i] = SkFloatToHalf(color[i]);
266 }
267 }
268}
269
Chris Craik32054b02014-05-09 13:58:56 -0700270static void FromColor_D32(void* dst, const SkColor src[], int width,
271 int, int) {
272 SkPMColor* d = (SkPMColor*)dst;
273
274 for (int i = 0; i < width; i++) {
275 *d++ = SkPreMultiplyColor(*src++);
276 }
277}
278
279static void FromColor_D32_Raw(void* dst, const SkColor src[], int width,
280 int, int) {
Dan Albert46d84442014-11-18 16:07:51 -0800281 // Needed to thwart the unreachable code detection from clang.
282 static const bool sk_color_ne_zero = SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER;
283
Chris Craik32054b02014-05-09 13:58:56 -0700284 // SkColor's ordering may be different from SkPMColor
Dan Albert46d84442014-11-18 16:07:51 -0800285 if (sk_color_ne_zero) {
Chris Craik32054b02014-05-09 13:58:56 -0700286 memcpy(dst, src, width * sizeof(SkColor));
287 return;
288 }
289
290 // order isn't same, repack each pixel manually
291 SkPMColor* d = (SkPMColor*)dst;
292 for (int i = 0; i < width; i++) {
293 SkColor c = *src++;
294 *d++ = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
295 SkColorGetG(c), SkColorGetB(c));
296 }
297}
298
299static void FromColor_D565(void* dst, const SkColor src[], int width,
300 int x, int y) {
301 uint16_t* d = (uint16_t*)dst;
302
303 DITHER_565_SCAN(y);
304 for (int stop = x + width; x < stop; x++) {
305 SkColor c = *src++;
306 *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c),
307 DITHER_VALUE(x));
308 }
309}
310
311static void FromColor_D4444(void* dst, const SkColor src[], int width,
312 int x, int y) {
313 SkPMColor16* d = (SkPMColor16*)dst;
314
315 DITHER_4444_SCAN(y);
316 for (int stop = x + width; x < stop; x++) {
317 SkPMColor pmc = SkPreMultiplyColor(*src++);
318 *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
319// *d++ = SkPixel32ToPixel4444(pmc);
320 }
321}
322
323static void FromColor_D4444_Raw(void* dst, const SkColor src[], int width,
324 int x, int y) {
325 SkPMColor16* d = (SkPMColor16*)dst;
326
327 DITHER_4444_SCAN(y);
328 for (int stop = x + width; x < stop; x++) {
329 SkColor c = *src++;
330
331 // SkPMColor is used because the ordering is ARGB32, even though the target actually premultiplied
332 SkPMColor pmc = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
333 SkColorGetG(c), SkColorGetB(c));
334 *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
335// *d++ = SkPixel32ToPixel4444(pmc);
336 }
337}
338
Chris Craik6260b222015-07-24 15:17:29 -0700339static void FromColor_DA8(void* dst, const SkColor src[], int width, int x, int y) {
340 uint8_t* d = (uint8_t*)dst;
341
342 for (int stop = x + width; x < stop; x++) {
343 *d++ = SkColorGetA(*src++);
344 }
345}
346
Chris Craik32054b02014-05-09 13:58:56 -0700347// can return NULL
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400348static FromColorProc ChooseFromColorProc(const SkBitmap& bitmap) {
349 switch (bitmap.colorType()) {
350 case kN32_SkColorType:
351 return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D32 : FromColor_D32_Raw;
352 case kARGB_4444_SkColorType:
353 return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D4444 :
354 FromColor_D4444_Raw;
355 case kRGB_565_SkColorType:
Chris Craik32054b02014-05-09 13:58:56 -0700356 return FromColor_D565;
Chris Craik6260b222015-07-24 15:17:29 -0700357 case kAlpha_8_SkColorType:
358 return FromColor_DA8;
Romain Guy9505a652016-12-14 09:43:50 -0800359 case kRGBA_F16_SkColorType:
360 return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_F16 : FromColor_F16_Raw;
Chris Craik32054b02014-05-09 13:58:56 -0700361 default:
362 break;
363 }
364 return NULL;
365}
366
367bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride,
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400368 int x, int y, int width, int height, const SkBitmap& dstBitmap) {
Chris Craik32054b02014-05-09 13:58:56 -0700369 SkAutoLockPixels alp(dstBitmap);
370 void* dst = dstBitmap.getPixels();
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400371 FromColorProc proc = ChooseFromColorProc(dstBitmap);
Chris Craik32054b02014-05-09 13:58:56 -0700372
373 if (NULL == dst || NULL == proc) {
374 return false;
375 }
376
377 const jint* array = env->GetIntArrayElements(srcColors, NULL);
378 const SkColor* src = (const SkColor*)array + srcOffset;
379
380 // reset to to actual choice from caller
381 dst = dstBitmap.getAddr(x, y);
382 // now copy/convert each scanline
383 for (int y = 0; y < height; y++) {
384 proc(dst, src, width, x, y);
385 src += srcStride;
386 dst = (char*)dst + dstBitmap.rowBytes();
387 }
388
389 dstBitmap.notifyPixelsChanged();
390
Romain Guy9505a652016-12-14 09:43:50 -0800391 env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array), JNI_ABORT);
Chris Craik32054b02014-05-09 13:58:56 -0700392 return true;
393}
394
395//////////////////// ToColor procs
396
397typedef void (*ToColorProc)(SkColor dst[], const void* src, int width,
398 SkColorTable*);
399
Romain Guy9505a652016-12-14 09:43:50 -0800400static void ToColor_F16_Alpha(SkColor dst[], const void* src, int width,
401 SkColorTable*) {
402 SkASSERT(width > 0);
403 uint64_t* s = (uint64_t*)src;
404 do {
405 *dst++ = SkPM4f::FromF16((const uint16_t*) s++).unpremul().toSkColor();
406 } while (--width != 0);
407}
408
409static void ToColor_F16_Raw(SkColor dst[], const void* src, int width,
410 SkColorTable*) {
411 SkASSERT(width > 0);
412 uint64_t* s = (uint64_t*)src;
413 do {
414 *dst++ = Sk4f_toS32(swizzle_rb(SkHalfToFloat_finite_ftz(*s++)));
415 } while (--width != 0);
416}
417
Chris Craik32054b02014-05-09 13:58:56 -0700418static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width,
419 SkColorTable*) {
420 SkASSERT(width > 0);
421 const SkPMColor* s = (const SkPMColor*)src;
422 do {
423 *dst++ = SkUnPreMultiply::PMColorToColor(*s++);
424 } while (--width != 0);
425}
426
427static void ToColor_S32_Raw(SkColor dst[], const void* src, int width,
428 SkColorTable*) {
429 SkASSERT(width > 0);
430 const SkPMColor* s = (const SkPMColor*)src;
431 do {
432 SkPMColor c = *s++;
433 *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
434 SkGetPackedG32(c), SkGetPackedB32(c));
435 } while (--width != 0);
436}
437
438static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width,
439 SkColorTable*) {
440 SkASSERT(width > 0);
441 const SkPMColor* s = (const SkPMColor*)src;
442 do {
443 SkPMColor c = *s++;
444 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
445 SkGetPackedB32(c));
446 } while (--width != 0);
447}
448
449static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width,
450 SkColorTable*) {
451 SkASSERT(width > 0);
452 const SkPMColor16* s = (const SkPMColor16*)src;
453 do {
454 *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++));
455 } while (--width != 0);
456}
457
458static void ToColor_S4444_Raw(SkColor dst[], const void* src, int width,
459 SkColorTable*) {
460 SkASSERT(width > 0);
461 const SkPMColor16* s = (const SkPMColor16*)src;
462 do {
463 SkPMColor c = SkPixel4444ToPixel32(*s++);
464 *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
465 SkGetPackedG32(c), SkGetPackedB32(c));
466 } while (--width != 0);
467}
468
469static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width,
470 SkColorTable*) {
471 SkASSERT(width > 0);
472 const SkPMColor16* s = (const SkPMColor16*)src;
473 do {
474 SkPMColor c = SkPixel4444ToPixel32(*s++);
475 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
476 SkGetPackedB32(c));
477 } while (--width != 0);
478}
479
480static void ToColor_S565(SkColor dst[], const void* src, int width,
481 SkColorTable*) {
482 SkASSERT(width > 0);
483 const uint16_t* s = (const uint16_t*)src;
484 do {
485 uint16_t c = *s++;
486 *dst++ = SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c),
487 SkPacked16ToB32(c));
488 } while (--width != 0);
489}
490
491static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width,
492 SkColorTable* ctable) {
493 SkASSERT(width > 0);
494 const uint8_t* s = (const uint8_t*)src;
Mike Reed71487eb2014-11-19 16:13:20 -0500495 const SkPMColor* colors = ctable->readColors();
Chris Craik32054b02014-05-09 13:58:56 -0700496 do {
497 *dst++ = SkUnPreMultiply::PMColorToColor(colors[*s++]);
498 } while (--width != 0);
Chris Craik32054b02014-05-09 13:58:56 -0700499}
500
501static void ToColor_SI8_Raw(SkColor dst[], const void* src, int width,
502 SkColorTable* ctable) {
503 SkASSERT(width > 0);
504 const uint8_t* s = (const uint8_t*)src;
Mike Reed71487eb2014-11-19 16:13:20 -0500505 const SkPMColor* colors = ctable->readColors();
Chris Craik32054b02014-05-09 13:58:56 -0700506 do {
507 SkPMColor c = colors[*s++];
508 *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
509 SkGetPackedG32(c), SkGetPackedB32(c));
510 } while (--width != 0);
Chris Craik32054b02014-05-09 13:58:56 -0700511}
512
513static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width,
514 SkColorTable* ctable) {
515 SkASSERT(width > 0);
516 const uint8_t* s = (const uint8_t*)src;
Mike Reed71487eb2014-11-19 16:13:20 -0500517 const SkPMColor* colors = ctable->readColors();
Chris Craik32054b02014-05-09 13:58:56 -0700518 do {
519 SkPMColor c = colors[*s++];
520 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
521 SkGetPackedB32(c));
522 } while (--width != 0);
Chris Craik32054b02014-05-09 13:58:56 -0700523}
524
Chris Craik6260b222015-07-24 15:17:29 -0700525static void ToColor_SA8(SkColor dst[], const void* src, int width, SkColorTable*) {
526 SkASSERT(width > 0);
527 const uint8_t* s = (const uint8_t*)src;
528 do {
529 uint8_t c = *s++;
530 *dst++ = SkColorSetARGB(c, c, c, c);
531 } while (--width != 0);
532}
533
Chris Craik32054b02014-05-09 13:58:56 -0700534// can return NULL
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400535static ToColorProc ChooseToColorProc(const SkBitmap& src) {
Mike Reedb9330552014-06-16 17:31:48 -0400536 switch (src.colorType()) {
537 case kN32_SkColorType:
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400538 switch (src.alphaType()) {
539 case kOpaque_SkAlphaType:
540 return ToColor_S32_Opaque;
541 case kPremul_SkAlphaType:
542 return ToColor_S32_Alpha;
543 case kUnpremul_SkAlphaType:
544 return ToColor_S32_Raw;
545 default:
546 return NULL;
547 }
Mike Reedb9330552014-06-16 17:31:48 -0400548 case kARGB_4444_SkColorType:
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400549 switch (src.alphaType()) {
550 case kOpaque_SkAlphaType:
551 return ToColor_S4444_Opaque;
552 case kPremul_SkAlphaType:
553 return ToColor_S4444_Alpha;
554 case kUnpremul_SkAlphaType:
555 return ToColor_S4444_Raw;
556 default:
557 return NULL;
558 }
Mike Reedb9330552014-06-16 17:31:48 -0400559 case kRGB_565_SkColorType:
Chris Craik32054b02014-05-09 13:58:56 -0700560 return ToColor_S565;
Mike Reedb9330552014-06-16 17:31:48 -0400561 case kIndex_8_SkColorType:
Chris Craik32054b02014-05-09 13:58:56 -0700562 if (src.getColorTable() == NULL) {
563 return NULL;
564 }
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400565 switch (src.alphaType()) {
566 case kOpaque_SkAlphaType:
567 return ToColor_SI8_Opaque;
568 case kPremul_SkAlphaType:
569 return ToColor_SI8_Alpha;
570 case kUnpremul_SkAlphaType:
571 return ToColor_SI8_Raw;
572 default:
573 return NULL;
574 }
Chris Craik6260b222015-07-24 15:17:29 -0700575 case kAlpha_8_SkColorType:
576 return ToColor_SA8;
Romain Guy9505a652016-12-14 09:43:50 -0800577 case kRGBA_F16_SkColorType:
578 switch (src.alphaType()) {
579 case kOpaque_SkAlphaType:
580 return ToColor_F16_Raw;
581 case kPremul_SkAlphaType:
582 return ToColor_F16_Alpha;
583 case kUnpremul_SkAlphaType:
584 return ToColor_F16_Raw;
585 default:
586 return NULL;
587 }
Chris Craik32054b02014-05-09 13:58:56 -0700588 default:
589 break;
590 }
591 return NULL;
592}
593
594///////////////////////////////////////////////////////////////////////////////
595///////////////////////////////////////////////////////////////////////////////
596
597static int getPremulBitmapCreateFlags(bool isMutable) {
sergeyvc69853c2016-10-07 14:14:09 -0700598 int flags = android::bitmap::kBitmapCreateFlag_Premultiplied;
599 if (isMutable) flags |= android::bitmap::kBitmapCreateFlag_Mutable;
Chris Craik32054b02014-05-09 13:58:56 -0700600 return flags;
601}
602
603static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
604 jint offset, jint stride, jint width, jint height,
605 jint configHandle, jboolean isMutable) {
Mike Reed1103b322014-07-08 12:36:44 -0400606 SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700607 if (NULL != jColors) {
608 size_t n = env->GetArrayLength(jColors);
609 if (n < SkAbs32(stride) * (size_t)height) {
610 doThrowAIOOBE(env);
611 return NULL;
612 }
613 }
614
615 // ARGB_4444 is a deprecated format, convert automatically to 8888
Mike Reedb9330552014-06-16 17:31:48 -0400616 if (colorType == kARGB_4444_SkColorType) {
617 colorType = kN32_SkColorType;
Chris Craik32054b02014-05-09 13:58:56 -0700618 }
619
620 SkBitmap bitmap;
Romain Guy253f2c22016-09-28 17:34:42 -0700621 bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType,
Romain Guy9505a652016-12-14 09:43:50 -0800622 GraphicsJNI::colorSpaceForType(colorType)));
Chris Craik32054b02014-05-09 13:58:56 -0700623
sergeyvc1c54062016-10-19 18:47:26 -0700624 sk_sp<Bitmap> nativeBitmap = Bitmap::allocateHeapBitmap(&bitmap, NULL);
John Reckf29ed282015-04-07 07:32:03 -0700625 if (!nativeBitmap) {
Chris Craik32054b02014-05-09 13:58:56 -0700626 return NULL;
627 }
628
629 if (jColors != NULL) {
Romain Guy9505a652016-12-14 09:43:50 -0800630 GraphicsJNI::SetPixels(env, jColors, offset, stride, 0, 0, width, height, bitmap);
Chris Craik32054b02014-05-09 13:58:56 -0700631 }
632
sergeyvc36bd6c2016-10-11 15:49:16 -0700633 return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable));
Chris Craik32054b02014-05-09 13:58:56 -0700634}
635
636static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle,
637 jint dstConfigHandle, jboolean isMutable) {
John Reckf29ed282015-04-07 07:32:03 -0700638 SkBitmap src;
sergeyvc1c54062016-10-19 18:47:26 -0700639 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
sergeyv05126d12016-12-15 19:50:15 -0800640 if (dstConfigHandle == GraphicsJNI::hardwareLegacyBitmapConfig()) {
641 sk_sp<Bitmap> bitmap(Bitmap::allocateHardwareBitmap(src));
642 if (!bitmap.get()) {
643 return NULL;
644 }
645 return createBitmap(env, bitmap.release(), kBitmapCreateFlag_None);
646 }
647
Mike Reed1103b322014-07-08 12:36:44 -0400648 SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
sergeyv45082182016-09-29 18:25:40 -0700649 SkBitmap result;
650 HeapAllocator allocator;
Chris Craik32054b02014-05-09 13:58:56 -0700651
John Reckf29ed282015-04-07 07:32:03 -0700652 if (!src.copyTo(&result, dstCT, &allocator)) {
Chris Craik32054b02014-05-09 13:58:56 -0700653 return NULL;
654 }
sergeyvc1c54062016-10-19 18:47:26 -0700655 auto bitmap = allocator.getStorageObjAndReset();
656 return createBitmap(env, bitmap, getPremulBitmapCreateFlags(isMutable));
Chris Craik32054b02014-05-09 13:58:56 -0700657}
658
sergeyvc1c54062016-10-19 18:47:26 -0700659static Bitmap* Bitmap_copyAshmemImpl(JNIEnv* env, SkBitmap& src, SkColorType& dstCT) {
Riley Andrews721ae5f2015-05-11 16:08:22 -0700660 SkBitmap result;
661
662 AshmemPixelAllocator allocator(env);
Winsona5fdde92016-04-14 15:27:15 -0700663 if (!src.copyTo(&result, dstCT, &allocator)) {
Riley Andrews721ae5f2015-05-11 16:08:22 -0700664 return NULL;
665 }
sergeyvc1c54062016-10-19 18:47:26 -0700666 auto bitmap = allocator.getStorageObjAndReset();
667 bitmap->setImmutable();
668 return bitmap;
Winsona5fdde92016-04-14 15:27:15 -0700669}
670
671static jobject Bitmap_copyAshmem(JNIEnv* env, jobject, jlong srcHandle) {
672 SkBitmap src;
sergeyvc1c54062016-10-19 18:47:26 -0700673 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
Winsona5fdde92016-04-14 15:27:15 -0700674 SkColorType dstCT = src.colorType();
sergeyvc1c54062016-10-19 18:47:26 -0700675 auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
676 jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
Winsona5fdde92016-04-14 15:27:15 -0700677 return ret;
678}
679
680static jobject Bitmap_copyAshmemConfig(JNIEnv* env, jobject, jlong srcHandle, jint dstConfigHandle) {
681 SkBitmap src;
sergeyvc1c54062016-10-19 18:47:26 -0700682 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
Winsona5fdde92016-04-14 15:27:15 -0700683 SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
sergeyvc1c54062016-10-19 18:47:26 -0700684 auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
685 jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
Riley Andrews721ae5f2015-05-11 16:08:22 -0700686 return ret;
687}
688
sergeyvc1c54062016-10-19 18:47:26 -0700689static void Bitmap_destruct(BitmapWrapper* bitmap) {
sergeyvc69853c2016-10-07 14:14:09 -0700690 delete bitmap;
Chris Craik32054b02014-05-09 13:58:56 -0700691}
692
Richard Uhler775873a2015-12-29 12:37:39 -0800693static jlong Bitmap_getNativeFinalizer(JNIEnv*, jobject) {
694 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Bitmap_destruct));
695}
696
Chris Craik32054b02014-05-09 13:58:56 -0700697static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700698 LocalScopedBitmap bitmap(bitmapHandle);
699 bitmap->freePixels();
Chris Craik32054b02014-05-09 13:58:56 -0700700 return JNI_TRUE;
701}
702
703static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
sergeyv45082182016-09-29 18:25:40 -0700704 jint width, jint height, jint configHandle, jboolean requestPremul) {
John Reckf29ed282015-04-07 07:32:03 -0700705 LocalScopedBitmap bitmap(bitmapHandle);
sergeyvc69853c2016-10-07 14:14:09 -0700706 bitmap->assertValid();
Mike Reed1103b322014-07-08 12:36:44 -0400707 SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
Leon Scroggins III17a8bfc2014-06-03 16:15:15 -0400708
709 // ARGB_4444 is a deprecated format, convert automatically to 8888
710 if (colorType == kARGB_4444_SkColorType) {
711 colorType = kN32_SkColorType;
712 }
sergeyv45082182016-09-29 18:25:40 -0700713 size_t requestedSize = width * height * SkColorTypeBytesPerPixel(colorType);
714 if (requestedSize > bitmap->getAllocationByteCount()) {
Chris Craik32054b02014-05-09 13:58:56 -0700715 // done in native as there's no way to get BytesPerPixel in Java
716 doThrowIAE(env, "Bitmap not large enough to support new configuration");
717 return;
718 }
Leon Scroggins III17a8bfc2014-06-03 16:15:15 -0400719 SkAlphaType alphaType;
John Reckf29ed282015-04-07 07:32:03 -0700720 if (bitmap->info().colorType() != kRGB_565_SkColorType
721 && bitmap->info().alphaType() == kOpaque_SkAlphaType) {
Leon Scroggins III17a8bfc2014-06-03 16:15:15 -0400722 // If the original bitmap was set to opaque, keep that setting, unless it
723 // was 565, which is required to be opaque.
724 alphaType = kOpaque_SkAlphaType;
725 } else {
726 // Otherwise respect the premultiplied request.
727 alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
728 }
sergeyvaed7f582016-10-14 16:30:21 -0700729 bitmap->bitmap().reconfigure(SkImageInfo::Make(width, height, colorType, alphaType,
sergeyv7d5219f2016-11-03 16:18:16 -0700730 sk_ref_sp(bitmap->info().colorSpace())));
Chris Craik32054b02014-05-09 13:58:56 -0700731}
732
733// These must match the int values in Bitmap.java
734enum JavaEncodeFormat {
735 kJPEG_JavaEncodeFormat = 0,
736 kPNG_JavaEncodeFormat = 1,
737 kWEBP_JavaEncodeFormat = 2
738};
739
740static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle,
741 jint format, jint quality,
742 jobject jstream, jbyteArray jstorage) {
Hal Canary10219fb2016-11-23 20:41:22 -0500743 SkEncodedImageFormat fm;
Chris Craik32054b02014-05-09 13:58:56 -0700744 switch (format) {
745 case kJPEG_JavaEncodeFormat:
Hal Canary10219fb2016-11-23 20:41:22 -0500746 fm = SkEncodedImageFormat::kJPEG;
Chris Craik32054b02014-05-09 13:58:56 -0700747 break;
748 case kPNG_JavaEncodeFormat:
Hal Canary10219fb2016-11-23 20:41:22 -0500749 fm = SkEncodedImageFormat::kPNG;
Chris Craik32054b02014-05-09 13:58:56 -0700750 break;
751 case kWEBP_JavaEncodeFormat:
Hal Canary10219fb2016-11-23 20:41:22 -0500752 fm = SkEncodedImageFormat::kWEBP;
Chris Craik32054b02014-05-09 13:58:56 -0700753 break;
754 default:
755 return JNI_FALSE;
756 }
757
Hal Canary10219fb2016-11-23 20:41:22 -0500758 LocalScopedBitmap bitmap(bitmapHandle);
John Reckf29ed282015-04-07 07:32:03 -0700759 if (!bitmap.valid()) {
760 return JNI_FALSE;
761 }
762
John Reckf29ed282015-04-07 07:32:03 -0700763 std::unique_ptr<SkWStream> strm(CreateJavaOutputStreamAdaptor(env, jstream, jstorage));
764 if (!strm.get()) {
765 return JNI_FALSE;
766 }
Chris Craik32054b02014-05-09 13:58:56 -0700767
Hal Canary10219fb2016-11-23 20:41:22 -0500768 SkBitmap skbitmap;
769 bitmap->getSkBitmap(&skbitmap);
770 return SkEncodeImage(strm.get(), skbitmap, fm, quality) ? JNI_TRUE : JNI_FALSE;
Chris Craik32054b02014-05-09 13:58:56 -0700771}
772
773static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) {
John Reckf29ed282015-04-07 07:32:03 -0700774 LocalScopedBitmap bitmap(bitmapHandle);
775 SkBitmap skBitmap;
776 bitmap->getSkBitmap(&skBitmap);
777 skBitmap.eraseColor(color);
Chris Craik32054b02014-05-09 13:58:56 -0700778}
779
780static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700781 LocalScopedBitmap bitmap(bitmapHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700782 return static_cast<jint>(bitmap->rowBytes());
783}
784
785static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700786 LocalScopedBitmap bitmap(bitmapHandle);
sergeyv15a10852016-12-27 14:32:03 -0800787 if (bitmap->isHardware()) {
sergeyv19b4b012016-12-13 16:06:00 -0800788 return GraphicsJNI::hardwareLegacyBitmapConfig();
789 }
John Reckf29ed282015-04-07 07:32:03 -0700790 return GraphicsJNI::colorTypeToLegacyBitmapConfig(bitmap->info().colorType());
Chris Craik32054b02014-05-09 13:58:56 -0700791}
792
793static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700794 LocalScopedBitmap bitmap(bitmapHandle);
sergeyvc69853c2016-10-07 14:14:09 -0700795 return static_cast<jint>(bitmap->getGenerationID());
Chris Craik32054b02014-05-09 13:58:56 -0700796}
797
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400798static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700799 LocalScopedBitmap bitmap(bitmapHandle);
800 if (bitmap->info().alphaType() == kPremul_SkAlphaType) {
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400801 return JNI_TRUE;
802 }
803 return JNI_FALSE;
804}
805
Chris Craik32054b02014-05-09 13:58:56 -0700806static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700807 LocalScopedBitmap bitmap(bitmapHandle);
808 return !bitmap->info().isOpaque() ? JNI_TRUE : JNI_FALSE;
Chris Craik32054b02014-05-09 13:58:56 -0700809}
810
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400811static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle,
812 jboolean hasAlpha, jboolean requestPremul) {
John Reckf29ed282015-04-07 07:32:03 -0700813 LocalScopedBitmap bitmap(bitmapHandle);
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400814 if (hasAlpha) {
John Reck0781a2f2015-05-27 16:29:17 -0700815 bitmap->setAlphaType(
John Reckf29ed282015-04-07 07:32:03 -0700816 requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
Chris Craik32054b02014-05-09 13:58:56 -0700817 } else {
John Reck0781a2f2015-05-27 16:29:17 -0700818 bitmap->setAlphaType(kOpaque_SkAlphaType);
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400819 }
820}
821
822static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
823 jboolean isPremul) {
John Reckf29ed282015-04-07 07:32:03 -0700824 LocalScopedBitmap bitmap(bitmapHandle);
825 if (!bitmap->info().isOpaque()) {
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400826 if (isPremul) {
John Reck0781a2f2015-05-27 16:29:17 -0700827 bitmap->setAlphaType(kPremul_SkAlphaType);
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400828 } else {
John Reck0781a2f2015-05-27 16:29:17 -0700829 bitmap->setAlphaType(kUnpremul_SkAlphaType);
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400830 }
Chris Craik32054b02014-05-09 13:58:56 -0700831 }
832}
833
834static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700835 LocalScopedBitmap bitmap(bitmapHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700836 return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE;
837}
838
839static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle,
840 jboolean hasMipMap) {
John Reckf29ed282015-04-07 07:32:03 -0700841 LocalScopedBitmap bitmap(bitmapHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700842 bitmap->setHasHardwareMipMap(hasMipMap);
843}
844
845///////////////////////////////////////////////////////////////////////////////
846
847static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
848 if (parcel == NULL) {
849 SkDebugf("-------- unparcel parcel is NULL\n");
850 return NULL;
851 }
852
853 android::Parcel* p = android::parcelForJavaObject(env, parcel);
854
Mike Reedb9330552014-06-16 17:31:48 -0400855 const bool isMutable = p->readInt32() != 0;
856 const SkColorType colorType = (SkColorType)p->readInt32();
857 const SkAlphaType alphaType = (SkAlphaType)p->readInt32();
Romain Guy253f2c22016-09-28 17:34:42 -0700858 const bool isSRGB = p->readInt32() != 0;
Mike Reedb9330552014-06-16 17:31:48 -0400859 const int width = p->readInt32();
860 const int height = p->readInt32();
861 const int rowBytes = p->readInt32();
862 const int density = p->readInt32();
Chris Craik32054b02014-05-09 13:58:56 -0700863
Mike Reedb9330552014-06-16 17:31:48 -0400864 if (kN32_SkColorType != colorType &&
Romain Guy9505a652016-12-14 09:43:50 -0800865 kRGBA_F16_SkColorType != colorType &&
Mike Reedb9330552014-06-16 17:31:48 -0400866 kRGB_565_SkColorType != colorType &&
867 kARGB_4444_SkColorType != colorType &&
868 kIndex_8_SkColorType != colorType &&
869 kAlpha_8_SkColorType != colorType) {
870 SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType);
Chris Craik32054b02014-05-09 13:58:56 -0700871 return NULL;
872 }
873
Leon Scroggins IIIec419e02015-03-11 13:12:06 -0400874 std::unique_ptr<SkBitmap> bitmap(new SkBitmap);
Chris Craik32054b02014-05-09 13:58:56 -0700875
Romain Guy9505a652016-12-14 09:43:50 -0800876 sk_sp<SkColorSpace> colorSpace;
877 if (kRGBA_F16_SkColorType == colorType) {
878 colorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGBLinear_Named);
879 } else {
880 colorSpace = isSRGB ? SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named) : nullptr;
881 }
882
883 if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType, colorSpace),
884 rowBytes)) {
Leon Scroggins IIIec419e02015-03-11 13:12:06 -0400885 return NULL;
886 }
Chris Craik32054b02014-05-09 13:58:56 -0700887
888 SkColorTable* ctable = NULL;
Mike Reedb9330552014-06-16 17:31:48 -0400889 if (colorType == kIndex_8_SkColorType) {
Chris Craik32054b02014-05-09 13:58:56 -0700890 int count = p->readInt32();
Leon Scroggins IIIec419e02015-03-11 13:12:06 -0400891 if (count < 0 || count > 256) {
892 // The data is corrupt, since SkColorTable enforces a value between 0 and 256,
893 // inclusive.
894 return NULL;
895 }
Chris Craik32054b02014-05-09 13:58:56 -0700896 if (count > 0) {
897 size_t size = count * sizeof(SkPMColor);
898 const SkPMColor* src = (const SkPMColor*)p->readInplace(size);
Leon Scroggins IIIec419e02015-03-11 13:12:06 -0400899 if (src == NULL) {
900 return NULL;
901 }
Chris Craik32054b02014-05-09 13:58:56 -0700902 ctable = new SkColorTable(src, count);
903 }
904 }
905
Jeff Browna316c5d2015-06-05 15:14:06 -0700906 // Read the bitmap blob.
907 size_t size = bitmap->getSize();
908 android::Parcel::ReadableBlob blob;
909 android::status_t status = p->readBlob(size, &blob);
910 if (status) {
Chris Craik32054b02014-05-09 13:58:56 -0700911 SkSafeUnref(ctable);
Jeff Browna316c5d2015-06-05 15:14:06 -0700912 doThrowRE(env, "Could not read bitmap blob.");
Chris Craik32054b02014-05-09 13:58:56 -0700913 return NULL;
914 }
915
Jeff Browna316c5d2015-06-05 15:14:06 -0700916 // Map the bitmap in place from the ashmem region if possible otherwise copy.
sergeyvc1c54062016-10-19 18:47:26 -0700917 sk_sp<Bitmap> nativeBitmap;
Riley Andrews8cee7c12015-11-01 23:36:04 -0800918 if (blob.fd() >= 0 && (blob.isMutable() || !isMutable) && (size >= ASHMEM_BITMAP_MIN_SIZE)) {
Jeff Browna316c5d2015-06-05 15:14:06 -0700919#if DEBUG_PARCEL
920 ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob "
921 "(fds %s)",
922 isMutable ? "mutable" : "immutable",
923 blob.isMutable() ? "mutable" : "immutable",
924 p->allowFds() ? "allowed" : "forbidden");
925#endif
926 // Dup the file descriptor so we can keep a reference to it after the Parcel
927 // is disposed.
928 int dupFd = dup(blob.fd());
929 if (dupFd < 0) {
Erik Wolsheimer211abad2015-11-13 11:54:47 -0800930 ALOGE("Error allocating dup fd. Error:%d", errno);
Jeff Browna316c5d2015-06-05 15:14:06 -0700931 blob.release();
932 SkSafeUnref(ctable);
933 doThrowRE(env, "Could not allocate dup blob fd.");
934 return NULL;
935 }
936
937 // Map the pixels in place and take ownership of the ashmem region.
sergeyvc1c54062016-10-19 18:47:26 -0700938 nativeBitmap = sk_sp<Bitmap>(GraphicsJNI::mapAshmemBitmap(env, bitmap.get(),
sergeyvc36bd6c2016-10-11 15:49:16 -0700939 ctable, dupFd, const_cast<void*>(blob.data()), size, !isMutable));
Jeff Browna316c5d2015-06-05 15:14:06 -0700940 SkSafeUnref(ctable);
941 if (!nativeBitmap) {
942 close(dupFd);
943 blob.release();
944 doThrowRE(env, "Could not allocate ashmem pixel ref.");
945 return NULL;
946 }
947
948 // Clear the blob handle, don't release it.
949 blob.clear();
950 } else {
951#if DEBUG_PARCEL
952 if (blob.fd() >= 0) {
953 ALOGD("Bitmap.createFromParcel: copied contents of mutable bitmap "
954 "from immutable blob (fds %s)",
955 p->allowFds() ? "allowed" : "forbidden");
956 } else {
957 ALOGD("Bitmap.createFromParcel: copied contents from %s blob "
958 "(fds %s)",
959 blob.isMutable() ? "mutable" : "immutable",
960 p->allowFds() ? "allowed" : "forbidden");
961 }
962#endif
963
964 // Copy the pixels into a new buffer.
sergeyvc1c54062016-10-19 18:47:26 -0700965 nativeBitmap = Bitmap::allocateHeapBitmap(bitmap.get(), ctable);
Jeff Browna316c5d2015-06-05 15:14:06 -0700966 SkSafeUnref(ctable);
967 if (!nativeBitmap) {
968 blob.release();
969 doThrowRE(env, "Could not allocate java pixel ref.");
970 return NULL;
971 }
972 bitmap->lockPixels();
973 memcpy(bitmap->getPixels(), blob.data(), size);
974 bitmap->unlockPixels();
975
976 // Release the blob handle.
977 blob.release();
Chris Craik32054b02014-05-09 13:58:56 -0700978 }
Chris Craik32054b02014-05-09 13:58:56 -0700979
sergeyvc36bd6c2016-10-11 15:49:16 -0700980 return createBitmap(env, nativeBitmap.release(),
Leon Scroggins IIIec419e02015-03-11 13:12:06 -0400981 getPremulBitmapCreateFlags(isMutable), NULL, NULL, density);
Chris Craik32054b02014-05-09 13:58:56 -0700982}
983
984static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
985 jlong bitmapHandle,
986 jboolean isMutable, jint density,
987 jobject parcel) {
Chris Craik32054b02014-05-09 13:58:56 -0700988 if (parcel == NULL) {
989 SkDebugf("------- writeToParcel null parcel\n");
990 return JNI_FALSE;
991 }
992
993 android::Parcel* p = android::parcelForJavaObject(env, parcel);
John Reckf29ed282015-04-07 07:32:03 -0700994 SkBitmap bitmap;
Riley Andrews39d7f302014-11-13 17:43:25 -0800995
sergeyvc1c54062016-10-19 18:47:26 -0700996 auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle);
997 bitmapWrapper->getSkBitmap(&bitmap);
Chris Craik32054b02014-05-09 13:58:56 -0700998
Mike Reedab12c1f2016-11-03 12:54:10 -0400999 sk_sp<SkColorSpace> sRGB = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
Romain Guy253f2c22016-09-28 17:34:42 -07001000 bool isSRGB = bitmap.colorSpace() == sRGB.get();
1001
Chris Craik32054b02014-05-09 13:58:56 -07001002 p->writeInt32(isMutable);
John Reckf29ed282015-04-07 07:32:03 -07001003 p->writeInt32(bitmap.colorType());
1004 p->writeInt32(bitmap.alphaType());
Romain Guy253f2c22016-09-28 17:34:42 -07001005 p->writeInt32(isSRGB); // TODO: We should write the color space (b/32072280)
John Reckf29ed282015-04-07 07:32:03 -07001006 p->writeInt32(bitmap.width());
1007 p->writeInt32(bitmap.height());
1008 p->writeInt32(bitmap.rowBytes());
Chris Craik32054b02014-05-09 13:58:56 -07001009 p->writeInt32(density);
1010
John Reckf29ed282015-04-07 07:32:03 -07001011 if (bitmap.colorType() == kIndex_8_SkColorType) {
Leon Scroggins III66ce1c32016-02-02 11:11:55 -05001012 // The bitmap needs to be locked to access its color table.
1013 SkAutoLockPixels alp(bitmap);
John Reckf29ed282015-04-07 07:32:03 -07001014 SkColorTable* ctable = bitmap.getColorTable();
Chris Craik32054b02014-05-09 13:58:56 -07001015 if (ctable != NULL) {
1016 int count = ctable->count();
1017 p->writeInt32(count);
1018 memcpy(p->writeInplace(count * sizeof(SkPMColor)),
Mike Reed71487eb2014-11-19 16:13:20 -05001019 ctable->readColors(), count * sizeof(SkPMColor));
Chris Craik32054b02014-05-09 13:58:56 -07001020 } else {
1021 p->writeInt32(0); // indicate no ctable
1022 }
1023 }
1024
Jeff Browna316c5d2015-06-05 15:14:06 -07001025 // Transfer the underlying ashmem region if we have one and it's immutable.
1026 android::status_t status;
sergeyvaed7f582016-10-14 16:30:21 -07001027 int fd = bitmapWrapper->bitmap().getAshmemFd();
Jeff Browna316c5d2015-06-05 15:14:06 -07001028 if (fd >= 0 && !isMutable && p->allowFds()) {
1029#if DEBUG_PARCEL
1030 ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as "
1031 "immutable blob (fds %s)",
1032 p->allowFds() ? "allowed" : "forbidden");
1033#endif
1034
1035 status = p->writeDupImmutableBlobFileDescriptor(fd);
1036 if (status) {
1037 doThrowRE(env, "Could not write bitmap blob file descriptor.");
Riley Andrews39d7f302014-11-13 17:43:25 -08001038 return JNI_FALSE;
1039 }
Jeff Browna316c5d2015-06-05 15:14:06 -07001040 return JNI_TRUE;
Riley Andrews39d7f302014-11-13 17:43:25 -08001041 }
Jeff Browna316c5d2015-06-05 15:14:06 -07001042
1043 // Copy the bitmap to a new blob.
1044 bool mutableCopy = isMutable;
1045#if DEBUG_PARCEL
1046 ALOGD("Bitmap.writeToParcel: copying %s bitmap into new %s blob (fds %s)",
1047 isMutable ? "mutable" : "immutable",
1048 mutableCopy ? "mutable" : "immutable",
1049 p->allowFds() ? "allowed" : "forbidden");
1050#endif
1051
1052 size_t size = bitmap.getSize();
1053 android::Parcel::WritableBlob blob;
1054 status = p->writeBlob(size, mutableCopy, &blob);
1055 if (status) {
1056 doThrowRE(env, "Could not copy bitmap to parcel blob.");
1057 return JNI_FALSE;
1058 }
1059
1060 bitmap.lockPixels();
1061 const void* pSrc = bitmap.getPixels();
1062 if (pSrc == NULL) {
1063 memset(blob.data(), 0, size);
1064 } else {
1065 memcpy(blob.data(), pSrc, size);
1066 }
1067 bitmap.unlockPixels();
1068
1069 blob.release();
Chris Craik32054b02014-05-09 13:58:56 -07001070 return JNI_TRUE;
1071}
1072
1073static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
1074 jlong srcHandle, jlong paintHandle,
1075 jintArray offsetXY) {
John Reckf29ed282015-04-07 07:32:03 -07001076 SkBitmap src;
sergeyvc1c54062016-10-19 18:47:26 -07001077 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -04001078 const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle);
Chris Craik32054b02014-05-09 13:58:56 -07001079 SkIPoint offset;
John Reckf29ed282015-04-07 07:32:03 -07001080 SkBitmap dst;
sergeyv45082182016-09-29 18:25:40 -07001081 HeapAllocator allocator;
Chris Craik32054b02014-05-09 13:58:56 -07001082
John Reckf29ed282015-04-07 07:32:03 -07001083 src.extractAlpha(&dst, paint, &allocator, &offset);
Chris Craik32054b02014-05-09 13:58:56 -07001084 // If Skia can't allocate pixels for destination bitmap, it resets
1085 // it, that is set its pixels buffer to NULL, and zero width and height.
John Reckf29ed282015-04-07 07:32:03 -07001086 if (dst.getPixels() == NULL && src.getPixels() != NULL) {
Chris Craik32054b02014-05-09 13:58:56 -07001087 doThrowOOME(env, "failed to allocate pixels for alpha");
1088 return NULL;
1089 }
1090 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
1091 int* array = env->GetIntArrayElements(offsetXY, NULL);
1092 array[0] = offset.fX;
1093 array[1] = offset.fY;
1094 env->ReleaseIntArrayElements(offsetXY, array, 0);
1095 }
1096
sergeyvc69853c2016-10-07 14:14:09 -07001097 return createBitmap(env, allocator.getStorageObjAndReset(),
John Reckf29ed282015-04-07 07:32:03 -07001098 getPremulBitmapCreateFlags(true));
Chris Craik32054b02014-05-09 13:58:56 -07001099}
1100
1101///////////////////////////////////////////////////////////////////////////////
1102
1103static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
Leon Scroggins III57ee6202014-06-04 18:51:07 -04001104 jint x, jint y) {
John Reckf29ed282015-04-07 07:32:03 -07001105 SkBitmap bitmap;
sergeyvc1c54062016-10-19 18:47:26 -07001106 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
John Reckf29ed282015-04-07 07:32:03 -07001107 SkAutoLockPixels alp(bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001108
John Reckf29ed282015-04-07 07:32:03 -07001109 ToColorProc proc = ChooseToColorProc(bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001110 if (NULL == proc) {
1111 return 0;
1112 }
John Reckf29ed282015-04-07 07:32:03 -07001113 const void* src = bitmap.getAddr(x, y);
Chris Craik32054b02014-05-09 13:58:56 -07001114 if (NULL == src) {
1115 return 0;
1116 }
1117
1118 SkColor dst[1];
John Reckf29ed282015-04-07 07:32:03 -07001119 proc(dst, src, 1, bitmap.getColorTable());
Chris Craik32054b02014-05-09 13:58:56 -07001120 return static_cast<jint>(dst[0]);
1121}
1122
1123static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,
1124 jintArray pixelArray, jint offset, jint stride,
Leon Scroggins III57ee6202014-06-04 18:51:07 -04001125 jint x, jint y, jint width, jint height) {
John Reckf29ed282015-04-07 07:32:03 -07001126 SkBitmap bitmap;
sergeyvc1c54062016-10-19 18:47:26 -07001127 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
John Reckf29ed282015-04-07 07:32:03 -07001128 SkAutoLockPixels alp(bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001129
John Reckf29ed282015-04-07 07:32:03 -07001130 ToColorProc proc = ChooseToColorProc(bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001131 if (NULL == proc) {
1132 return;
1133 }
John Reckf29ed282015-04-07 07:32:03 -07001134 const void* src = bitmap.getAddr(x, y);
Chris Craik32054b02014-05-09 13:58:56 -07001135 if (NULL == src) {
1136 return;
1137 }
1138
John Reckf29ed282015-04-07 07:32:03 -07001139 SkColorTable* ctable = bitmap.getColorTable();
Chris Craik32054b02014-05-09 13:58:56 -07001140 jint* dst = env->GetIntArrayElements(pixelArray, NULL);
1141 SkColor* d = (SkColor*)dst + offset;
1142 while (--height >= 0) {
1143 proc(d, src, width, ctable);
1144 d += stride;
John Reckf29ed282015-04-07 07:32:03 -07001145 src = (void*)((const char*)src + bitmap.rowBytes());
Chris Craik32054b02014-05-09 13:58:56 -07001146 }
1147 env->ReleaseIntArrayElements(pixelArray, dst, 0);
1148}
1149
1150///////////////////////////////////////////////////////////////////////////////
1151
1152static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle,
Leon Scroggins III57ee6202014-06-04 18:51:07 -04001153 jint x, jint y, jint colorHandle) {
John Reckf29ed282015-04-07 07:32:03 -07001154 SkBitmap bitmap;
sergeyvc1c54062016-10-19 18:47:26 -07001155 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001156 SkColor color = static_cast<SkColor>(colorHandle);
John Reckf29ed282015-04-07 07:32:03 -07001157 SkAutoLockPixels alp(bitmap);
1158 if (NULL == bitmap.getPixels()) {
Chris Craik32054b02014-05-09 13:58:56 -07001159 return;
1160 }
1161
John Reckf29ed282015-04-07 07:32:03 -07001162 FromColorProc proc = ChooseFromColorProc(bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001163 if (NULL == proc) {
1164 return;
1165 }
1166
John Reckf29ed282015-04-07 07:32:03 -07001167 proc(bitmap.getAddr(x, y), &color, 1, x, y);
1168 bitmap.notifyPixelsChanged();
Chris Craik32054b02014-05-09 13:58:56 -07001169}
1170
1171static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,
1172 jintArray pixelArray, jint offset, jint stride,
Leon Scroggins III57ee6202014-06-04 18:51:07 -04001173 jint x, jint y, jint width, jint height) {
John Reckf29ed282015-04-07 07:32:03 -07001174 SkBitmap bitmap;
sergeyvc1c54062016-10-19 18:47:26 -07001175 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001176 GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
John Reckf29ed282015-04-07 07:32:03 -07001177 x, y, width, height, bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001178}
1179
1180static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
1181 jlong bitmapHandle, jobject jbuffer) {
John Reckf29ed282015-04-07 07:32:03 -07001182 SkBitmap bitmap;
sergeyvc1c54062016-10-19 18:47:26 -07001183 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
John Reckf29ed282015-04-07 07:32:03 -07001184 SkAutoLockPixels alp(bitmap);
1185 const void* src = bitmap.getPixels();
Chris Craik32054b02014-05-09 13:58:56 -07001186
1187 if (NULL != src) {
1188 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
1189
1190 // the java side has already checked that buffer is large enough
John Reckf29ed282015-04-07 07:32:03 -07001191 memcpy(abp.pointer(), src, bitmap.getSize());
Chris Craik32054b02014-05-09 13:58:56 -07001192 }
1193}
1194
1195static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,
1196 jlong bitmapHandle, jobject jbuffer) {
John Reckf29ed282015-04-07 07:32:03 -07001197 SkBitmap bitmap;
sergeyvc1c54062016-10-19 18:47:26 -07001198 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
John Reckf29ed282015-04-07 07:32:03 -07001199 SkAutoLockPixels alp(bitmap);
1200 void* dst = bitmap.getPixels();
Chris Craik32054b02014-05-09 13:58:56 -07001201
1202 if (NULL != dst) {
1203 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);
1204 // the java side has already checked that buffer is large enough
John Reckf29ed282015-04-07 07:32:03 -07001205 memcpy(dst, abp.pointer(), bitmap.getSize());
1206 bitmap.notifyPixelsChanged();
Chris Craik32054b02014-05-09 13:58:56 -07001207 }
1208}
1209
Chris Craik795bd0f2016-12-16 15:22:31 -08001210static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle, jlong bm1Handle) {
John Reckf29ed282015-04-07 07:32:03 -07001211 SkBitmap bm0;
1212 SkBitmap bm1;
sergeyv1eabed32016-12-14 14:19:47 -08001213
1214 LocalScopedBitmap bitmap0(bm0Handle);
1215 LocalScopedBitmap bitmap1(bm1Handle);
1216
1217 // Paying the price for making Hardware Bitmap as Config:
1218 // later check for colorType will pass successfully,
1219 // because Hardware Config internally may be RGBA8888 or smth like that.
sergeyv15a10852016-12-27 14:32:03 -08001220 if (bitmap0->isHardware() != bitmap1->isHardware()) {
sergeyv1eabed32016-12-14 14:19:47 -08001221 return JNI_FALSE;
1222 }
1223
1224 bitmap0->bitmap().getSkBitmap(&bm0);
1225 bitmap1->bitmap().getSkBitmap(&bm1);
Chris Craik795bd0f2016-12-16 15:22:31 -08001226 if (bm0.width() != bm1.width()
1227 || bm0.height() != bm1.height()
1228 || bm0.colorType() != bm1.colorType()
1229 || bm0.alphaType() != bm1.alphaType()
1230 || !SkColorSpace::Equals(bm0.colorSpace(), bm1.colorSpace())) {
Chris Craik32054b02014-05-09 13:58:56 -07001231 return JNI_FALSE;
1232 }
1233
John Reckf29ed282015-04-07 07:32:03 -07001234 SkAutoLockPixels alp0(bm0);
1235 SkAutoLockPixels alp1(bm1);
Chris Craik32054b02014-05-09 13:58:56 -07001236
1237 // if we can't load the pixels, return false
John Reckf29ed282015-04-07 07:32:03 -07001238 if (NULL == bm0.getPixels() || NULL == bm1.getPixels()) {
Chris Craik32054b02014-05-09 13:58:56 -07001239 return JNI_FALSE;
1240 }
1241
John Reckf29ed282015-04-07 07:32:03 -07001242 if (bm0.colorType() == kIndex_8_SkColorType) {
1243 SkColorTable* ct0 = bm0.getColorTable();
1244 SkColorTable* ct1 = bm1.getColorTable();
Chris Craik32054b02014-05-09 13:58:56 -07001245 if (NULL == ct0 || NULL == ct1) {
1246 return JNI_FALSE;
1247 }
1248 if (ct0->count() != ct1->count()) {
1249 return JNI_FALSE;
1250 }
1251
Chris Craik32054b02014-05-09 13:58:56 -07001252 const size_t size = ct0->count() * sizeof(SkPMColor);
Mike Reed71487eb2014-11-19 16:13:20 -05001253 if (memcmp(ct0->readColors(), ct1->readColors(), size) != 0) {
Chris Craik32054b02014-05-09 13:58:56 -07001254 return JNI_FALSE;
1255 }
1256 }
1257
1258 // now compare each scanline. We can't do the entire buffer at once,
1259 // since we don't care about the pixel values that might extend beyond
1260 // the width (since the scanline might be larger than the logical width)
John Reckf29ed282015-04-07 07:32:03 -07001261 const int h = bm0.height();
1262 const size_t size = bm0.width() * bm0.bytesPerPixel();
Chris Craik32054b02014-05-09 13:58:56 -07001263 for (int y = 0; y < h; y++) {
henry.uh_chen53001ca2014-07-03 20:40:22 +08001264 // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config
1265 // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0
1266 // and bm1 both have pixel data() (have passed NULL == getPixels() check),
1267 // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE
1268 // to warn user those 2 unrecognized config bitmaps may be different.
John Reckf29ed282015-04-07 07:32:03 -07001269 void *bm0Addr = bm0.getAddr(0, y);
1270 void *bm1Addr = bm1.getAddr(0, y);
henry.uh_chen53001ca2014-07-03 20:40:22 +08001271
1272 if(bm0Addr == NULL || bm1Addr == NULL) {
1273 return JNI_FALSE;
1274 }
1275
1276 if (memcmp(bm0Addr, bm1Addr, size) != 0) {
Chris Craik32054b02014-05-09 13:58:56 -07001277 return JNI_FALSE;
1278 }
1279 }
1280 return JNI_TRUE;
1281}
1282
John Reck43871902016-08-01 14:39:24 -07001283static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapPtr) {
1284 LocalScopedBitmap bitmapHandle(bitmapPtr);
1285 if (!bitmapHandle.valid()) return;
sergeyvec4a4b12016-10-20 18:39:04 -07001286 android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmapHandle->bitmap());
John Reck43871902016-08-01 14:39:24 -07001287}
1288
sergeyv45082182016-09-29 18:25:40 -07001289static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr) {
1290 LocalScopedBitmap bitmapHandle(bitmapPtr);
1291 return static_cast<jint>(bitmapHandle->getAllocationByteCount());
1292}
1293
sergeyv81f97ee2016-12-27 18:08:01 -08001294static jobject Bitmap_nativeCopyPreserveInternalConfig(JNIEnv* env, jobject, jlong bitmapPtr) {
1295 LocalScopedBitmap bitmapHandle(bitmapPtr);
1296 LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
1297 "Hardware config is only supported config in Bitmap_nativeCopyPreserveInternalConfig");
1298 Bitmap& hwuiBitmap = bitmapHandle->bitmap();
1299 SkBitmap src;
1300 hwuiBitmap.getSkBitmap(&src);
1301
1302 SkBitmap result;
1303 HeapAllocator allocator;
1304 if (!src.copyTo(&result, hwuiBitmap.info().colorType(), &allocator)) {
1305 doThrowRE(env, "Could not copy a hardware bitmap.");
1306 return NULL;
1307 }
1308 return createBitmap(env, allocator.getStorageObjAndReset(), kBitmapCreateFlag_None);
1309}
1310
Chris Craik32054b02014-05-09 13:58:56 -07001311///////////////////////////////////////////////////////////////////////////////
sergeyvc69853c2016-10-07 14:14:09 -07001312static jclass make_globalref(JNIEnv* env, const char classname[])
1313{
1314 jclass c = env->FindClass(classname);
1315 SkASSERT(c);
1316 return (jclass) env->NewGlobalRef(c);
1317}
1318
1319static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
1320 const char fieldname[], const char type[])
1321{
1322 jfieldID id = env->GetFieldID(clazz, fieldname, type);
1323 SkASSERT(id);
1324 return id;
1325}
Chris Craik32054b02014-05-09 13:58:56 -07001326
Daniel Micay76f6a862015-09-19 17:31:01 -04001327static const JNINativeMethod gBitmapMethods[] = {
Chris Craik32054b02014-05-09 13:58:56 -07001328 { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;",
1329 (void*)Bitmap_creator },
1330 { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;",
1331 (void*)Bitmap_copy },
Riley Andrews721ae5f2015-05-11 16:08:22 -07001332 { "nativeCopyAshmem", "(J)Landroid/graphics/Bitmap;",
1333 (void*)Bitmap_copyAshmem },
Winsona5fdde92016-04-14 15:27:15 -07001334 { "nativeCopyAshmemConfig", "(JI)Landroid/graphics/Bitmap;",
1335 (void*)Bitmap_copyAshmemConfig },
Richard Uhler775873a2015-12-29 12:37:39 -08001336 { "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer },
Chris Craik32054b02014-05-09 13:58:56 -07001337 { "nativeRecycle", "(J)Z", (void*)Bitmap_recycle },
sergeyv45082182016-09-29 18:25:40 -07001338 { "nativeReconfigure", "(JIIIZ)V", (void*)Bitmap_reconfigure },
Chris Craik32054b02014-05-09 13:58:56 -07001339 { "nativeCompress", "(JIILjava/io/OutputStream;[B)Z",
1340 (void*)Bitmap_compress },
1341 { "nativeErase", "(JI)V", (void*)Bitmap_erase },
1342 { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes },
1343 { "nativeConfig", "(J)I", (void*)Bitmap_config },
1344 { "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha },
Leon Scroggins III57ee6202014-06-04 18:51:07 -04001345 { "nativeIsPremultiplied", "(J)Z", (void*)Bitmap_isPremultiplied},
1346 { "nativeSetHasAlpha", "(JZZ)V", (void*)Bitmap_setHasAlpha},
1347 { "nativeSetPremultiplied", "(JZ)V", (void*)Bitmap_setPremultiplied},
Chris Craik32054b02014-05-09 13:58:56 -07001348 { "nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap },
1349 { "nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap },
1350 { "nativeCreateFromParcel",
1351 "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
1352 (void*)Bitmap_createFromParcel },
1353 { "nativeWriteToParcel", "(JZILandroid/os/Parcel;)Z",
1354 (void*)Bitmap_writeToParcel },
1355 { "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;",
1356 (void*)Bitmap_extractAlpha },
1357 { "nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId },
Leon Scroggins III57ee6202014-06-04 18:51:07 -04001358 { "nativeGetPixel", "(JII)I", (void*)Bitmap_getPixel },
1359 { "nativeGetPixels", "(J[IIIIIII)V", (void*)Bitmap_getPixels },
1360 { "nativeSetPixel", "(JIII)V", (void*)Bitmap_setPixel },
1361 { "nativeSetPixels", "(J[IIIIIII)V", (void*)Bitmap_setPixels },
Chris Craik32054b02014-05-09 13:58:56 -07001362 { "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V",
1363 (void*)Bitmap_copyPixelsToBuffer },
1364 { "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V",
1365 (void*)Bitmap_copyPixelsFromBuffer },
1366 { "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs },
John Reck43871902016-08-01 14:39:24 -07001367 { "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw },
sergeyv45082182016-09-29 18:25:40 -07001368 { "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount },
sergeyv81f97ee2016-12-27 18:08:01 -08001369 { "nativeCopyPreserveInternalConfig", "(J)Landroid/graphics/Bitmap;",
1370 (void*)Bitmap_nativeCopyPreserveInternalConfig },
Chris Craik32054b02014-05-09 13:58:56 -07001371};
1372
Chris Craik32054b02014-05-09 13:58:56 -07001373int register_android_graphics_Bitmap(JNIEnv* env)
1374{
sergeyvc69853c2016-10-07 14:14:09 -07001375 gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
1376 gBitmap_nativePtr = getFieldIDCheck(env, gBitmap_class, "mNativePtr", "J");
1377 gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
1378 gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "(IIZ)V");
1379 gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I");
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001380 return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods,
1381 NELEM(gBitmapMethods));
John Reck9192d5e2016-10-31 10:32:09 -07001382}