blob: 1b22e2d025638df0a973560fe03b880b11709097 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001#include "SkBitmap.h"
Patrick Dubroye4ac2d62010-12-01 11:23:13 -08002#include "SkPixelRef.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003#include "SkImageEncoder.h"
4#include "SkColorPriv.h"
5#include "GraphicsJNI.h"
6#include "SkDither.h"
7#include "SkUnPreMultiply.h"
8
Mathias Agopian07952722009-05-19 19:08:10 -07009#include <binder/Parcel.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010#include "android_util_Binder.h"
11#include "android_nio_utils.h"
12#include "CreateJavaOutputStreamAdaptor.h"
13
14#include <jni.h>
15
Romain Guy9aaa8262010-09-08 15:15:43 -070016#include <Caches.h>
17
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018#if 0
19 #define TRACE_BITMAP(code) code
20#else
21 #define TRACE_BITMAP(code)
22#endif
23
24///////////////////////////////////////////////////////////////////////////////
25// Conversions to/from SkColor, for get/setPixels, and the create method, which
26// is basically like setPixels
27
28typedef void (*FromColorProc)(void* dst, const SkColor src[], int width,
29 int x, int y);
30
31static void FromColor_D32(void* dst, const SkColor src[], int width,
32 int, int) {
33 SkPMColor* d = (SkPMColor*)dst;
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +080034
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035 for (int i = 0; i < width; i++) {
36 *d++ = SkPreMultiplyColor(*src++);
37 }
38}
39
40static void FromColor_D565(void* dst, const SkColor src[], int width,
41 int x, int y) {
42 uint16_t* d = (uint16_t*)dst;
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +080043
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044 DITHER_565_SCAN(y);
45 for (int stop = x + width; x < stop; x++) {
46 SkColor c = *src++;
47 *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c),
48 DITHER_VALUE(x));
49 }
50}
51
52static void FromColor_D4444(void* dst, const SkColor src[], int width,
53 int x, int y) {
54 SkPMColor16* d = (SkPMColor16*)dst;
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +080055
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056 DITHER_4444_SCAN(y);
57 for (int stop = x + width; x < stop; x++) {
58 SkPMColor c = SkPreMultiplyColor(*src++);
59 *d++ = SkDitherARGB32To4444(c, DITHER_VALUE(x));
60// *d++ = SkPixel32ToPixel4444(c);
61 }
62}
63
64// can return NULL
65static FromColorProc ChooseFromColorProc(SkBitmap::Config config) {
66 switch (config) {
67 case SkBitmap::kARGB_8888_Config:
68 return FromColor_D32;
69 case SkBitmap::kARGB_4444_Config:
70 return FromColor_D4444;
71 case SkBitmap::kRGB_565_Config:
72 return FromColor_D565;
73 default:
74 break;
75 }
76 return NULL;
77}
78
79bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors,
80 int srcOffset, int srcStride,
81 int x, int y, int width, int height,
82 const SkBitmap& dstBitmap) {
83 SkAutoLockPixels alp(dstBitmap);
84 void* dst = dstBitmap.getPixels();
85 FromColorProc proc = ChooseFromColorProc(dstBitmap.config());
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +080086
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087 if (NULL == dst || NULL == proc) {
88 return false;
89 }
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +080090
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091 const jint* array = env->GetIntArrayElements(srcColors, NULL);
92 const SkColor* src = (const SkColor*)array + srcOffset;
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +080093
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 // reset to to actual choice from caller
95 dst = dstBitmap.getAddr(x, y);
96 // now copy/convert each scanline
97 for (int y = 0; y < height; y++) {
98 proc(dst, src, width, x, y);
99 src += srcStride;
100 dst = (char*)dst + dstBitmap.rowBytes();
101 }
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800102
Romain Guy1a81aea2011-03-21 15:24:51 -0700103 dstBitmap.notifyPixelsChanged();
104
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array),
106 JNI_ABORT);
107 return true;
108}
109
110//////////////////// ToColor procs
111
112typedef void (*ToColorProc)(SkColor dst[], const void* src, int width,
113 SkColorTable*);
114
115static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width,
116 SkColorTable*) {
117 SkASSERT(width > 0);
118 const SkPMColor* s = (const SkPMColor*)src;
119 do {
120 *dst++ = SkUnPreMultiply::PMColorToColor(*s++);
121 } while (--width != 0);
122}
123
124static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width,
125 SkColorTable*) {
126 SkASSERT(width > 0);
127 const SkPMColor* s = (const SkPMColor*)src;
128 do {
129 SkPMColor c = *s++;
130 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
131 SkGetPackedB32(c));
132 } while (--width != 0);
133}
134
135static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width,
136 SkColorTable*) {
137 SkASSERT(width > 0);
138 const SkPMColor16* s = (const SkPMColor16*)src;
139 do {
140 *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++));
141 } while (--width != 0);
142}
143
144static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width,
145 SkColorTable*) {
146 SkASSERT(width > 0);
147 const SkPMColor* s = (const SkPMColor*)src;
148 do {
149 SkPMColor c = SkPixel4444ToPixel32(*s++);
150 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
151 SkGetPackedB32(c));
152 } while (--width != 0);
153}
154
155static void ToColor_S565(SkColor dst[], const void* src, int width,
156 SkColorTable*) {
157 SkASSERT(width > 0);
158 const uint16_t* s = (const uint16_t*)src;
159 do {
160 uint16_t c = *s++;
161 *dst++ = SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c),
162 SkPacked16ToB32(c));
163 } while (--width != 0);
164}
165
166static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width,
167 SkColorTable* ctable) {
168 SkASSERT(width > 0);
169 const uint8_t* s = (const uint8_t*)src;
170 const SkPMColor* colors = ctable->lockColors();
171 do {
172 *dst++ = SkUnPreMultiply::PMColorToColor(colors[*s++]);
173 } while (--width != 0);
174 ctable->unlockColors(false);
175}
176
177static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width,
178 SkColorTable* ctable) {
179 SkASSERT(width > 0);
180 const uint8_t* s = (const uint8_t*)src;
181 const SkPMColor* colors = ctable->lockColors();
182 do {
183 SkPMColor c = colors[*s++];
184 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
185 SkGetPackedB32(c));
186 } while (--width != 0);
187 ctable->unlockColors(false);
188}
189
190// can return NULL
191static ToColorProc ChooseToColorProc(const SkBitmap& src) {
192 switch (src.config()) {
193 case SkBitmap::kARGB_8888_Config:
194 return src.isOpaque() ? ToColor_S32_Opaque : ToColor_S32_Alpha;
195 case SkBitmap::kARGB_4444_Config:
196 return src.isOpaque() ? ToColor_S4444_Opaque : ToColor_S4444_Alpha;
197 case SkBitmap::kRGB_565_Config:
198 return ToColor_S565;
199 case SkBitmap::kIndex8_Config:
200 if (src.getColorTable() == NULL) {
201 return NULL;
202 }
203 return src.isOpaque() ? ToColor_SI8_Opaque : ToColor_SI8_Alpha;
204 default:
205 break;
206 }
207 return NULL;
208}
209
210///////////////////////////////////////////////////////////////////////////////
211///////////////////////////////////////////////////////////////////////////////
212
213static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
214 int offset, int stride, int width, int height,
215 SkBitmap::Config config, jboolean isMutable) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216 if (NULL != jColors) {
217 size_t n = env->GetArrayLength(jColors);
218 if (n < SkAbs32(stride) * (size_t)height) {
219 doThrowAIOOBE(env);
220 return NULL;
221 }
222 }
223
224 SkBitmap bitmap;
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800225
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 bitmap.setConfig(config, width, height);
Patrick Dubroye4ac2d62010-12-01 11:23:13 -0800227
228 jbyteArray buff = GraphicsJNI::allocateJavaPixelRef(env, &bitmap, NULL);
229 if (NULL == buff) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230 return NULL;
231 }
232
233 if (jColors != NULL) {
234 GraphicsJNI::SetPixels(env, jColors, offset, stride,
235 0, 0, width, height, bitmap);
236 }
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800237
Patrick Dubroye4ac2d62010-12-01 11:23:13 -0800238 return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), buff, isMutable, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239}
240
241static jobject Bitmap_copy(JNIEnv* env, jobject, const SkBitmap* src,
242 SkBitmap::Config dstConfig, jboolean isMutable) {
243 SkBitmap result;
Patrick Dubroye4ac2d62010-12-01 11:23:13 -0800244 JavaPixelAllocator allocator(env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245
246 if (!src->copyTo(&result, dstConfig, &allocator)) {
247 return NULL;
248 }
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800249
Patrick Dubroye4ac2d62010-12-01 11:23:13 -0800250 return GraphicsJNI::createBitmap(env, new SkBitmap(result), allocator.getStorageObj(), isMutable, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251}
252
253static void Bitmap_destructor(JNIEnv* env, jobject, SkBitmap* bitmap) {
Romain Guy9aaa8262010-09-08 15:15:43 -0700254#ifdef USE_OPENGL_RENDERER
Romain Guya2341a92010-09-08 18:04:33 -0700255 if (android::uirenderer::Caches::hasInstance()) {
Chet Haase5c13d892010-10-08 08:37:55 -0700256 android::uirenderer::Caches::getInstance().resourceCache.destructor(bitmap);
Chet Haase27f0b172010-10-22 08:52:33 -0700257 return;
Romain Guya2341a92010-09-08 18:04:33 -0700258 }
Chet Haase27f0b172010-10-22 08:52:33 -0700259#endif // USE_OPENGL_RENDERER
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 delete bitmap;
261}
262
263static void Bitmap_recycle(JNIEnv* env, jobject, SkBitmap* bitmap) {
Chet Haase5c13d892010-10-08 08:37:55 -0700264#ifdef USE_OPENGL_RENDERER
265 if (android::uirenderer::Caches::hasInstance()) {
266 android::uirenderer::Caches::getInstance().resourceCache.recycle(bitmap);
Chet Haase27f0b172010-10-22 08:52:33 -0700267 return;
Chet Haase5c13d892010-10-08 08:37:55 -0700268 }
Chet Haase5c13d892010-10-08 08:37:55 -0700269#endif // USE_OPENGL_RENDERER
Chet Haase27f0b172010-10-22 08:52:33 -0700270 bitmap->setPixels(NULL, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800271}
272
273// These must match the int values in Bitmap.java
274enum JavaEncodeFormat {
275 kJPEG_JavaEncodeFormat = 0,
276 kPNG_JavaEncodeFormat = 1
277};
278
279static bool Bitmap_compress(JNIEnv* env, jobject clazz, SkBitmap* bitmap,
280 int format, int quality,
281 jobject jstream, jbyteArray jstorage) {
282 SkImageEncoder::Type fm;
283
284 switch (format) {
285 case kJPEG_JavaEncodeFormat:
286 fm = SkImageEncoder::kJPEG_Type;
287 break;
288 case kPNG_JavaEncodeFormat:
289 fm = SkImageEncoder::kPNG_Type;
290 break;
291 default:
292 return false;
293 }
294
295 bool success = false;
296 SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
297 if (NULL != strm) {
298 SkImageEncoder* encoder = SkImageEncoder::Create(fm);
299 if (NULL != encoder) {
300 success = encoder->encodeStream(strm, *bitmap, quality);
301 delete encoder;
302 }
303 delete strm;
304 }
305 return success;
306}
307
308static void Bitmap_erase(JNIEnv* env, jobject, SkBitmap* bitmap, jint color) {
309 bitmap->eraseColor(color);
310}
311
312static int Bitmap_width(JNIEnv* env, jobject, SkBitmap* bitmap) {
313 return bitmap->width();
314}
315
316static int Bitmap_height(JNIEnv* env, jobject, SkBitmap* bitmap) {
317 return bitmap->height();
318}
319
320static int Bitmap_rowBytes(JNIEnv* env, jobject, SkBitmap* bitmap) {
321 return bitmap->rowBytes();
322}
323
324static int Bitmap_config(JNIEnv* env, jobject, SkBitmap* bitmap) {
325 return bitmap->config();
326}
327
Romain Guy0bbae082010-06-15 18:03:40 -0700328static int Bitmap_getGenerationId(JNIEnv* env, jobject, SkBitmap* bitmap) {
329 return bitmap->getGenerationID();
330}
331
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, SkBitmap* bitmap) {
333 return !bitmap->isOpaque();
334}
335
Mike Reeda78b0a22009-10-07 11:38:05 -0700336static void Bitmap_setHasAlpha(JNIEnv* env, jobject, SkBitmap* bitmap,
337 jboolean hasAlpha) {
338 bitmap->setIsOpaque(!hasAlpha);
339}
340
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341///////////////////////////////////////////////////////////////////////////////
342
343static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
344 if (parcel == NULL) {
345 SkDebugf("-------- unparcel parcel is NULL\n");
346 return NULL;
347 }
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800348
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 android::Parcel* p = android::parcelForJavaObject(env, parcel);
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800350
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 const bool isMutable = p->readInt32() != 0;
352 const SkBitmap::Config config = (SkBitmap::Config)p->readInt32();
353 const int width = p->readInt32();
354 const int height = p->readInt32();
355 const int rowBytes = p->readInt32();
Dianne Hackbornde0dfb72009-09-23 14:09:34 -0700356 const int density = p->readInt32();
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800357
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 if (SkBitmap::kARGB_8888_Config != config &&
359 SkBitmap::kRGB_565_Config != config &&
360 SkBitmap::kARGB_4444_Config != config &&
361 SkBitmap::kIndex8_Config != config &&
362 SkBitmap::kA8_Config != config) {
363 SkDebugf("Bitmap_createFromParcel unknown config: %d\n", config);
364 return NULL;
365 }
366
367 SkBitmap* bitmap = new SkBitmap;
368
369 bitmap->setConfig(config, width, height, rowBytes);
370
371 SkColorTable* ctable = NULL;
372 if (config == SkBitmap::kIndex8_Config) {
373 int count = p->readInt32();
374 if (count > 0) {
375 size_t size = count * sizeof(SkPMColor);
376 const SkPMColor* src = (const SkPMColor*)p->readInplace(size);
377 ctable = new SkColorTable(src, count);
378 }
379 }
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800380
Patrick Dubroye4ac2d62010-12-01 11:23:13 -0800381 jbyteArray buffer = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable);
382 if (NULL == buffer) {
Derek Sollenberger6062c592011-02-22 13:55:04 -0500383 SkSafeUnref(ctable);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 delete bitmap;
385 return NULL;
386 }
387
Derek Sollenberger6062c592011-02-22 13:55:04 -0500388 SkSafeUnref(ctable);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389
390 size_t size = bitmap->getSize();
391 bitmap->lockPixels();
392 memcpy(bitmap->getPixels(), p->readInplace(size), size);
393 bitmap->unlockPixels();
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800394
Patrick Dubroye4ac2d62010-12-01 11:23:13 -0800395 return GraphicsJNI::createBitmap(env, bitmap, buffer, isMutable, NULL, density);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396}
397
398static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
399 const SkBitmap* bitmap,
Dianne Hackbornde0dfb72009-09-23 14:09:34 -0700400 jboolean isMutable, jint density,
401 jobject parcel) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 if (parcel == NULL) {
403 SkDebugf("------- writeToParcel null parcel\n");
404 return false;
405 }
406
407 android::Parcel* p = android::parcelForJavaObject(env, parcel);
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800408
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409 p->writeInt32(isMutable);
410 p->writeInt32(bitmap->config());
411 p->writeInt32(bitmap->width());
412 p->writeInt32(bitmap->height());
413 p->writeInt32(bitmap->rowBytes());
Dianne Hackbornde0dfb72009-09-23 14:09:34 -0700414 p->writeInt32(density);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415
416 if (bitmap->getConfig() == SkBitmap::kIndex8_Config) {
417 SkColorTable* ctable = bitmap->getColorTable();
418 if (ctable != NULL) {
419 int count = ctable->count();
420 p->writeInt32(count);
421 memcpy(p->writeInplace(count * sizeof(SkPMColor)),
422 ctable->lockColors(), count * sizeof(SkPMColor));
423 ctable->unlockColors(false);
424 } else {
425 p->writeInt32(0); // indicate no ctable
426 }
427 }
428
429 size_t size = bitmap->getSize();
430 bitmap->lockPixels();
Jack Palevichdee4cb02010-12-13 11:13:32 -0800431 void* pDst = p->writeInplace(size);
432
433 const void* pSrc = bitmap->getPixels();
434
435 if (pSrc == NULL) {
436 memset(pDst, 0, size);
437 } else {
438 memcpy(pDst, pSrc, size);
439 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440 bitmap->unlockPixels();
441 return true;
442}
443
444static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
445 const SkBitmap* src, const SkPaint* paint,
446 jintArray offsetXY) {
447 SkIPoint offset;
448 SkBitmap* dst = new SkBitmap;
Patrick Dubroye4ac2d62010-12-01 11:23:13 -0800449 JavaPixelAllocator allocator(env);
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800450
Patrick Dubroye4ac2d62010-12-01 11:23:13 -0800451 src->extractAlpha(dst, paint, &allocator, &offset);
Eric Hassoldef7be262011-02-23 16:46:11 -0800452 // If Skia can't allocate pixels for destination bitmap, it resets
453 // it, that is set its pixels buffer to NULL, and zero width and height.
454 if (dst->getPixels() == NULL && src->getPixels() != NULL) {
455 delete dst;
456 doThrowOOME(env, "failed to allocate pixels for alpha");
457 return NULL;
458 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
460 int* array = env->GetIntArrayElements(offsetXY, NULL);
461 array[0] = offset.fX;
462 array[1] = offset.fY;
463 env->ReleaseIntArrayElements(offsetXY, array, 0);
464 }
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800465
Patrick Dubroye4ac2d62010-12-01 11:23:13 -0800466 return GraphicsJNI::createBitmap(env, dst, allocator.getStorageObj(), true, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467}
468
469///////////////////////////////////////////////////////////////////////////////
470
471static int Bitmap_getPixel(JNIEnv* env, jobject, const SkBitmap* bitmap,
472 int x, int y) {
473 SkAutoLockPixels alp(*bitmap);
474
475 ToColorProc proc = ChooseToColorProc(*bitmap);
476 if (NULL == proc) {
477 return 0;
478 }
479 const void* src = bitmap->getAddr(x, y);
480 if (NULL == src) {
481 return 0;
482 }
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800483
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800484 SkColor dst[1];
485 proc(dst, src, 1, bitmap->getColorTable());
486 return dst[0];
487}
488
489static void Bitmap_getPixels(JNIEnv* env, jobject, const SkBitmap* bitmap,
490 jintArray pixelArray, int offset, int stride,
491 int x, int y, int width, int height) {
492 SkAutoLockPixels alp(*bitmap);
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800493
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800494 ToColorProc proc = ChooseToColorProc(*bitmap);
495 if (NULL == proc) {
496 return;
497 }
498 const void* src = bitmap->getAddr(x, y);
499 if (NULL == src) {
500 return;
501 }
502
503 SkColorTable* ctable = bitmap->getColorTable();
504 jint* dst = env->GetIntArrayElements(pixelArray, NULL);
505 SkColor* d = (SkColor*)dst + offset;
506 while (--height >= 0) {
507 proc(d, src, width, ctable);
508 d += stride;
509 src = (void*)((const char*)src + bitmap->rowBytes());
510 }
511 env->ReleaseIntArrayElements(pixelArray, dst, 0);
512}
513
514///////////////////////////////////////////////////////////////////////////////
515
516static void Bitmap_setPixel(JNIEnv* env, jobject, const SkBitmap* bitmap,
517 int x, int y, SkColor color) {
518 SkAutoLockPixels alp(*bitmap);
519 if (NULL == bitmap->getPixels()) {
520 return;
521 }
522
523 FromColorProc proc = ChooseFromColorProc(bitmap->config());
524 if (NULL == proc) {
525 return;
526 }
527
528 proc(bitmap->getAddr(x, y), &color, 1, x, y);
Romain Guy1a81aea2011-03-21 15:24:51 -0700529 bitmap->notifyPixelsChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800530}
531
532static void Bitmap_setPixels(JNIEnv* env, jobject, const SkBitmap* bitmap,
533 jintArray pixelArray, int offset, int stride,
534 int x, int y, int width, int height) {
535 GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
536 x, y, width, height, *bitmap);
537}
538
539static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
540 const SkBitmap* bitmap, jobject jbuffer) {
541 SkAutoLockPixels alp(*bitmap);
542 const void* src = bitmap->getPixels();
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800543
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544 if (NULL != src) {
545 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
546
547 // the java side has already checked that buffer is large enough
548 memcpy(abp.pointer(), src, bitmap->getSize());
549 }
550}
551
552static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,
553 const SkBitmap* bitmap, jobject jbuffer) {
554 SkAutoLockPixels alp(*bitmap);
555 void* dst = bitmap->getPixels();
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800556
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 if (NULL != dst) {
558 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);
559 // the java side has already checked that buffer is large enough
560 memcpy(dst, abp.pointer(), bitmap->getSize());
561 }
562}
563
Mike Reed76d1e012010-03-05 17:42:30 -0500564static bool Bitmap_sameAs(JNIEnv* env, jobject, const SkBitmap* bm0,
565 const SkBitmap* bm1) {
566 if (bm0->width() != bm1->width() ||
567 bm0->height() != bm1->height() ||
568 bm0->config() != bm1->config()) {
569 return false;
570 }
571
572 SkAutoLockPixels alp0(*bm0);
573 SkAutoLockPixels alp1(*bm1);
574
575 // if we can't load the pixels, return false
576 if (NULL == bm0->getPixels() || NULL == bm1->getPixels()) {
577 return false;
578 }
579
580 if (bm0->config() == SkBitmap::kIndex8_Config) {
581 SkColorTable* ct0 = bm0->getColorTable();
582 SkColorTable* ct1 = bm1->getColorTable();
583 if (NULL == ct0 || NULL == ct1) {
584 return false;
585 }
586 if (ct0->count() != ct1->count()) {
587 return false;
588 }
589
590 SkAutoLockColors alc0(ct0);
591 SkAutoLockColors alc1(ct1);
592 const size_t size = ct0->count() * sizeof(SkPMColor);
593 if (memcmp(alc0.colors(), alc1.colors(), size) != 0) {
594 return false;
595 }
596 }
597
598 // now compare each scanline. We can't do the entire buffer at once,
599 // since we don't care about the pixel values that might extend beyond
600 // the width (since the scanline might be larger than the logical width)
601 const int h = bm0->height();
602 const size_t size = bm0->width() * bm0->bytesPerPixel();
603 for (int y = 0; y < h; y++) {
604 if (memcmp(bm0->getAddr(0, y), bm1->getAddr(0, y), size) != 0) {
605 return false;
606 }
607 }
608 return true;
609}
610
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800611static void Bitmap_prepareToDraw(JNIEnv* env, jobject, SkBitmap* bitmap) {
612 bitmap->lockPixels();
613 bitmap->unlockPixels();
614}
615
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616///////////////////////////////////////////////////////////////////////////////
617
618#include <android_runtime/AndroidRuntime.h>
619
620static JNINativeMethod gBitmapMethods[] = {
621 { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;",
622 (void*)Bitmap_creator },
623 { "nativeCopy", "(IIZ)Landroid/graphics/Bitmap;",
624 (void*)Bitmap_copy },
625 { "nativeDestructor", "(I)V", (void*)Bitmap_destructor },
626 { "nativeRecycle", "(I)V", (void*)Bitmap_recycle },
627 { "nativeCompress", "(IIILjava/io/OutputStream;[B)Z",
628 (void*)Bitmap_compress },
629 { "nativeErase", "(II)V", (void*)Bitmap_erase },
630 { "nativeWidth", "(I)I", (void*)Bitmap_width },
631 { "nativeHeight", "(I)I", (void*)Bitmap_height },
632 { "nativeRowBytes", "(I)I", (void*)Bitmap_rowBytes },
633 { "nativeConfig", "(I)I", (void*)Bitmap_config },
634 { "nativeHasAlpha", "(I)Z", (void*)Bitmap_hasAlpha },
Mike Reeda78b0a22009-10-07 11:38:05 -0700635 { "nativeSetHasAlpha", "(IZ)V", (void*)Bitmap_setHasAlpha },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 { "nativeCreateFromParcel",
637 "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
638 (void*)Bitmap_createFromParcel },
Dianne Hackbornde0dfb72009-09-23 14:09:34 -0700639 { "nativeWriteToParcel", "(IZILandroid/os/Parcel;)Z",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800640 (void*)Bitmap_writeToParcel },
641 { "nativeExtractAlpha", "(II[I)Landroid/graphics/Bitmap;",
642 (void*)Bitmap_extractAlpha },
Romain Guy0bbae082010-06-15 18:03:40 -0700643 { "nativeGenerationId", "(I)I", (void*)Bitmap_getGenerationId },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800644 { "nativeGetPixel", "(III)I", (void*)Bitmap_getPixel },
645 { "nativeGetPixels", "(I[IIIIIII)V", (void*)Bitmap_getPixels },
646 { "nativeSetPixel", "(IIII)V", (void*)Bitmap_setPixel },
647 { "nativeSetPixels", "(I[IIIIIII)V", (void*)Bitmap_setPixels },
648 { "nativeCopyPixelsToBuffer", "(ILjava/nio/Buffer;)V",
649 (void*)Bitmap_copyPixelsToBuffer },
650 { "nativeCopyPixelsFromBuffer", "(ILjava/nio/Buffer;)V",
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800651 (void*)Bitmap_copyPixelsFromBuffer },
Mike Reed76d1e012010-03-05 17:42:30 -0500652 { "nativeSameAs", "(II)Z", (void*)Bitmap_sameAs },
653 { "nativePrepareToDraw", "(I)V", (void*)Bitmap_prepareToDraw },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654};
655
656#define kClassPathName "android/graphics/Bitmap"
657
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658int register_android_graphics_Bitmap(JNIEnv* env)
659{
660 return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
661 gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods));
662}