blob: c139c9d27ae96f0d7b2885ae49da21e6e1519249 [file] [log] [blame]
Chris Craik32054b02014-05-09 13:58:56 -07001#include "SkBitmap.h"
2#include "SkPixelRef.h"
3#include "SkImageEncoder.h"
4#include "SkColorPriv.h"
5#include "GraphicsJNI.h"
6#include "SkDither.h"
7#include "SkUnPreMultiply.h"
8#include "SkStream.h"
9
10#include <binder/Parcel.h>
11#include "android_os_Parcel.h"
12#include "android_util_Binder.h"
13#include "android_nio_utils.h"
14#include "CreateJavaOutputStreamAdaptor.h"
15
16#include <jni.h>
17
18#include <Caches.h>
19
20#if 0
21 #define TRACE_BITMAP(code) code
22#else
23 #define TRACE_BITMAP(code)
24#endif
25
26///////////////////////////////////////////////////////////////////////////////
27// Conversions to/from SkColor, for get/setPixels, and the create method, which
28// is basically like setPixels
29
30typedef void (*FromColorProc)(void* dst, const SkColor src[], int width,
31 int x, int y);
32
33static void FromColor_D32(void* dst, const SkColor src[], int width,
34 int, int) {
35 SkPMColor* d = (SkPMColor*)dst;
36
37 for (int i = 0; i < width; i++) {
38 *d++ = SkPreMultiplyColor(*src++);
39 }
40}
41
42static void FromColor_D32_Raw(void* dst, const SkColor src[], int width,
43 int, int) {
44 // SkColor's ordering may be different from SkPMColor
45 if (SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER) {
46 memcpy(dst, src, width * sizeof(SkColor));
47 return;
48 }
49
50 // order isn't same, repack each pixel manually
51 SkPMColor* d = (SkPMColor*)dst;
52 for (int i = 0; i < width; i++) {
53 SkColor c = *src++;
54 *d++ = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
55 SkColorGetG(c), SkColorGetB(c));
56 }
57}
58
59static void FromColor_D565(void* dst, const SkColor src[], int width,
60 int x, int y) {
61 uint16_t* d = (uint16_t*)dst;
62
63 DITHER_565_SCAN(y);
64 for (int stop = x + width; x < stop; x++) {
65 SkColor c = *src++;
66 *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c),
67 DITHER_VALUE(x));
68 }
69}
70
71static void FromColor_D4444(void* dst, const SkColor src[], int width,
72 int x, int y) {
73 SkPMColor16* d = (SkPMColor16*)dst;
74
75 DITHER_4444_SCAN(y);
76 for (int stop = x + width; x < stop; x++) {
77 SkPMColor pmc = SkPreMultiplyColor(*src++);
78 *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
79// *d++ = SkPixel32ToPixel4444(pmc);
80 }
81}
82
83static void FromColor_D4444_Raw(void* dst, const SkColor src[], int width,
84 int x, int y) {
85 SkPMColor16* d = (SkPMColor16*)dst;
86
87 DITHER_4444_SCAN(y);
88 for (int stop = x + width; x < stop; x++) {
89 SkColor c = *src++;
90
91 // SkPMColor is used because the ordering is ARGB32, even though the target actually premultiplied
92 SkPMColor pmc = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
93 SkColorGetG(c), SkColorGetB(c));
94 *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
95// *d++ = SkPixel32ToPixel4444(pmc);
96 }
97}
98
99// can return NULL
100static FromColorProc ChooseFromColorProc(SkBitmap::Config config, bool isPremultiplied) {
101 switch (config) {
102 case SkBitmap::kARGB_8888_Config:
103 return isPremultiplied ? FromColor_D32 : FromColor_D32_Raw;
104 case SkBitmap::kARGB_4444_Config:
105 return isPremultiplied ? FromColor_D4444 : FromColor_D4444_Raw;
106 case SkBitmap::kRGB_565_Config:
107 return FromColor_D565;
108 default:
109 break;
110 }
111 return NULL;
112}
113
114bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride,
115 int x, int y, int width, int height,
116 const SkBitmap& dstBitmap, bool isPremultiplied) {
117 SkAutoLockPixels alp(dstBitmap);
118 void* dst = dstBitmap.getPixels();
119 FromColorProc proc = ChooseFromColorProc(dstBitmap.config(), isPremultiplied);
120
121 if (NULL == dst || NULL == proc) {
122 return false;
123 }
124
125 const jint* array = env->GetIntArrayElements(srcColors, NULL);
126 const SkColor* src = (const SkColor*)array + srcOffset;
127
128 // reset to to actual choice from caller
129 dst = dstBitmap.getAddr(x, y);
130 // now copy/convert each scanline
131 for (int y = 0; y < height; y++) {
132 proc(dst, src, width, x, y);
133 src += srcStride;
134 dst = (char*)dst + dstBitmap.rowBytes();
135 }
136
137 dstBitmap.notifyPixelsChanged();
138
139 env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array),
140 JNI_ABORT);
141 return true;
142}
143
144//////////////////// ToColor procs
145
146typedef void (*ToColorProc)(SkColor dst[], const void* src, int width,
147 SkColorTable*);
148
149static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width,
150 SkColorTable*) {
151 SkASSERT(width > 0);
152 const SkPMColor* s = (const SkPMColor*)src;
153 do {
154 *dst++ = SkUnPreMultiply::PMColorToColor(*s++);
155 } while (--width != 0);
156}
157
158static void ToColor_S32_Raw(SkColor dst[], const void* src, int width,
159 SkColorTable*) {
160 SkASSERT(width > 0);
161 const SkPMColor* s = (const SkPMColor*)src;
162 do {
163 SkPMColor c = *s++;
164 *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
165 SkGetPackedG32(c), SkGetPackedB32(c));
166 } while (--width != 0);
167}
168
169static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width,
170 SkColorTable*) {
171 SkASSERT(width > 0);
172 const SkPMColor* s = (const SkPMColor*)src;
173 do {
174 SkPMColor c = *s++;
175 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
176 SkGetPackedB32(c));
177 } while (--width != 0);
178}
179
180static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width,
181 SkColorTable*) {
182 SkASSERT(width > 0);
183 const SkPMColor16* s = (const SkPMColor16*)src;
184 do {
185 *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++));
186 } while (--width != 0);
187}
188
189static void ToColor_S4444_Raw(SkColor dst[], const void* src, int width,
190 SkColorTable*) {
191 SkASSERT(width > 0);
192 const SkPMColor16* s = (const SkPMColor16*)src;
193 do {
194 SkPMColor c = SkPixel4444ToPixel32(*s++);
195 *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
196 SkGetPackedG32(c), SkGetPackedB32(c));
197 } while (--width != 0);
198}
199
200static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width,
201 SkColorTable*) {
202 SkASSERT(width > 0);
203 const SkPMColor16* s = (const SkPMColor16*)src;
204 do {
205 SkPMColor c = SkPixel4444ToPixel32(*s++);
206 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
207 SkGetPackedB32(c));
208 } while (--width != 0);
209}
210
211static void ToColor_S565(SkColor dst[], const void* src, int width,
212 SkColorTable*) {
213 SkASSERT(width > 0);
214 const uint16_t* s = (const uint16_t*)src;
215 do {
216 uint16_t c = *s++;
217 *dst++ = SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c),
218 SkPacked16ToB32(c));
219 } while (--width != 0);
220}
221
222static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width,
223 SkColorTable* ctable) {
224 SkASSERT(width > 0);
225 const uint8_t* s = (const uint8_t*)src;
226 const SkPMColor* colors = ctable->lockColors();
227 do {
228 *dst++ = SkUnPreMultiply::PMColorToColor(colors[*s++]);
229 } while (--width != 0);
230 ctable->unlockColors();
231}
232
233static void ToColor_SI8_Raw(SkColor dst[], const void* src, int width,
234 SkColorTable* ctable) {
235 SkASSERT(width > 0);
236 const uint8_t* s = (const uint8_t*)src;
237 const SkPMColor* colors = ctable->lockColors();
238 do {
239 SkPMColor c = colors[*s++];
240 *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
241 SkGetPackedG32(c), SkGetPackedB32(c));
242 } while (--width != 0);
243 ctable->unlockColors();
244}
245
246static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width,
247 SkColorTable* ctable) {
248 SkASSERT(width > 0);
249 const uint8_t* s = (const uint8_t*)src;
250 const SkPMColor* colors = ctable->lockColors();
251 do {
252 SkPMColor c = colors[*s++];
253 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
254 SkGetPackedB32(c));
255 } while (--width != 0);
256 ctable->unlockColors();
257}
258
259// can return NULL
260static ToColorProc ChooseToColorProc(const SkBitmap& src, bool isPremultiplied) {
Mike Reedb9330552014-06-16 17:31:48 -0400261 switch (src.colorType()) {
262 case kN32_SkColorType:
Chris Craik32054b02014-05-09 13:58:56 -0700263 if (src.isOpaque()) return ToColor_S32_Opaque;
264 return isPremultiplied ? ToColor_S32_Alpha : ToColor_S32_Raw;
Mike Reedb9330552014-06-16 17:31:48 -0400265 case kARGB_4444_SkColorType:
Chris Craik32054b02014-05-09 13:58:56 -0700266 if (src.isOpaque()) return ToColor_S4444_Opaque;
267 return isPremultiplied ? ToColor_S4444_Alpha : ToColor_S4444_Raw;
Mike Reedb9330552014-06-16 17:31:48 -0400268 case kRGB_565_SkColorType:
Chris Craik32054b02014-05-09 13:58:56 -0700269 return ToColor_S565;
Mike Reedb9330552014-06-16 17:31:48 -0400270 case kIndex_8_SkColorType:
Chris Craik32054b02014-05-09 13:58:56 -0700271 if (src.getColorTable() == NULL) {
272 return NULL;
273 }
274 if (src.isOpaque()) return ToColor_SI8_Opaque;
275 return isPremultiplied ? ToColor_SI8_Raw : ToColor_SI8_Alpha;
276 default:
277 break;
278 }
279 return NULL;
280}
281
282///////////////////////////////////////////////////////////////////////////////
283///////////////////////////////////////////////////////////////////////////////
284
285static int getPremulBitmapCreateFlags(bool isMutable) {
286 int flags = GraphicsJNI::kBitmapCreateFlag_Premultiplied;
287 if (isMutable) flags |= GraphicsJNI::kBitmapCreateFlag_Mutable;
288 return flags;
289}
290
291static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
292 jint offset, jint stride, jint width, jint height,
293 jint configHandle, jboolean isMutable) {
Mike Reedb9330552014-06-16 17:31:48 -0400294 SkColorType colorType = SkBitmapConfigToColorType(static_cast<SkBitmap::Config>(configHandle));
Chris Craik32054b02014-05-09 13:58:56 -0700295 if (NULL != jColors) {
296 size_t n = env->GetArrayLength(jColors);
297 if (n < SkAbs32(stride) * (size_t)height) {
298 doThrowAIOOBE(env);
299 return NULL;
300 }
301 }
302
303 // ARGB_4444 is a deprecated format, convert automatically to 8888
Mike Reedb9330552014-06-16 17:31:48 -0400304 if (colorType == kARGB_4444_SkColorType) {
305 colorType = kN32_SkColorType;
Chris Craik32054b02014-05-09 13:58:56 -0700306 }
307
308 SkBitmap bitmap;
Mike Reedb9330552014-06-16 17:31:48 -0400309 bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType));
Chris Craik32054b02014-05-09 13:58:56 -0700310
311 jbyteArray buff = GraphicsJNI::allocateJavaPixelRef(env, &bitmap, NULL);
312 if (NULL == buff) {
313 return NULL;
314 }
315
316 if (jColors != NULL) {
317 GraphicsJNI::SetPixels(env, jColors, offset, stride,
318 0, 0, width, height, bitmap, true);
319 }
320
321 return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), buff,
322 getPremulBitmapCreateFlags(isMutable), NULL, NULL);
323}
324
325static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle,
326 jint dstConfigHandle, jboolean isMutable) {
327 const SkBitmap* src = reinterpret_cast<SkBitmap*>(srcHandle);
328 SkBitmap::Config dstConfig = static_cast<SkBitmap::Config>(dstConfigHandle);
329 SkBitmap result;
330 JavaPixelAllocator allocator(env);
331
Leon Scrogginscc11f152014-03-31 16:52:13 -0400332 if (!src->copyTo(&result, SkBitmapConfigToColorType(dstConfig), &allocator)) {
Chris Craik32054b02014-05-09 13:58:56 -0700333 return NULL;
334 }
335 return GraphicsJNI::createBitmap(env, new SkBitmap(result), allocator.getStorageObj(),
336 getPremulBitmapCreateFlags(isMutable), NULL, NULL);
337}
338
339static void Bitmap_destructor(JNIEnv* env, jobject, jlong bitmapHandle) {
340 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
341#ifdef USE_OPENGL_RENDERER
342 if (android::uirenderer::Caches::hasInstance()) {
343 android::uirenderer::Caches::getInstance().resourceCache.destructor(bitmap);
344 return;
345 }
346#endif // USE_OPENGL_RENDERER
347 delete bitmap;
348}
349
350static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {
351 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
352#ifdef USE_OPENGL_RENDERER
353 if (android::uirenderer::Caches::hasInstance()) {
354 bool result;
355 result = android::uirenderer::Caches::getInstance().resourceCache.recycle(bitmap);
356 return result ? JNI_TRUE : JNI_FALSE;
357 }
358#endif // USE_OPENGL_RENDERER
359 bitmap->setPixels(NULL, NULL);
360 return JNI_TRUE;
361}
362
363static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
Leon Scroggins III17a8bfc2014-06-03 16:15:15 -0400364 jint width, jint height, jint configHandle, jint allocSize,
365 jboolean requestPremul) {
Chris Craik32054b02014-05-09 13:58:56 -0700366 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
367 SkBitmap::Config config = static_cast<SkBitmap::Config>(configHandle);
Leon Scroggins III17a8bfc2014-06-03 16:15:15 -0400368 SkColorType colorType = SkBitmapConfigToColorType(config);
369
370 // ARGB_4444 is a deprecated format, convert automatically to 8888
371 if (colorType == kARGB_4444_SkColorType) {
372 colorType = kN32_SkColorType;
373 }
374
375 if (width * height * SkColorTypeBytesPerPixel(colorType) > allocSize) {
Chris Craik32054b02014-05-09 13:58:56 -0700376 // done in native as there's no way to get BytesPerPixel in Java
377 doThrowIAE(env, "Bitmap not large enough to support new configuration");
378 return;
379 }
380 SkPixelRef* ref = bitmap->pixelRef();
Leon Scroggins III17a8bfc2014-06-03 16:15:15 -0400381 ref->ref();
382 SkAlphaType alphaType;
383 if (bitmap->colorType() != kRGB_565_SkColorType
384 && bitmap->alphaType() == kOpaque_SkAlphaType) {
385 // If the original bitmap was set to opaque, keep that setting, unless it
386 // was 565, which is required to be opaque.
387 alphaType = kOpaque_SkAlphaType;
388 } else {
389 // Otherwise respect the premultiplied request.
390 alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
391 }
392 bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType));
393 // FIXME: Skia thinks of an SkPixelRef as having a constant SkImageInfo (except for
394 // its alphatype), so it would make more sense from Skia's perspective to create a
395 // new SkPixelRef. That said, libhwui uses the pointer to the SkPixelRef as a key
396 // for its cache, so it won't realize this is the same Java Bitmap.
397 SkImageInfo& info = const_cast<SkImageInfo&>(ref->info());
398 // Use the updated from the SkBitmap, which may have corrected an invalid alphatype.
399 // (e.g. 565 non-opaque)
400 info = bitmap->info();
Chris Craik32054b02014-05-09 13:58:56 -0700401 bitmap->setPixelRef(ref);
402
403 // notifyPixelsChanged will increment the generation ID even though the actual pixel data
404 // hasn't been touched. This signals the renderer that the bitmap (including width, height,
Leon Scroggins III17a8bfc2014-06-03 16:15:15 -0400405 // colortype and alphatype) has changed.
Chris Craik32054b02014-05-09 13:58:56 -0700406 ref->notifyPixelsChanged();
Leon Scroggins III17a8bfc2014-06-03 16:15:15 -0400407 ref->unref();
Chris Craik32054b02014-05-09 13:58:56 -0700408}
409
410// These must match the int values in Bitmap.java
411enum JavaEncodeFormat {
412 kJPEG_JavaEncodeFormat = 0,
413 kPNG_JavaEncodeFormat = 1,
414 kWEBP_JavaEncodeFormat = 2
415};
416
417static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle,
418 jint format, jint quality,
419 jobject jstream, jbyteArray jstorage) {
420 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
421 SkImageEncoder::Type fm;
422
423 switch (format) {
424 case kJPEG_JavaEncodeFormat:
425 fm = SkImageEncoder::kJPEG_Type;
426 break;
427 case kPNG_JavaEncodeFormat:
428 fm = SkImageEncoder::kPNG_Type;
429 break;
430 case kWEBP_JavaEncodeFormat:
431 fm = SkImageEncoder::kWEBP_Type;
432 break;
433 default:
434 return JNI_FALSE;
435 }
436
437 bool success = false;
438 if (NULL != bitmap) {
439 SkAutoLockPixels alp(*bitmap);
440
441 if (NULL == bitmap->getPixels()) {
442 return JNI_FALSE;
443 }
444
445 SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
446 if (NULL == strm) {
447 return JNI_FALSE;
448 }
449
450 SkImageEncoder* encoder = SkImageEncoder::Create(fm);
451 if (NULL != encoder) {
452 success = encoder->encodeStream(strm, *bitmap, quality);
453 delete encoder;
454 }
455 delete strm;
456 }
457 return success ? JNI_TRUE : JNI_FALSE;
458}
459
460static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) {
461 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
462 bitmap->eraseColor(color);
463}
464
465static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {
466 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
467 return static_cast<jint>(bitmap->rowBytes());
468}
469
470static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) {
471 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
472 return static_cast<jint>(bitmap->config());
473}
474
475static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {
476 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
477 return static_cast<jint>(bitmap->getGenerationID());
478}
479
480static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) {
481 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
482 return !bitmap->isOpaque() ? JNI_TRUE : JNI_FALSE;
483}
484
485static void Bitmap_setAlphaAndPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
486 jboolean hasAlpha, jboolean isPremul) {
487 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
488 if (!hasAlpha) {
489 bitmap->setAlphaType(kOpaque_SkAlphaType);
490 } else if (isPremul) {
491 bitmap->setAlphaType(kPremul_SkAlphaType);
492 } else {
493 bitmap->setAlphaType(kUnpremul_SkAlphaType);
494 }
495}
496
497static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) {
498 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
499 return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE;
500}
501
502static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle,
503 jboolean hasMipMap) {
504 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
505 bitmap->setHasHardwareMipMap(hasMipMap);
506}
507
508///////////////////////////////////////////////////////////////////////////////
509
510static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
511 if (parcel == NULL) {
512 SkDebugf("-------- unparcel parcel is NULL\n");
513 return NULL;
514 }
515
516 android::Parcel* p = android::parcelForJavaObject(env, parcel);
517
Mike Reedb9330552014-06-16 17:31:48 -0400518 const bool isMutable = p->readInt32() != 0;
519 const SkColorType colorType = (SkColorType)p->readInt32();
520 const SkAlphaType alphaType = (SkAlphaType)p->readInt32();
521 const int width = p->readInt32();
522 const int height = p->readInt32();
523 const int rowBytes = p->readInt32();
524 const int density = p->readInt32();
Chris Craik32054b02014-05-09 13:58:56 -0700525
Mike Reedb9330552014-06-16 17:31:48 -0400526 if (kN32_SkColorType != colorType &&
527 kRGB_565_SkColorType != colorType &&
528 kARGB_4444_SkColorType != colorType &&
529 kIndex_8_SkColorType != colorType &&
530 kAlpha_8_SkColorType != colorType) {
531 SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType);
Chris Craik32054b02014-05-09 13:58:56 -0700532 return NULL;
533 }
534
535 SkBitmap* bitmap = new SkBitmap;
536
Mike Reedb9330552014-06-16 17:31:48 -0400537 bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType), rowBytes);
Chris Craik32054b02014-05-09 13:58:56 -0700538
539 SkColorTable* ctable = NULL;
Mike Reedb9330552014-06-16 17:31:48 -0400540 if (colorType == kIndex_8_SkColorType) {
Chris Craik32054b02014-05-09 13:58:56 -0700541 int count = p->readInt32();
542 if (count > 0) {
543 size_t size = count * sizeof(SkPMColor);
544 const SkPMColor* src = (const SkPMColor*)p->readInplace(size);
545 ctable = new SkColorTable(src, count);
546 }
547 }
548
549 jbyteArray buffer = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable);
550 if (NULL == buffer) {
551 SkSafeUnref(ctable);
552 delete bitmap;
553 return NULL;
554 }
555
556 SkSafeUnref(ctable);
557
558 size_t size = bitmap->getSize();
559
560 android::Parcel::ReadableBlob blob;
561 android::status_t status = p->readBlob(size, &blob);
562 if (status) {
563 doThrowRE(env, "Could not read bitmap from parcel blob.");
564 delete bitmap;
565 return NULL;
566 }
567
568 bitmap->lockPixels();
569 memcpy(bitmap->getPixels(), blob.data(), size);
570 bitmap->unlockPixels();
571
572 blob.release();
573
574 return GraphicsJNI::createBitmap(env, bitmap, buffer, getPremulBitmapCreateFlags(isMutable),
575 NULL, NULL, density);
576}
577
578static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
579 jlong bitmapHandle,
580 jboolean isMutable, jint density,
581 jobject parcel) {
582 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
583 if (parcel == NULL) {
584 SkDebugf("------- writeToParcel null parcel\n");
585 return JNI_FALSE;
586 }
587
588 android::Parcel* p = android::parcelForJavaObject(env, parcel);
589
590 p->writeInt32(isMutable);
Mike Reedb9330552014-06-16 17:31:48 -0400591 p->writeInt32(bitmap->colorType());
592 p->writeInt32(bitmap->alphaType());
Chris Craik32054b02014-05-09 13:58:56 -0700593 p->writeInt32(bitmap->width());
594 p->writeInt32(bitmap->height());
595 p->writeInt32(bitmap->rowBytes());
596 p->writeInt32(density);
597
Mike Reedb9330552014-06-16 17:31:48 -0400598 if (bitmap->colorType() == kIndex_8_SkColorType) {
Chris Craik32054b02014-05-09 13:58:56 -0700599 SkColorTable* ctable = bitmap->getColorTable();
600 if (ctable != NULL) {
601 int count = ctable->count();
602 p->writeInt32(count);
603 memcpy(p->writeInplace(count * sizeof(SkPMColor)),
604 ctable->lockColors(), count * sizeof(SkPMColor));
605 ctable->unlockColors();
606 } else {
607 p->writeInt32(0); // indicate no ctable
608 }
609 }
610
611 size_t size = bitmap->getSize();
612
613 android::Parcel::WritableBlob blob;
614 android::status_t status = p->writeBlob(size, &blob);
615 if (status) {
616 doThrowRE(env, "Could not write bitmap to parcel blob.");
617 return JNI_FALSE;
618 }
619
620 bitmap->lockPixels();
621 const void* pSrc = bitmap->getPixels();
622 if (pSrc == NULL) {
623 memset(blob.data(), 0, size);
624 } else {
625 memcpy(blob.data(), pSrc, size);
626 }
627 bitmap->unlockPixels();
628
629 blob.release();
630 return JNI_TRUE;
631}
632
633static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
634 jlong srcHandle, jlong paintHandle,
635 jintArray offsetXY) {
636 const SkBitmap* src = reinterpret_cast<SkBitmap*>(srcHandle);
637 const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
638 SkIPoint offset;
639 SkBitmap* dst = new SkBitmap;
640 JavaPixelAllocator allocator(env);
641
642 src->extractAlpha(dst, paint, &allocator, &offset);
643 // If Skia can't allocate pixels for destination bitmap, it resets
644 // it, that is set its pixels buffer to NULL, and zero width and height.
645 if (dst->getPixels() == NULL && src->getPixels() != NULL) {
646 delete dst;
647 doThrowOOME(env, "failed to allocate pixels for alpha");
648 return NULL;
649 }
650 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
651 int* array = env->GetIntArrayElements(offsetXY, NULL);
652 array[0] = offset.fX;
653 array[1] = offset.fY;
654 env->ReleaseIntArrayElements(offsetXY, array, 0);
655 }
656
657 return GraphicsJNI::createBitmap(env, dst, allocator.getStorageObj(),
658 getPremulBitmapCreateFlags(true), NULL, NULL);
659}
660
661///////////////////////////////////////////////////////////////////////////////
662
663static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
664 jint x, jint y, jboolean isPremultiplied) {
665 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
666 SkAutoLockPixels alp(*bitmap);
667
668 ToColorProc proc = ChooseToColorProc(*bitmap, isPremultiplied);
669 if (NULL == proc) {
670 return 0;
671 }
672 const void* src = bitmap->getAddr(x, y);
673 if (NULL == src) {
674 return 0;
675 }
676
677 SkColor dst[1];
678 proc(dst, src, 1, bitmap->getColorTable());
679 return static_cast<jint>(dst[0]);
680}
681
682static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,
683 jintArray pixelArray, jint offset, jint stride,
684 jint x, jint y, jint width, jint height, jboolean isPremultiplied) {
685 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
686 SkAutoLockPixels alp(*bitmap);
687
688 ToColorProc proc = ChooseToColorProc(*bitmap, isPremultiplied);
689 if (NULL == proc) {
690 return;
691 }
692 const void* src = bitmap->getAddr(x, y);
693 if (NULL == src) {
694 return;
695 }
696
697 SkColorTable* ctable = bitmap->getColorTable();
698 jint* dst = env->GetIntArrayElements(pixelArray, NULL);
699 SkColor* d = (SkColor*)dst + offset;
700 while (--height >= 0) {
701 proc(d, src, width, ctable);
702 d += stride;
703 src = (void*)((const char*)src + bitmap->rowBytes());
704 }
705 env->ReleaseIntArrayElements(pixelArray, dst, 0);
706}
707
708///////////////////////////////////////////////////////////////////////////////
709
710static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle,
711 jint x, jint y, jint colorHandle, jboolean isPremultiplied) {
712 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
713 SkColor color = static_cast<SkColor>(colorHandle);
714 SkAutoLockPixels alp(*bitmap);
715 if (NULL == bitmap->getPixels()) {
716 return;
717 }
718
719 FromColorProc proc = ChooseFromColorProc(bitmap->config(), isPremultiplied);
720 if (NULL == proc) {
721 return;
722 }
723
724 proc(bitmap->getAddr(x, y), &color, 1, x, y);
725 bitmap->notifyPixelsChanged();
726}
727
728static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,
729 jintArray pixelArray, jint offset, jint stride,
730 jint x, jint y, jint width, jint height, jboolean isPremultiplied) {
731 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
732 GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
733 x, y, width, height, *bitmap, isPremultiplied);
734}
735
736static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
737 jlong bitmapHandle, jobject jbuffer) {
738 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
739 SkAutoLockPixels alp(*bitmap);
740 const void* src = bitmap->getPixels();
741
742 if (NULL != src) {
743 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
744
745 // the java side has already checked that buffer is large enough
746 memcpy(abp.pointer(), src, bitmap->getSize());
747 }
748}
749
750static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,
751 jlong bitmapHandle, jobject jbuffer) {
752 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
753 SkAutoLockPixels alp(*bitmap);
754 void* dst = bitmap->getPixels();
755
756 if (NULL != dst) {
757 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);
758 // the java side has already checked that buffer is large enough
759 memcpy(dst, abp.pointer(), bitmap->getSize());
760 bitmap->notifyPixelsChanged();
761 }
762}
763
764static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle,
765 jlong bm1Handle) {
766 const SkBitmap* bm0 = reinterpret_cast<SkBitmap*>(bm0Handle);
767 const SkBitmap* bm1 = reinterpret_cast<SkBitmap*>(bm1Handle);
768 if (bm0->width() != bm1->width() ||
769 bm0->height() != bm1->height() ||
770 bm0->config() != bm1->config()) {
771 return JNI_FALSE;
772 }
773
774 SkAutoLockPixels alp0(*bm0);
775 SkAutoLockPixels alp1(*bm1);
776
777 // if we can't load the pixels, return false
778 if (NULL == bm0->getPixels() || NULL == bm1->getPixels()) {
779 return JNI_FALSE;
780 }
781
782 if (bm0->config() == SkBitmap::kIndex8_Config) {
783 SkColorTable* ct0 = bm0->getColorTable();
784 SkColorTable* ct1 = bm1->getColorTable();
785 if (NULL == ct0 || NULL == ct1) {
786 return JNI_FALSE;
787 }
788 if (ct0->count() != ct1->count()) {
789 return JNI_FALSE;
790 }
791
792 SkAutoLockColors alc0(ct0);
793 SkAutoLockColors alc1(ct1);
794 const size_t size = ct0->count() * sizeof(SkPMColor);
795 if (memcmp(alc0.colors(), alc1.colors(), size) != 0) {
796 return JNI_FALSE;
797 }
798 }
799
800 // now compare each scanline. We can't do the entire buffer at once,
801 // since we don't care about the pixel values that might extend beyond
802 // the width (since the scanline might be larger than the logical width)
803 const int h = bm0->height();
804 const size_t size = bm0->width() * bm0->bytesPerPixel();
805 for (int y = 0; y < h; y++) {
806 if (memcmp(bm0->getAddr(0, y), bm1->getAddr(0, y), size) != 0) {
807 return JNI_FALSE;
808 }
809 }
810 return JNI_TRUE;
811}
812
813static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapHandle) {
814 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
815 bitmap->lockPixels();
816 bitmap->unlockPixels();
817}
818
819///////////////////////////////////////////////////////////////////////////////
820
821#include <android_runtime/AndroidRuntime.h>
822
823static JNINativeMethod gBitmapMethods[] = {
824 { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;",
825 (void*)Bitmap_creator },
826 { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;",
827 (void*)Bitmap_copy },
828 { "nativeDestructor", "(J)V", (void*)Bitmap_destructor },
829 { "nativeRecycle", "(J)Z", (void*)Bitmap_recycle },
Leon Scroggins III17a8bfc2014-06-03 16:15:15 -0400830 { "nativeReconfigure", "(JIIIIZ)V", (void*)Bitmap_reconfigure },
Chris Craik32054b02014-05-09 13:58:56 -0700831 { "nativeCompress", "(JIILjava/io/OutputStream;[B)Z",
832 (void*)Bitmap_compress },
833 { "nativeErase", "(JI)V", (void*)Bitmap_erase },
834 { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes },
835 { "nativeConfig", "(J)I", (void*)Bitmap_config },
836 { "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha },
837 { "nativeSetAlphaAndPremultiplied", "(JZZ)V", (void*)Bitmap_setAlphaAndPremultiplied},
838 { "nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap },
839 { "nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap },
840 { "nativeCreateFromParcel",
841 "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
842 (void*)Bitmap_createFromParcel },
843 { "nativeWriteToParcel", "(JZILandroid/os/Parcel;)Z",
844 (void*)Bitmap_writeToParcel },
845 { "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;",
846 (void*)Bitmap_extractAlpha },
847 { "nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId },
848 { "nativeGetPixel", "(JIIZ)I", (void*)Bitmap_getPixel },
849 { "nativeGetPixels", "(J[IIIIIIIZ)V", (void*)Bitmap_getPixels },
850 { "nativeSetPixel", "(JIIIZ)V", (void*)Bitmap_setPixel },
851 { "nativeSetPixels", "(J[IIIIIIIZ)V", (void*)Bitmap_setPixels },
852 { "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V",
853 (void*)Bitmap_copyPixelsToBuffer },
854 { "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V",
855 (void*)Bitmap_copyPixelsFromBuffer },
856 { "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs },
857 { "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw },
858};
859
860#define kClassPathName "android/graphics/Bitmap"
861
862int register_android_graphics_Bitmap(JNIEnv* env)
863{
864 return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
865 gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods));
866}