blob: 8064836164629185ce376cb57810e91fa36f759a [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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array),
104 JNI_ABORT);
105 return true;
106}
107
108//////////////////// ToColor procs
109
110typedef void (*ToColorProc)(SkColor dst[], const void* src, int width,
111 SkColorTable*);
112
113static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width,
114 SkColorTable*) {
115 SkASSERT(width > 0);
116 const SkPMColor* s = (const SkPMColor*)src;
117 do {
118 *dst++ = SkUnPreMultiply::PMColorToColor(*s++);
119 } while (--width != 0);
120}
121
122static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width,
123 SkColorTable*) {
124 SkASSERT(width > 0);
125 const SkPMColor* s = (const SkPMColor*)src;
126 do {
127 SkPMColor c = *s++;
128 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
129 SkGetPackedB32(c));
130 } while (--width != 0);
131}
132
133static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width,
134 SkColorTable*) {
135 SkASSERT(width > 0);
136 const SkPMColor16* s = (const SkPMColor16*)src;
137 do {
138 *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++));
139 } while (--width != 0);
140}
141
142static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width,
143 SkColorTable*) {
144 SkASSERT(width > 0);
145 const SkPMColor* s = (const SkPMColor*)src;
146 do {
147 SkPMColor c = SkPixel4444ToPixel32(*s++);
148 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
149 SkGetPackedB32(c));
150 } while (--width != 0);
151}
152
153static void ToColor_S565(SkColor dst[], const void* src, int width,
154 SkColorTable*) {
155 SkASSERT(width > 0);
156 const uint16_t* s = (const uint16_t*)src;
157 do {
158 uint16_t c = *s++;
159 *dst++ = SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c),
160 SkPacked16ToB32(c));
161 } while (--width != 0);
162}
163
164static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width,
165 SkColorTable* ctable) {
166 SkASSERT(width > 0);
167 const uint8_t* s = (const uint8_t*)src;
168 const SkPMColor* colors = ctable->lockColors();
169 do {
170 *dst++ = SkUnPreMultiply::PMColorToColor(colors[*s++]);
171 } while (--width != 0);
172 ctable->unlockColors(false);
173}
174
175static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width,
176 SkColorTable* ctable) {
177 SkASSERT(width > 0);
178 const uint8_t* s = (const uint8_t*)src;
179 const SkPMColor* colors = ctable->lockColors();
180 do {
181 SkPMColor c = colors[*s++];
182 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
183 SkGetPackedB32(c));
184 } while (--width != 0);
185 ctable->unlockColors(false);
186}
187
188// can return NULL
189static ToColorProc ChooseToColorProc(const SkBitmap& src) {
190 switch (src.config()) {
191 case SkBitmap::kARGB_8888_Config:
192 return src.isOpaque() ? ToColor_S32_Opaque : ToColor_S32_Alpha;
193 case SkBitmap::kARGB_4444_Config:
194 return src.isOpaque() ? ToColor_S4444_Opaque : ToColor_S4444_Alpha;
195 case SkBitmap::kRGB_565_Config:
196 return ToColor_S565;
197 case SkBitmap::kIndex8_Config:
198 if (src.getColorTable() == NULL) {
199 return NULL;
200 }
201 return src.isOpaque() ? ToColor_SI8_Opaque : ToColor_SI8_Alpha;
202 default:
203 break;
204 }
205 return NULL;
206}
207
208///////////////////////////////////////////////////////////////////////////////
209///////////////////////////////////////////////////////////////////////////////
210
211static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
212 int offset, int stride, int width, int height,
213 SkBitmap::Config config, jboolean isMutable) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214 if (NULL != jColors) {
215 size_t n = env->GetArrayLength(jColors);
216 if (n < SkAbs32(stride) * (size_t)height) {
217 doThrowAIOOBE(env);
218 return NULL;
219 }
220 }
221
222 SkBitmap bitmap;
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800223
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224 bitmap.setConfig(config, width, height);
Patrick Dubroye4ac2d62010-12-01 11:23:13 -0800225
226 jbyteArray buff = GraphicsJNI::allocateJavaPixelRef(env, &bitmap, NULL);
227 if (NULL == buff) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 return NULL;
229 }
230
231 if (jColors != NULL) {
232 GraphicsJNI::SetPixels(env, jColors, offset, stride,
233 0, 0, width, height, bitmap);
234 }
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800235
Patrick Dubroye4ac2d62010-12-01 11:23:13 -0800236 return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), buff, isMutable, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237}
238
239static jobject Bitmap_copy(JNIEnv* env, jobject, const SkBitmap* src,
240 SkBitmap::Config dstConfig, jboolean isMutable) {
241 SkBitmap result;
Patrick Dubroye4ac2d62010-12-01 11:23:13 -0800242 JavaPixelAllocator allocator(env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243
244 if (!src->copyTo(&result, dstConfig, &allocator)) {
245 return NULL;
246 }
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800247
Patrick Dubroye4ac2d62010-12-01 11:23:13 -0800248 return GraphicsJNI::createBitmap(env, new SkBitmap(result), allocator.getStorageObj(), isMutable, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249}
250
251static void Bitmap_destructor(JNIEnv* env, jobject, SkBitmap* bitmap) {
Romain Guy9aaa8262010-09-08 15:15:43 -0700252#ifdef USE_OPENGL_RENDERER
Romain Guya2341a92010-09-08 18:04:33 -0700253 if (android::uirenderer::Caches::hasInstance()) {
Chet Haase5c13d892010-10-08 08:37:55 -0700254 android::uirenderer::Caches::getInstance().resourceCache.destructor(bitmap);
Chet Haase27f0b172010-10-22 08:52:33 -0700255 return;
Romain Guya2341a92010-09-08 18:04:33 -0700256 }
Chet Haase27f0b172010-10-22 08:52:33 -0700257#endif // USE_OPENGL_RENDERER
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 delete bitmap;
259}
260
261static void Bitmap_recycle(JNIEnv* env, jobject, SkBitmap* bitmap) {
Chet Haase5c13d892010-10-08 08:37:55 -0700262#ifdef USE_OPENGL_RENDERER
263 if (android::uirenderer::Caches::hasInstance()) {
264 android::uirenderer::Caches::getInstance().resourceCache.recycle(bitmap);
Chet Haase27f0b172010-10-22 08:52:33 -0700265 return;
Chet Haase5c13d892010-10-08 08:37:55 -0700266 }
Chet Haase5c13d892010-10-08 08:37:55 -0700267#endif // USE_OPENGL_RENDERER
Chet Haase27f0b172010-10-22 08:52:33 -0700268 bitmap->setPixels(NULL, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269}
270
271// These must match the int values in Bitmap.java
272enum JavaEncodeFormat {
273 kJPEG_JavaEncodeFormat = 0,
274 kPNG_JavaEncodeFormat = 1
275};
276
277static bool Bitmap_compress(JNIEnv* env, jobject clazz, SkBitmap* bitmap,
278 int format, int quality,
279 jobject jstream, jbyteArray jstorage) {
280 SkImageEncoder::Type fm;
281
282 switch (format) {
283 case kJPEG_JavaEncodeFormat:
284 fm = SkImageEncoder::kJPEG_Type;
285 break;
286 case kPNG_JavaEncodeFormat:
287 fm = SkImageEncoder::kPNG_Type;
288 break;
289 default:
290 return false;
291 }
292
293 bool success = false;
294 SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
295 if (NULL != strm) {
296 SkImageEncoder* encoder = SkImageEncoder::Create(fm);
297 if (NULL != encoder) {
298 success = encoder->encodeStream(strm, *bitmap, quality);
299 delete encoder;
300 }
301 delete strm;
302 }
303 return success;
304}
305
306static void Bitmap_erase(JNIEnv* env, jobject, SkBitmap* bitmap, jint color) {
307 bitmap->eraseColor(color);
308}
309
310static int Bitmap_width(JNIEnv* env, jobject, SkBitmap* bitmap) {
311 return bitmap->width();
312}
313
314static int Bitmap_height(JNIEnv* env, jobject, SkBitmap* bitmap) {
315 return bitmap->height();
316}
317
318static int Bitmap_rowBytes(JNIEnv* env, jobject, SkBitmap* bitmap) {
319 return bitmap->rowBytes();
320}
321
322static int Bitmap_config(JNIEnv* env, jobject, SkBitmap* bitmap) {
323 return bitmap->config();
324}
325
Romain Guy0bbae082010-06-15 18:03:40 -0700326static int Bitmap_getGenerationId(JNIEnv* env, jobject, SkBitmap* bitmap) {
327 return bitmap->getGenerationID();
328}
329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, SkBitmap* bitmap) {
331 return !bitmap->isOpaque();
332}
333
Mike Reeda78b0a22009-10-07 11:38:05 -0700334static void Bitmap_setHasAlpha(JNIEnv* env, jobject, SkBitmap* bitmap,
335 jboolean hasAlpha) {
336 bitmap->setIsOpaque(!hasAlpha);
337}
338
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339///////////////////////////////////////////////////////////////////////////////
340
341static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
342 if (parcel == NULL) {
343 SkDebugf("-------- unparcel parcel is NULL\n");
344 return NULL;
345 }
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800346
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800347 android::Parcel* p = android::parcelForJavaObject(env, parcel);
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800348
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 const bool isMutable = p->readInt32() != 0;
350 const SkBitmap::Config config = (SkBitmap::Config)p->readInt32();
351 const int width = p->readInt32();
352 const int height = p->readInt32();
353 const int rowBytes = p->readInt32();
Dianne Hackbornde0dfb72009-09-23 14:09:34 -0700354 const int density = p->readInt32();
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800355
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800356 if (SkBitmap::kARGB_8888_Config != config &&
357 SkBitmap::kRGB_565_Config != config &&
358 SkBitmap::kARGB_4444_Config != config &&
359 SkBitmap::kIndex8_Config != config &&
360 SkBitmap::kA8_Config != config) {
361 SkDebugf("Bitmap_createFromParcel unknown config: %d\n", config);
362 return NULL;
363 }
364
365 SkBitmap* bitmap = new SkBitmap;
366
367 bitmap->setConfig(config, width, height, rowBytes);
368
369 SkColorTable* ctable = NULL;
370 if (config == SkBitmap::kIndex8_Config) {
371 int count = p->readInt32();
372 if (count > 0) {
373 size_t size = count * sizeof(SkPMColor);
374 const SkPMColor* src = (const SkPMColor*)p->readInplace(size);
375 ctable = new SkColorTable(src, count);
376 }
377 }
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800378
Patrick Dubroye4ac2d62010-12-01 11:23:13 -0800379 jbyteArray buffer = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable);
380 if (NULL == buffer) {
Derek Sollenberger6062c592011-02-22 13:55:04 -0500381 SkSafeUnref(ctable);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 delete bitmap;
383 return NULL;
384 }
385
Derek Sollenberger6062c592011-02-22 13:55:04 -0500386 SkSafeUnref(ctable);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387
388 size_t size = bitmap->getSize();
389 bitmap->lockPixels();
390 memcpy(bitmap->getPixels(), p->readInplace(size), size);
391 bitmap->unlockPixels();
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800392
Patrick Dubroye4ac2d62010-12-01 11:23:13 -0800393 return GraphicsJNI::createBitmap(env, bitmap, buffer, isMutable, NULL, density);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394}
395
396static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
397 const SkBitmap* bitmap,
Dianne Hackbornde0dfb72009-09-23 14:09:34 -0700398 jboolean isMutable, jint density,
399 jobject parcel) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 if (parcel == NULL) {
401 SkDebugf("------- writeToParcel null parcel\n");
402 return false;
403 }
404
405 android::Parcel* p = android::parcelForJavaObject(env, parcel);
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800406
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407 p->writeInt32(isMutable);
408 p->writeInt32(bitmap->config());
409 p->writeInt32(bitmap->width());
410 p->writeInt32(bitmap->height());
411 p->writeInt32(bitmap->rowBytes());
Dianne Hackbornde0dfb72009-09-23 14:09:34 -0700412 p->writeInt32(density);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413
414 if (bitmap->getConfig() == SkBitmap::kIndex8_Config) {
415 SkColorTable* ctable = bitmap->getColorTable();
416 if (ctable != NULL) {
417 int count = ctable->count();
418 p->writeInt32(count);
419 memcpy(p->writeInplace(count * sizeof(SkPMColor)),
420 ctable->lockColors(), count * sizeof(SkPMColor));
421 ctable->unlockColors(false);
422 } else {
423 p->writeInt32(0); // indicate no ctable
424 }
425 }
426
427 size_t size = bitmap->getSize();
428 bitmap->lockPixels();
Jack Palevichdee4cb02010-12-13 11:13:32 -0800429 void* pDst = p->writeInplace(size);
430
431 const void* pSrc = bitmap->getPixels();
432
433 if (pSrc == NULL) {
434 memset(pDst, 0, size);
435 } else {
436 memcpy(pDst, pSrc, size);
437 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438 bitmap->unlockPixels();
439 return true;
440}
441
442static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
443 const SkBitmap* src, const SkPaint* paint,
444 jintArray offsetXY) {
445 SkIPoint offset;
446 SkBitmap* dst = new SkBitmap;
Patrick Dubroye4ac2d62010-12-01 11:23:13 -0800447 JavaPixelAllocator allocator(env);
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800448
Patrick Dubroye4ac2d62010-12-01 11:23:13 -0800449 src->extractAlpha(dst, paint, &allocator, &offset);
Eric Hassoldef7be262011-02-23 16:46:11 -0800450 // If Skia can't allocate pixels for destination bitmap, it resets
451 // it, that is set its pixels buffer to NULL, and zero width and height.
452 if (dst->getPixels() == NULL && src->getPixels() != NULL) {
453 delete dst;
454 doThrowOOME(env, "failed to allocate pixels for alpha");
455 return NULL;
456 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
458 int* array = env->GetIntArrayElements(offsetXY, NULL);
459 array[0] = offset.fX;
460 array[1] = offset.fY;
461 env->ReleaseIntArrayElements(offsetXY, array, 0);
462 }
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800463
Patrick Dubroye4ac2d62010-12-01 11:23:13 -0800464 return GraphicsJNI::createBitmap(env, dst, allocator.getStorageObj(), true, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465}
466
467///////////////////////////////////////////////////////////////////////////////
468
469static int Bitmap_getPixel(JNIEnv* env, jobject, const SkBitmap* bitmap,
470 int x, int y) {
471 SkAutoLockPixels alp(*bitmap);
472
473 ToColorProc proc = ChooseToColorProc(*bitmap);
474 if (NULL == proc) {
475 return 0;
476 }
477 const void* src = bitmap->getAddr(x, y);
478 if (NULL == src) {
479 return 0;
480 }
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800481
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800482 SkColor dst[1];
483 proc(dst, src, 1, bitmap->getColorTable());
484 return dst[0];
485}
486
487static void Bitmap_getPixels(JNIEnv* env, jobject, const SkBitmap* bitmap,
488 jintArray pixelArray, int offset, int stride,
489 int x, int y, int width, int height) {
490 SkAutoLockPixels alp(*bitmap);
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800491
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800492 ToColorProc proc = ChooseToColorProc(*bitmap);
493 if (NULL == proc) {
494 return;
495 }
496 const void* src = bitmap->getAddr(x, y);
497 if (NULL == src) {
498 return;
499 }
500
501 SkColorTable* ctable = bitmap->getColorTable();
502 jint* dst = env->GetIntArrayElements(pixelArray, NULL);
503 SkColor* d = (SkColor*)dst + offset;
504 while (--height >= 0) {
505 proc(d, src, width, ctable);
506 d += stride;
507 src = (void*)((const char*)src + bitmap->rowBytes());
508 }
509 env->ReleaseIntArrayElements(pixelArray, dst, 0);
510}
511
512///////////////////////////////////////////////////////////////////////////////
513
514static void Bitmap_setPixel(JNIEnv* env, jobject, const SkBitmap* bitmap,
515 int x, int y, SkColor color) {
516 SkAutoLockPixels alp(*bitmap);
517 if (NULL == bitmap->getPixels()) {
518 return;
519 }
520
521 FromColorProc proc = ChooseFromColorProc(bitmap->config());
522 if (NULL == proc) {
523 return;
524 }
525
526 proc(bitmap->getAddr(x, y), &color, 1, x, y);
527}
528
529static void Bitmap_setPixels(JNIEnv* env, jobject, const SkBitmap* bitmap,
530 jintArray pixelArray, int offset, int stride,
531 int x, int y, int width, int height) {
532 GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
533 x, y, width, height, *bitmap);
534}
535
536static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
537 const SkBitmap* bitmap, jobject jbuffer) {
538 SkAutoLockPixels alp(*bitmap);
539 const void* src = bitmap->getPixels();
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800540
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 if (NULL != src) {
542 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
543
544 // the java side has already checked that buffer is large enough
545 memcpy(abp.pointer(), src, bitmap->getSize());
546 }
547}
548
549static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,
550 const SkBitmap* bitmap, jobject jbuffer) {
551 SkAutoLockPixels alp(*bitmap);
552 void* dst = bitmap->getPixels();
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800553
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800554 if (NULL != dst) {
555 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);
556 // the java side has already checked that buffer is large enough
557 memcpy(dst, abp.pointer(), bitmap->getSize());
558 }
559}
560
Mike Reed76d1e012010-03-05 17:42:30 -0500561static bool Bitmap_sameAs(JNIEnv* env, jobject, const SkBitmap* bm0,
562 const SkBitmap* bm1) {
563 if (bm0->width() != bm1->width() ||
564 bm0->height() != bm1->height() ||
565 bm0->config() != bm1->config()) {
566 return false;
567 }
568
569 SkAutoLockPixels alp0(*bm0);
570 SkAutoLockPixels alp1(*bm1);
571
572 // if we can't load the pixels, return false
573 if (NULL == bm0->getPixels() || NULL == bm1->getPixels()) {
574 return false;
575 }
576
577 if (bm0->config() == SkBitmap::kIndex8_Config) {
578 SkColorTable* ct0 = bm0->getColorTable();
579 SkColorTable* ct1 = bm1->getColorTable();
580 if (NULL == ct0 || NULL == ct1) {
581 return false;
582 }
583 if (ct0->count() != ct1->count()) {
584 return false;
585 }
586
587 SkAutoLockColors alc0(ct0);
588 SkAutoLockColors alc1(ct1);
589 const size_t size = ct0->count() * sizeof(SkPMColor);
590 if (memcmp(alc0.colors(), alc1.colors(), size) != 0) {
591 return false;
592 }
593 }
594
595 // now compare each scanline. We can't do the entire buffer at once,
596 // since we don't care about the pixel values that might extend beyond
597 // the width (since the scanline might be larger than the logical width)
598 const int h = bm0->height();
599 const size_t size = bm0->width() * bm0->bytesPerPixel();
600 for (int y = 0; y < h; y++) {
601 if (memcmp(bm0->getAddr(0, y), bm1->getAddr(0, y), size) != 0) {
602 return false;
603 }
604 }
605 return true;
606}
607
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800608static void Bitmap_prepareToDraw(JNIEnv* env, jobject, SkBitmap* bitmap) {
609 bitmap->lockPixels();
610 bitmap->unlockPixels();
611}
612
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613///////////////////////////////////////////////////////////////////////////////
614
615#include <android_runtime/AndroidRuntime.h>
616
617static JNINativeMethod gBitmapMethods[] = {
618 { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;",
619 (void*)Bitmap_creator },
620 { "nativeCopy", "(IIZ)Landroid/graphics/Bitmap;",
621 (void*)Bitmap_copy },
622 { "nativeDestructor", "(I)V", (void*)Bitmap_destructor },
623 { "nativeRecycle", "(I)V", (void*)Bitmap_recycle },
624 { "nativeCompress", "(IIILjava/io/OutputStream;[B)Z",
625 (void*)Bitmap_compress },
626 { "nativeErase", "(II)V", (void*)Bitmap_erase },
627 { "nativeWidth", "(I)I", (void*)Bitmap_width },
628 { "nativeHeight", "(I)I", (void*)Bitmap_height },
629 { "nativeRowBytes", "(I)I", (void*)Bitmap_rowBytes },
630 { "nativeConfig", "(I)I", (void*)Bitmap_config },
631 { "nativeHasAlpha", "(I)Z", (void*)Bitmap_hasAlpha },
Mike Reeda78b0a22009-10-07 11:38:05 -0700632 { "nativeSetHasAlpha", "(IZ)V", (void*)Bitmap_setHasAlpha },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 { "nativeCreateFromParcel",
634 "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
635 (void*)Bitmap_createFromParcel },
Dianne Hackbornde0dfb72009-09-23 14:09:34 -0700636 { "nativeWriteToParcel", "(IZILandroid/os/Parcel;)Z",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 (void*)Bitmap_writeToParcel },
638 { "nativeExtractAlpha", "(II[I)Landroid/graphics/Bitmap;",
639 (void*)Bitmap_extractAlpha },
Romain Guy0bbae082010-06-15 18:03:40 -0700640 { "nativeGenerationId", "(I)I", (void*)Bitmap_getGenerationId },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800641 { "nativeGetPixel", "(III)I", (void*)Bitmap_getPixel },
642 { "nativeGetPixels", "(I[IIIIIII)V", (void*)Bitmap_getPixels },
643 { "nativeSetPixel", "(IIII)V", (void*)Bitmap_setPixel },
644 { "nativeSetPixels", "(I[IIIIIII)V", (void*)Bitmap_setPixels },
645 { "nativeCopyPixelsToBuffer", "(ILjava/nio/Buffer;)V",
646 (void*)Bitmap_copyPixelsToBuffer },
647 { "nativeCopyPixelsFromBuffer", "(ILjava/nio/Buffer;)V",
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800648 (void*)Bitmap_copyPixelsFromBuffer },
Mike Reed76d1e012010-03-05 17:42:30 -0500649 { "nativeSameAs", "(II)Z", (void*)Bitmap_sameAs },
650 { "nativePrepareToDraw", "(I)V", (void*)Bitmap_prepareToDraw },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800651};
652
653#define kClassPathName "android/graphics/Bitmap"
654
655int register_android_graphics_Bitmap(JNIEnv* env);
656int register_android_graphics_Bitmap(JNIEnv* env)
657{
658 return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
659 gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods));
660}