1 #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
9 #include <binder/Parcel.h>
10 #include "android_os_Parcel.h"
11 #include "android_util_Binder.h"
12 #include "android_nio_utils.h"
13 #include "CreateJavaOutputStreamAdaptor.h"
14
15 #include <jni.h>
16
17 #include <Caches.h>
18
19 #if 0
20 #define TRACE_BITMAP(code) code
21 #else
22 #define TRACE_BITMAP(code)
23 #endif
24
25 ///////////////////////////////////////////////////////////////////////////////
26 // Conversions to/from SkColor, for get/setPixels, and the create method, which
27 // is basically like setPixels
28
29 typedef void (*FromColorProc)(void* dst, const SkColor src[], int width,
30 int x, int y);
31
FromColor_D32(void * dst,const SkColor src[],int width,int,int)32 static void FromColor_D32(void* dst, const SkColor src[], int width,
33 int, int) {
34 SkPMColor* d = (SkPMColor*)dst;
35
36 for (int i = 0; i < width; i++) {
37 *d++ = SkPreMultiplyColor(*src++);
38 }
39 }
40
FromColor_D565(void * dst,const SkColor src[],int width,int x,int y)41 static void FromColor_D565(void* dst, const SkColor src[], int width,
42 int x, int y) {
43 uint16_t* d = (uint16_t*)dst;
44
45 DITHER_565_SCAN(y);
46 for (int stop = x + width; x < stop; x++) {
47 SkColor c = *src++;
48 *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c),
49 DITHER_VALUE(x));
50 }
51 }
52
FromColor_D4444(void * dst,const SkColor src[],int width,int x,int y)53 static void FromColor_D4444(void* dst, const SkColor src[], int width,
54 int x, int y) {
55 SkPMColor16* d = (SkPMColor16*)dst;
56
57 DITHER_4444_SCAN(y);
58 for (int stop = x + width; x < stop; x++) {
59 SkPMColor c = SkPreMultiplyColor(*src++);
60 *d++ = SkDitherARGB32To4444(c, DITHER_VALUE(x));
61 // *d++ = SkPixel32ToPixel4444(c);
62 }
63 }
64
65 // can return NULL
ChooseFromColorProc(SkBitmap::Config config)66 static FromColorProc ChooseFromColorProc(SkBitmap::Config config) {
67 switch (config) {
68 case SkBitmap::kARGB_8888_Config:
69 return FromColor_D32;
70 case SkBitmap::kARGB_4444_Config:
71 return FromColor_D4444;
72 case SkBitmap::kRGB_565_Config:
73 return FromColor_D565;
74 default:
75 break;
76 }
77 return NULL;
78 }
79
SetPixels(JNIEnv * env,jintArray srcColors,int srcOffset,int srcStride,int x,int y,int width,int height,const SkBitmap & dstBitmap)80 bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors,
81 int srcOffset, int srcStride,
82 int x, int y, int width, int height,
83 const SkBitmap& dstBitmap) {
84 SkAutoLockPixels alp(dstBitmap);
85 void* dst = dstBitmap.getPixels();
86 FromColorProc proc = ChooseFromColorProc(dstBitmap.config());
87
88 if (NULL == dst || NULL == proc) {
89 return false;
90 }
91
92 const jint* array = env->GetIntArrayElements(srcColors, NULL);
93 const SkColor* src = (const SkColor*)array + srcOffset;
94
95 // reset to to actual choice from caller
96 dst = dstBitmap.getAddr(x, y);
97 // now copy/convert each scanline
98 for (int y = 0; y < height; y++) {
99 proc(dst, src, width, x, y);
100 src += srcStride;
101 dst = (char*)dst + dstBitmap.rowBytes();
102 }
103
104 dstBitmap.notifyPixelsChanged();
105
106 env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array),
107 JNI_ABORT);
108 return true;
109 }
110
111 //////////////////// ToColor procs
112
113 typedef void (*ToColorProc)(SkColor dst[], const void* src, int width,
114 SkColorTable*);
115
ToColor_S32_Alpha(SkColor dst[],const void * src,int width,SkColorTable *)116 static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width,
117 SkColorTable*) {
118 SkASSERT(width > 0);
119 const SkPMColor* s = (const SkPMColor*)src;
120 do {
121 *dst++ = SkUnPreMultiply::PMColorToColor(*s++);
122 } while (--width != 0);
123 }
124
ToColor_S32_Opaque(SkColor dst[],const void * src,int width,SkColorTable *)125 static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width,
126 SkColorTable*) {
127 SkASSERT(width > 0);
128 const SkPMColor* s = (const SkPMColor*)src;
129 do {
130 SkPMColor c = *s++;
131 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
132 SkGetPackedB32(c));
133 } while (--width != 0);
134 }
135
ToColor_S4444_Alpha(SkColor dst[],const void * src,int width,SkColorTable *)136 static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width,
137 SkColorTable*) {
138 SkASSERT(width > 0);
139 const SkPMColor16* s = (const SkPMColor16*)src;
140 do {
141 *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++));
142 } while (--width != 0);
143 }
144
ToColor_S4444_Opaque(SkColor dst[],const void * src,int width,SkColorTable *)145 static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width,
146 SkColorTable*) {
147 SkASSERT(width > 0);
148 const SkPMColor16* s = (const SkPMColor16*)src;
149 do {
150 SkPMColor c = SkPixel4444ToPixel32(*s++);
151 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
152 SkGetPackedB32(c));
153 } while (--width != 0);
154 }
155
ToColor_S565(SkColor dst[],const void * src,int width,SkColorTable *)156 static void ToColor_S565(SkColor dst[], const void* src, int width,
157 SkColorTable*) {
158 SkASSERT(width > 0);
159 const uint16_t* s = (const uint16_t*)src;
160 do {
161 uint16_t c = *s++;
162 *dst++ = SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c),
163 SkPacked16ToB32(c));
164 } while (--width != 0);
165 }
166
ToColor_SI8_Alpha(SkColor dst[],const void * src,int width,SkColorTable * ctable)167 static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width,
168 SkColorTable* ctable) {
169 SkASSERT(width > 0);
170 const uint8_t* s = (const uint8_t*)src;
171 const SkPMColor* colors = ctable->lockColors();
172 do {
173 *dst++ = SkUnPreMultiply::PMColorToColor(colors[*s++]);
174 } while (--width != 0);
175 ctable->unlockColors(false);
176 }
177
ToColor_SI8_Opaque(SkColor dst[],const void * src,int width,SkColorTable * ctable)178 static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width,
179 SkColorTable* ctable) {
180 SkASSERT(width > 0);
181 const uint8_t* s = (const uint8_t*)src;
182 const SkPMColor* colors = ctable->lockColors();
183 do {
184 SkPMColor c = colors[*s++];
185 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
186 SkGetPackedB32(c));
187 } while (--width != 0);
188 ctable->unlockColors(false);
189 }
190
191 // can return NULL
ChooseToColorProc(const SkBitmap & src)192 static ToColorProc ChooseToColorProc(const SkBitmap& src) {
193 switch (src.config()) {
194 case SkBitmap::kARGB_8888_Config:
195 return src.isOpaque() ? ToColor_S32_Opaque : ToColor_S32_Alpha;
196 case SkBitmap::kARGB_4444_Config:
197 return src.isOpaque() ? ToColor_S4444_Opaque : ToColor_S4444_Alpha;
198 case SkBitmap::kRGB_565_Config:
199 return ToColor_S565;
200 case SkBitmap::kIndex8_Config:
201 if (src.getColorTable() == NULL) {
202 return NULL;
203 }
204 return src.isOpaque() ? ToColor_SI8_Opaque : ToColor_SI8_Alpha;
205 default:
206 break;
207 }
208 return NULL;
209 }
210
211 ///////////////////////////////////////////////////////////////////////////////
212 ///////////////////////////////////////////////////////////////////////////////
213
Bitmap_creator(JNIEnv * env,jobject,jintArray jColors,int offset,int stride,int width,int height,SkBitmap::Config config,jboolean isMutable)214 static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
215 int offset, int stride, int width, int height,
216 SkBitmap::Config config, jboolean isMutable) {
217 if (NULL != jColors) {
218 size_t n = env->GetArrayLength(jColors);
219 if (n < SkAbs32(stride) * (size_t)height) {
220 doThrowAIOOBE(env);
221 return NULL;
222 }
223 }
224
225 SkBitmap bitmap;
226
227 bitmap.setConfig(config, width, height);
228
229 jbyteArray buff = GraphicsJNI::allocateJavaPixelRef(env, &bitmap, NULL);
230 if (NULL == buff) {
231 return NULL;
232 }
233
234 if (jColors != NULL) {
235 GraphicsJNI::SetPixels(env, jColors, offset, stride,
236 0, 0, width, height, bitmap);
237 }
238
239 return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), buff, isMutable, NULL, NULL);
240 }
241
Bitmap_copy(JNIEnv * env,jobject,const SkBitmap * src,SkBitmap::Config dstConfig,jboolean isMutable)242 static jobject Bitmap_copy(JNIEnv* env, jobject, const SkBitmap* src,
243 SkBitmap::Config dstConfig, jboolean isMutable) {
244 SkBitmap result;
245 JavaPixelAllocator allocator(env);
246
247 if (!src->copyTo(&result, dstConfig, &allocator)) {
248 return NULL;
249 }
250
251 return GraphicsJNI::createBitmap(env, new SkBitmap(result), allocator.getStorageObj(), isMutable, NULL, NULL);
252 }
253
Bitmap_destructor(JNIEnv * env,jobject,SkBitmap * bitmap)254 static void Bitmap_destructor(JNIEnv* env, jobject, SkBitmap* bitmap) {
255 #ifdef USE_OPENGL_RENDERER
256 if (android::uirenderer::Caches::hasInstance()) {
257 android::uirenderer::Caches::getInstance().resourceCache.destructor(bitmap);
258 return;
259 }
260 #endif // USE_OPENGL_RENDERER
261 delete bitmap;
262 }
263
Bitmap_recycle(JNIEnv * env,jobject,SkBitmap * bitmap)264 static jboolean Bitmap_recycle(JNIEnv* env, jobject, SkBitmap* bitmap) {
265 #ifdef USE_OPENGL_RENDERER
266 if (android::uirenderer::Caches::hasInstance()) {
267 return android::uirenderer::Caches::getInstance().resourceCache.recycle(bitmap);
268 }
269 #endif // USE_OPENGL_RENDERER
270 bitmap->setPixels(NULL, NULL);
271 return true;
272 }
273
274 // These must match the int values in Bitmap.java
275 enum JavaEncodeFormat {
276 kJPEG_JavaEncodeFormat = 0,
277 kPNG_JavaEncodeFormat = 1,
278 kWEBP_JavaEncodeFormat = 2
279 };
280
Bitmap_compress(JNIEnv * env,jobject clazz,SkBitmap * bitmap,int format,int quality,jobject jstream,jbyteArray jstorage)281 static bool Bitmap_compress(JNIEnv* env, jobject clazz, SkBitmap* bitmap,
282 int format, int quality,
283 jobject jstream, jbyteArray jstorage) {
284 SkImageEncoder::Type fm;
285
286 switch (format) {
287 case kJPEG_JavaEncodeFormat:
288 fm = SkImageEncoder::kJPEG_Type;
289 break;
290 case kPNG_JavaEncodeFormat:
291 fm = SkImageEncoder::kPNG_Type;
292 break;
293 case kWEBP_JavaEncodeFormat:
294 fm = SkImageEncoder::kWEBP_Type;
295 break;
296 default:
297 return false;
298 }
299
300 bool success = false;
301 if (NULL != bitmap) {
302 SkAutoLockPixels alp(*bitmap);
303
304 if (NULL == bitmap->getPixels()) {
305 return false;
306 }
307
308 SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
309 if (NULL == strm) {
310 return false;
311 }
312
313 SkImageEncoder* encoder = SkImageEncoder::Create(fm);
314 if (NULL != encoder) {
315 success = encoder->encodeStream(strm, *bitmap, quality);
316 delete encoder;
317 }
318 delete strm;
319 }
320 return success;
321 }
322
Bitmap_erase(JNIEnv * env,jobject,SkBitmap * bitmap,jint color)323 static void Bitmap_erase(JNIEnv* env, jobject, SkBitmap* bitmap, jint color) {
324 bitmap->eraseColor(color);
325 }
326
Bitmap_width(JNIEnv * env,jobject,SkBitmap * bitmap)327 static int Bitmap_width(JNIEnv* env, jobject, SkBitmap* bitmap) {
328 return bitmap->width();
329 }
330
Bitmap_height(JNIEnv * env,jobject,SkBitmap * bitmap)331 static int Bitmap_height(JNIEnv* env, jobject, SkBitmap* bitmap) {
332 return bitmap->height();
333 }
334
Bitmap_rowBytes(JNIEnv * env,jobject,SkBitmap * bitmap)335 static int Bitmap_rowBytes(JNIEnv* env, jobject, SkBitmap* bitmap) {
336 return bitmap->rowBytes();
337 }
338
Bitmap_config(JNIEnv * env,jobject,SkBitmap * bitmap)339 static int Bitmap_config(JNIEnv* env, jobject, SkBitmap* bitmap) {
340 return bitmap->config();
341 }
342
Bitmap_getGenerationId(JNIEnv * env,jobject,SkBitmap * bitmap)343 static int Bitmap_getGenerationId(JNIEnv* env, jobject, SkBitmap* bitmap) {
344 return bitmap->getGenerationID();
345 }
346
Bitmap_hasAlpha(JNIEnv * env,jobject,SkBitmap * bitmap)347 static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, SkBitmap* bitmap) {
348 return !bitmap->isOpaque();
349 }
350
Bitmap_setHasAlpha(JNIEnv * env,jobject,SkBitmap * bitmap,jboolean hasAlpha)351 static void Bitmap_setHasAlpha(JNIEnv* env, jobject, SkBitmap* bitmap,
352 jboolean hasAlpha) {
353 bitmap->setIsOpaque(!hasAlpha);
354 }
355
Bitmap_hasMipMap(JNIEnv * env,jobject,SkBitmap * bitmap)356 static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, SkBitmap* bitmap) {
357 return bitmap->hasHardwareMipMap();
358 }
359
Bitmap_setHasMipMap(JNIEnv * env,jobject,SkBitmap * bitmap,jboolean hasMipMap)360 static void Bitmap_setHasMipMap(JNIEnv* env, jobject, SkBitmap* bitmap,
361 jboolean hasMipMap) {
362 bitmap->setHasHardwareMipMap(hasMipMap);
363 }
364
365 ///////////////////////////////////////////////////////////////////////////////
366
Bitmap_createFromParcel(JNIEnv * env,jobject,jobject parcel)367 static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
368 if (parcel == NULL) {
369 SkDebugf("-------- unparcel parcel is NULL\n");
370 return NULL;
371 }
372
373 android::Parcel* p = android::parcelForJavaObject(env, parcel);
374
375 const bool isMutable = p->readInt32() != 0;
376 const SkBitmap::Config config = (SkBitmap::Config)p->readInt32();
377 const int width = p->readInt32();
378 const int height = p->readInt32();
379 const int rowBytes = p->readInt32();
380 const int density = p->readInt32();
381
382 if (SkBitmap::kARGB_8888_Config != config &&
383 SkBitmap::kRGB_565_Config != config &&
384 SkBitmap::kARGB_4444_Config != config &&
385 SkBitmap::kIndex8_Config != config &&
386 SkBitmap::kA8_Config != config) {
387 SkDebugf("Bitmap_createFromParcel unknown config: %d\n", config);
388 return NULL;
389 }
390
391 SkBitmap* bitmap = new SkBitmap;
392
393 bitmap->setConfig(config, width, height, rowBytes);
394
395 SkColorTable* ctable = NULL;
396 if (config == SkBitmap::kIndex8_Config) {
397 int count = p->readInt32();
398 if (count > 0) {
399 size_t size = count * sizeof(SkPMColor);
400 const SkPMColor* src = (const SkPMColor*)p->readInplace(size);
401 ctable = new SkColorTable(src, count);
402 }
403 }
404
405 jbyteArray buffer = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable);
406 if (NULL == buffer) {
407 SkSafeUnref(ctable);
408 delete bitmap;
409 return NULL;
410 }
411
412 SkSafeUnref(ctable);
413
414 size_t size = bitmap->getSize();
415
416 android::Parcel::ReadableBlob blob;
417 android::status_t status = p->readBlob(size, &blob);
418 if (status) {
419 doThrowRE(env, "Could not read bitmap from parcel blob.");
420 delete bitmap;
421 return NULL;
422 }
423
424 bitmap->lockPixels();
425 memcpy(bitmap->getPixels(), blob.data(), size);
426 bitmap->unlockPixels();
427
428 blob.release();
429 return GraphicsJNI::createBitmap(env, bitmap, buffer, isMutable, NULL, NULL, density);
430 }
431
Bitmap_writeToParcel(JNIEnv * env,jobject,const SkBitmap * bitmap,jboolean isMutable,jint density,jobject parcel)432 static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
433 const SkBitmap* bitmap,
434 jboolean isMutable, jint density,
435 jobject parcel) {
436 if (parcel == NULL) {
437 SkDebugf("------- writeToParcel null parcel\n");
438 return false;
439 }
440
441 android::Parcel* p = android::parcelForJavaObject(env, parcel);
442
443 p->writeInt32(isMutable);
444 p->writeInt32(bitmap->config());
445 p->writeInt32(bitmap->width());
446 p->writeInt32(bitmap->height());
447 p->writeInt32(bitmap->rowBytes());
448 p->writeInt32(density);
449
450 if (bitmap->getConfig() == SkBitmap::kIndex8_Config) {
451 SkColorTable* ctable = bitmap->getColorTable();
452 if (ctable != NULL) {
453 int count = ctable->count();
454 p->writeInt32(count);
455 memcpy(p->writeInplace(count * sizeof(SkPMColor)),
456 ctable->lockColors(), count * sizeof(SkPMColor));
457 ctable->unlockColors(false);
458 } else {
459 p->writeInt32(0); // indicate no ctable
460 }
461 }
462
463 size_t size = bitmap->getSize();
464
465 android::Parcel::WritableBlob blob;
466 android::status_t status = p->writeBlob(size, &blob);
467 if (status) {
468 doThrowRE(env, "Could not write bitmap to parcel blob.");
469 return false;
470 }
471
472 bitmap->lockPixels();
473 const void* pSrc = bitmap->getPixels();
474 if (pSrc == NULL) {
475 memset(blob.data(), 0, size);
476 } else {
477 memcpy(blob.data(), pSrc, size);
478 }
479 bitmap->unlockPixels();
480
481 blob.release();
482 return true;
483 }
484
Bitmap_extractAlpha(JNIEnv * env,jobject clazz,const SkBitmap * src,const SkPaint * paint,jintArray offsetXY)485 static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
486 const SkBitmap* src, const SkPaint* paint,
487 jintArray offsetXY) {
488 SkIPoint offset;
489 SkBitmap* dst = new SkBitmap;
490 JavaPixelAllocator allocator(env);
491
492 src->extractAlpha(dst, paint, &allocator, &offset);
493 // If Skia can't allocate pixels for destination bitmap, it resets
494 // it, that is set its pixels buffer to NULL, and zero width and height.
495 if (dst->getPixels() == NULL && src->getPixels() != NULL) {
496 delete dst;
497 doThrowOOME(env, "failed to allocate pixels for alpha");
498 return NULL;
499 }
500 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
501 int* array = env->GetIntArrayElements(offsetXY, NULL);
502 array[0] = offset.fX;
503 array[1] = offset.fY;
504 env->ReleaseIntArrayElements(offsetXY, array, 0);
505 }
506
507 return GraphicsJNI::createBitmap(env, dst, allocator.getStorageObj(), true, NULL, NULL);
508 }
509
510 ///////////////////////////////////////////////////////////////////////////////
511
Bitmap_getPixel(JNIEnv * env,jobject,const SkBitmap * bitmap,int x,int y)512 static int Bitmap_getPixel(JNIEnv* env, jobject, const SkBitmap* bitmap,
513 int x, int y) {
514 SkAutoLockPixels alp(*bitmap);
515
516 ToColorProc proc = ChooseToColorProc(*bitmap);
517 if (NULL == proc) {
518 return 0;
519 }
520 const void* src = bitmap->getAddr(x, y);
521 if (NULL == src) {
522 return 0;
523 }
524
525 SkColor dst[1];
526 proc(dst, src, 1, bitmap->getColorTable());
527 return dst[0];
528 }
529
Bitmap_getPixels(JNIEnv * env,jobject,const SkBitmap * bitmap,jintArray pixelArray,int offset,int stride,int x,int y,int width,int height)530 static void Bitmap_getPixels(JNIEnv* env, jobject, const SkBitmap* bitmap,
531 jintArray pixelArray, int offset, int stride,
532 int x, int y, int width, int height) {
533 SkAutoLockPixels alp(*bitmap);
534
535 ToColorProc proc = ChooseToColorProc(*bitmap);
536 if (NULL == proc) {
537 return;
538 }
539 const void* src = bitmap->getAddr(x, y);
540 if (NULL == src) {
541 return;
542 }
543
544 SkColorTable* ctable = bitmap->getColorTable();
545 jint* dst = env->GetIntArrayElements(pixelArray, NULL);
546 SkColor* d = (SkColor*)dst + offset;
547 while (--height >= 0) {
548 proc(d, src, width, ctable);
549 d += stride;
550 src = (void*)((const char*)src + bitmap->rowBytes());
551 }
552 env->ReleaseIntArrayElements(pixelArray, dst, 0);
553 }
554
555 ///////////////////////////////////////////////////////////////////////////////
556
Bitmap_setPixel(JNIEnv * env,jobject,const SkBitmap * bitmap,int x,int y,SkColor color)557 static void Bitmap_setPixel(JNIEnv* env, jobject, const SkBitmap* bitmap,
558 int x, int y, SkColor color) {
559 SkAutoLockPixels alp(*bitmap);
560 if (NULL == bitmap->getPixels()) {
561 return;
562 }
563
564 FromColorProc proc = ChooseFromColorProc(bitmap->config());
565 if (NULL == proc) {
566 return;
567 }
568
569 proc(bitmap->getAddr(x, y), &color, 1, x, y);
570 bitmap->notifyPixelsChanged();
571 }
572
Bitmap_setPixels(JNIEnv * env,jobject,const SkBitmap * bitmap,jintArray pixelArray,int offset,int stride,int x,int y,int width,int height)573 static void Bitmap_setPixels(JNIEnv* env, jobject, const SkBitmap* bitmap,
574 jintArray pixelArray, int offset, int stride,
575 int x, int y, int width, int height) {
576 GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
577 x, y, width, height, *bitmap);
578 }
579
Bitmap_copyPixelsToBuffer(JNIEnv * env,jobject,const SkBitmap * bitmap,jobject jbuffer)580 static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
581 const SkBitmap* bitmap, jobject jbuffer) {
582 SkAutoLockPixels alp(*bitmap);
583 const void* src = bitmap->getPixels();
584
585 if (NULL != src) {
586 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
587
588 // the java side has already checked that buffer is large enough
589 memcpy(abp.pointer(), src, bitmap->getSize());
590 }
591 }
592
Bitmap_copyPixelsFromBuffer(JNIEnv * env,jobject,const SkBitmap * bitmap,jobject jbuffer)593 static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,
594 const SkBitmap* bitmap, jobject jbuffer) {
595 SkAutoLockPixels alp(*bitmap);
596 void* dst = bitmap->getPixels();
597
598 if (NULL != dst) {
599 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);
600 // the java side has already checked that buffer is large enough
601 memcpy(dst, abp.pointer(), bitmap->getSize());
602 bitmap->notifyPixelsChanged();
603 }
604 }
605
Bitmap_sameAs(JNIEnv * env,jobject,const SkBitmap * bm0,const SkBitmap * bm1)606 static bool Bitmap_sameAs(JNIEnv* env, jobject, const SkBitmap* bm0,
607 const SkBitmap* bm1) {
608 if (bm0->width() != bm1->width() ||
609 bm0->height() != bm1->height() ||
610 bm0->config() != bm1->config()) {
611 return false;
612 }
613
614 SkAutoLockPixels alp0(*bm0);
615 SkAutoLockPixels alp1(*bm1);
616
617 // if we can't load the pixels, return false
618 if (NULL == bm0->getPixels() || NULL == bm1->getPixels()) {
619 return false;
620 }
621
622 if (bm0->config() == SkBitmap::kIndex8_Config) {
623 SkColorTable* ct0 = bm0->getColorTable();
624 SkColorTable* ct1 = bm1->getColorTable();
625 if (NULL == ct0 || NULL == ct1) {
626 return false;
627 }
628 if (ct0->count() != ct1->count()) {
629 return false;
630 }
631
632 SkAutoLockColors alc0(ct0);
633 SkAutoLockColors alc1(ct1);
634 const size_t size = ct0->count() * sizeof(SkPMColor);
635 if (memcmp(alc0.colors(), alc1.colors(), size) != 0) {
636 return false;
637 }
638 }
639
640 // now compare each scanline. We can't do the entire buffer at once,
641 // since we don't care about the pixel values that might extend beyond
642 // the width (since the scanline might be larger than the logical width)
643 const int h = bm0->height();
644 const size_t size = bm0->width() * bm0->bytesPerPixel();
645 for (int y = 0; y < h; y++) {
646 if (memcmp(bm0->getAddr(0, y), bm1->getAddr(0, y), size) != 0) {
647 return false;
648 }
649 }
650 return true;
651 }
652
Bitmap_prepareToDraw(JNIEnv * env,jobject,SkBitmap * bitmap)653 static void Bitmap_prepareToDraw(JNIEnv* env, jobject, SkBitmap* bitmap) {
654 bitmap->lockPixels();
655 bitmap->unlockPixels();
656 }
657
658 ///////////////////////////////////////////////////////////////////////////////
659
660 #include <android_runtime/AndroidRuntime.h>
661
662 static JNINativeMethod gBitmapMethods[] = {
663 { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;",
664 (void*)Bitmap_creator },
665 { "nativeCopy", "(IIZ)Landroid/graphics/Bitmap;",
666 (void*)Bitmap_copy },
667 { "nativeDestructor", "(I)V", (void*)Bitmap_destructor },
668 { "nativeRecycle", "(I)Z", (void*)Bitmap_recycle },
669 { "nativeCompress", "(IIILjava/io/OutputStream;[B)Z",
670 (void*)Bitmap_compress },
671 { "nativeErase", "(II)V", (void*)Bitmap_erase },
672 { "nativeWidth", "(I)I", (void*)Bitmap_width },
673 { "nativeHeight", "(I)I", (void*)Bitmap_height },
674 { "nativeRowBytes", "(I)I", (void*)Bitmap_rowBytes },
675 { "nativeConfig", "(I)I", (void*)Bitmap_config },
676 { "nativeHasAlpha", "(I)Z", (void*)Bitmap_hasAlpha },
677 { "nativeSetHasAlpha", "(IZ)V", (void*)Bitmap_setHasAlpha },
678 { "nativeHasMipMap", "(I)Z", (void*)Bitmap_hasMipMap },
679 { "nativeSetHasMipMap", "(IZ)V", (void*)Bitmap_setHasMipMap },
680 { "nativeCreateFromParcel",
681 "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
682 (void*)Bitmap_createFromParcel },
683 { "nativeWriteToParcel", "(IZILandroid/os/Parcel;)Z",
684 (void*)Bitmap_writeToParcel },
685 { "nativeExtractAlpha", "(II[I)Landroid/graphics/Bitmap;",
686 (void*)Bitmap_extractAlpha },
687 { "nativeGenerationId", "(I)I", (void*)Bitmap_getGenerationId },
688 { "nativeGetPixel", "(III)I", (void*)Bitmap_getPixel },
689 { "nativeGetPixels", "(I[IIIIIII)V", (void*)Bitmap_getPixels },
690 { "nativeSetPixel", "(IIII)V", (void*)Bitmap_setPixel },
691 { "nativeSetPixels", "(I[IIIIIII)V", (void*)Bitmap_setPixels },
692 { "nativeCopyPixelsToBuffer", "(ILjava/nio/Buffer;)V",
693 (void*)Bitmap_copyPixelsToBuffer },
694 { "nativeCopyPixelsFromBuffer", "(ILjava/nio/Buffer;)V",
695 (void*)Bitmap_copyPixelsFromBuffer },
696 { "nativeSameAs", "(II)Z", (void*)Bitmap_sameAs },
697 { "nativePrepareToDraw", "(I)V", (void*)Bitmap_prepareToDraw },
698 };
699
700 #define kClassPathName "android/graphics/Bitmap"
701
register_android_graphics_Bitmap(JNIEnv * env)702 int register_android_graphics_Bitmap(JNIEnv* env)
703 {
704 return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
705 gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods));
706 }
707