blob: b03d12aa2057ba6679e05696072ea0af45692c64 [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>
Romain Guy713e1bb2012-10-16 18:44:09 -070010#include "android_os_Parcel.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011#include "android_util_Binder.h"
12#include "android_nio_utils.h"
13#include "CreateJavaOutputStreamAdaptor.h"
14
15#include <jni.h>
16
Romain Guy9aaa8262010-09-08 15:15:43 -070017#include <Caches.h>
18
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019#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
29typedef void (*FromColorProc)(void* dst, const SkColor src[], int width,
30 int x, int y);
31
32static void FromColor_D32(void* dst, const SkColor src[], int width,
33 int, int) {
34 SkPMColor* d = (SkPMColor*)dst;
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +080035
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036 for (int i = 0; i < width; i++) {
37 *d++ = SkPreMultiplyColor(*src++);
38 }
39}
40
41static void FromColor_D565(void* dst, const SkColor src[], int width,
42 int x, int y) {
43 uint16_t* d = (uint16_t*)dst;
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +080044
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045 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
53static void FromColor_D4444(void* dst, const SkColor src[], int width,
54 int x, int y) {
55 SkPMColor16* d = (SkPMColor16*)dst;
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +080056
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057 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
66static 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
80bool 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());
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +080087
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 if (NULL == dst || NULL == proc) {
89 return false;
90 }
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +080091
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 const jint* array = env->GetIntArrayElements(srcColors, NULL);
93 const SkColor* src = (const SkColor*)array + srcOffset;
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +080094
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095 // 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 }
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800103
Romain Guy1a81aea2011-03-21 15:24:51 -0700104 dstBitmap.notifyPixelsChanged();
105
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array),
107 JNI_ABORT);
108 return true;
109}
110
111//////////////////// ToColor procs
112
113typedef void (*ToColorProc)(SkColor dst[], const void* src, int width,
114 SkColorTable*);
115
116static 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
125static 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
136static 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
145static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width,
146 SkColorTable*) {
147 SkASSERT(width > 0);
Keun young Park038953d2012-10-12 11:36:13 -0700148 const SkPMColor16* s = (const SkPMColor16*)src;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149 do {
150 SkPMColor c = SkPixel4444ToPixel32(*s++);
151 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
152 SkGetPackedB32(c));
153 } while (--width != 0);
154}
155
156static 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
167static 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
178static 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
192static 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
214static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
215 int offset, int stride, int width, int height,
216 SkBitmap::Config config, jboolean isMutable) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 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;
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800226
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227 bitmap.setConfig(config, width, height);
Patrick Dubroye4ac2d62010-12-01 11:23:13 -0800228
229 jbyteArray buff = GraphicsJNI::allocateJavaPixelRef(env, &bitmap, NULL);
230 if (NULL == buff) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231 return NULL;
232 }
233
234 if (jColors != NULL) {
235 GraphicsJNI::SetPixels(env, jColors, offset, stride,
236 0, 0, width, height, bitmap);
237 }
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800238
Amith Yamasaniec4a5042012-04-04 10:27:15 -0700239 return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), buff, isMutable, NULL, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240}
241
242static jobject Bitmap_copy(JNIEnv* env, jobject, const SkBitmap* src,
243 SkBitmap::Config dstConfig, jboolean isMutable) {
244 SkBitmap result;
Patrick Dubroye4ac2d62010-12-01 11:23:13 -0800245 JavaPixelAllocator allocator(env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246
247 if (!src->copyTo(&result, dstConfig, &allocator)) {
248 return NULL;
249 }
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800250
Amith Yamasaniec4a5042012-04-04 10:27:15 -0700251 return GraphicsJNI::createBitmap(env, new SkBitmap(result), allocator.getStorageObj(), isMutable, NULL, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252}
253
254static void Bitmap_destructor(JNIEnv* env, jobject, SkBitmap* bitmap) {
Romain Guy9aaa8262010-09-08 15:15:43 -0700255#ifdef USE_OPENGL_RENDERER
Romain Guya2341a92010-09-08 18:04:33 -0700256 if (android::uirenderer::Caches::hasInstance()) {
Chet Haase5c13d892010-10-08 08:37:55 -0700257 android::uirenderer::Caches::getInstance().resourceCache.destructor(bitmap);
Chet Haase27f0b172010-10-22 08:52:33 -0700258 return;
Romain Guya2341a92010-09-08 18:04:33 -0700259 }
Chet Haase27f0b172010-10-22 08:52:33 -0700260#endif // USE_OPENGL_RENDERER
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 delete bitmap;
262}
263
Chet Haase547e6652012-10-22 15:07:26 -0700264static jboolean Bitmap_recycle(JNIEnv* env, jobject, SkBitmap* bitmap) {
Chet Haase5c13d892010-10-08 08:37:55 -0700265#ifdef USE_OPENGL_RENDERER
266 if (android::uirenderer::Caches::hasInstance()) {
Chet Haase547e6652012-10-22 15:07:26 -0700267 return android::uirenderer::Caches::getInstance().resourceCache.recycle(bitmap);
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);
Chet Haase547e6652012-10-22 15:07:26 -0700271 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272}
273
Chris Craikc84d2032013-07-12 19:35:52 -0700274static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jint bitmapInt,
275 int width, int height, SkBitmap::Config config, int allocSize) {
276 if (width * height * SkBitmap::ComputeBytesPerPixel(config) > allocSize) {
277 // done in native as there's no way to get BytesPerPixel in Java
278 doThrowIAE(env, "Bitmap not large enough to support new configuration");
279 return;
280 }
281 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapInt);
282 SkPixelRef* ref = bitmap->pixelRef();
283 SkSafeRef(ref);
284 bitmap->setConfig(config, width, height);
285 bitmap->setPixelRef(ref);
286
287 // notifyPixelsChanged will increment the generation ID even though the actual pixel data
288 // hasn't been touched. This signals the renderer that the bitmap (including width, height,
289 // and config) has changed.
290 ref->notifyPixelsChanged();
291 SkSafeUnref(ref);
292}
293
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294// These must match the int values in Bitmap.java
295enum JavaEncodeFormat {
296 kJPEG_JavaEncodeFormat = 0,
Vikas Arora2305ac92011-06-23 13:11:13 +0530297 kPNG_JavaEncodeFormat = 1,
298 kWEBP_JavaEncodeFormat = 2
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299};
300
301static bool Bitmap_compress(JNIEnv* env, jobject clazz, SkBitmap* bitmap,
302 int format, int quality,
303 jobject jstream, jbyteArray jstorage) {
304 SkImageEncoder::Type fm;
305
306 switch (format) {
307 case kJPEG_JavaEncodeFormat:
308 fm = SkImageEncoder::kJPEG_Type;
309 break;
310 case kPNG_JavaEncodeFormat:
311 fm = SkImageEncoder::kPNG_Type;
312 break;
Vikas Arora2305ac92011-06-23 13:11:13 +0530313 case kWEBP_JavaEncodeFormat:
314 fm = SkImageEncoder::kWEBP_Type;
315 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 default:
317 return false;
318 }
319
320 bool success = false;
Michal Stawinski35ef5672012-07-08 12:25:45 +0200321 if (NULL != bitmap) {
322 SkAutoLockPixels alp(*bitmap);
323
324 if (NULL == bitmap->getPixels()) {
325 return false;
326 }
327
328 SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
329 if (NULL == strm) {
330 return false;
331 }
332
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800333 SkImageEncoder* encoder = SkImageEncoder::Create(fm);
334 if (NULL != encoder) {
335 success = encoder->encodeStream(strm, *bitmap, quality);
336 delete encoder;
337 }
338 delete strm;
339 }
340 return success;
341}
342
343static void Bitmap_erase(JNIEnv* env, jobject, SkBitmap* bitmap, jint color) {
344 bitmap->eraseColor(color);
345}
346
347static int Bitmap_width(JNIEnv* env, jobject, SkBitmap* bitmap) {
348 return bitmap->width();
349}
350
351static int Bitmap_height(JNIEnv* env, jobject, SkBitmap* bitmap) {
352 return bitmap->height();
353}
354
355static int Bitmap_rowBytes(JNIEnv* env, jobject, SkBitmap* bitmap) {
356 return bitmap->rowBytes();
357}
358
359static int Bitmap_config(JNIEnv* env, jobject, SkBitmap* bitmap) {
360 return bitmap->config();
361}
362
Romain Guy0bbae082010-06-15 18:03:40 -0700363static int Bitmap_getGenerationId(JNIEnv* env, jobject, SkBitmap* bitmap) {
364 return bitmap->getGenerationID();
365}
366
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, SkBitmap* bitmap) {
368 return !bitmap->isOpaque();
369}
370
Mike Reeda78b0a22009-10-07 11:38:05 -0700371static void Bitmap_setHasAlpha(JNIEnv* env, jobject, SkBitmap* bitmap,
372 jboolean hasAlpha) {
373 bitmap->setIsOpaque(!hasAlpha);
374}
375
Romain Guy713e1bb2012-10-16 18:44:09 -0700376static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, SkBitmap* bitmap) {
377 return bitmap->hasHardwareMipMap();
378}
379
380static void Bitmap_setHasMipMap(JNIEnv* env, jobject, SkBitmap* bitmap,
381 jboolean hasMipMap) {
382 bitmap->setHasHardwareMipMap(hasMipMap);
383}
384
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385///////////////////////////////////////////////////////////////////////////////
386
387static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
388 if (parcel == NULL) {
389 SkDebugf("-------- unparcel parcel is NULL\n");
390 return NULL;
391 }
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800392
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393 android::Parcel* p = android::parcelForJavaObject(env, parcel);
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800394
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 const bool isMutable = p->readInt32() != 0;
396 const SkBitmap::Config config = (SkBitmap::Config)p->readInt32();
397 const int width = p->readInt32();
398 const int height = p->readInt32();
399 const int rowBytes = p->readInt32();
Dianne Hackbornde0dfb72009-09-23 14:09:34 -0700400 const int density = p->readInt32();
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800401
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 if (SkBitmap::kARGB_8888_Config != config &&
403 SkBitmap::kRGB_565_Config != config &&
404 SkBitmap::kARGB_4444_Config != config &&
405 SkBitmap::kIndex8_Config != config &&
406 SkBitmap::kA8_Config != config) {
407 SkDebugf("Bitmap_createFromParcel unknown config: %d\n", config);
408 return NULL;
409 }
410
411 SkBitmap* bitmap = new SkBitmap;
412
413 bitmap->setConfig(config, width, height, rowBytes);
414
415 SkColorTable* ctable = NULL;
416 if (config == SkBitmap::kIndex8_Config) {
417 int count = p->readInt32();
418 if (count > 0) {
419 size_t size = count * sizeof(SkPMColor);
420 const SkPMColor* src = (const SkPMColor*)p->readInplace(size);
421 ctable = new SkColorTable(src, count);
422 }
423 }
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800424
Patrick Dubroye4ac2d62010-12-01 11:23:13 -0800425 jbyteArray buffer = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable);
426 if (NULL == buffer) {
Derek Sollenberger6062c592011-02-22 13:55:04 -0500427 SkSafeUnref(ctable);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 delete bitmap;
429 return NULL;
430 }
431
Derek Sollenberger6062c592011-02-22 13:55:04 -0500432 SkSafeUnref(ctable);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433
434 size_t size = bitmap->getSize();
Jeff Brown6579a9d2011-09-23 21:17:56 -0700435
436 android::Parcel::ReadableBlob blob;
437 android::status_t status = p->readBlob(size, &blob);
438 if (status) {
439 doThrowRE(env, "Could not read bitmap from parcel blob.");
440 delete bitmap;
441 return NULL;
442 }
443
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444 bitmap->lockPixels();
Jeff Brown6579a9d2011-09-23 21:17:56 -0700445 memcpy(bitmap->getPixels(), blob.data(), size);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800446 bitmap->unlockPixels();
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800447
Jeff Brown6579a9d2011-09-23 21:17:56 -0700448 blob.release();
Amith Yamasaniec4a5042012-04-04 10:27:15 -0700449 return GraphicsJNI::createBitmap(env, bitmap, buffer, isMutable, NULL, NULL, density);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800450}
451
452static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
453 const SkBitmap* bitmap,
Dianne Hackbornde0dfb72009-09-23 14:09:34 -0700454 jboolean isMutable, jint density,
455 jobject parcel) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800456 if (parcel == NULL) {
457 SkDebugf("------- writeToParcel null parcel\n");
458 return false;
459 }
460
461 android::Parcel* p = android::parcelForJavaObject(env, parcel);
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800462
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463 p->writeInt32(isMutable);
464 p->writeInt32(bitmap->config());
465 p->writeInt32(bitmap->width());
466 p->writeInt32(bitmap->height());
467 p->writeInt32(bitmap->rowBytes());
Dianne Hackbornde0dfb72009-09-23 14:09:34 -0700468 p->writeInt32(density);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469
470 if (bitmap->getConfig() == SkBitmap::kIndex8_Config) {
471 SkColorTable* ctable = bitmap->getColorTable();
472 if (ctable != NULL) {
473 int count = ctable->count();
474 p->writeInt32(count);
475 memcpy(p->writeInplace(count * sizeof(SkPMColor)),
476 ctable->lockColors(), count * sizeof(SkPMColor));
477 ctable->unlockColors(false);
478 } else {
479 p->writeInt32(0); // indicate no ctable
480 }
481 }
482
483 size_t size = bitmap->getSize();
Jeff Brown6579a9d2011-09-23 21:17:56 -0700484
485 android::Parcel::WritableBlob blob;
486 android::status_t status = p->writeBlob(size, &blob);
487 if (status) {
488 doThrowRE(env, "Could not write bitmap to parcel blob.");
489 return false;
490 }
491
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800492 bitmap->lockPixels();
Jack Palevichdee4cb02010-12-13 11:13:32 -0800493 const void* pSrc = bitmap->getPixels();
Jack Palevichdee4cb02010-12-13 11:13:32 -0800494 if (pSrc == NULL) {
Jeff Brown6579a9d2011-09-23 21:17:56 -0700495 memset(blob.data(), 0, size);
Jack Palevichdee4cb02010-12-13 11:13:32 -0800496 } else {
Jeff Brown6579a9d2011-09-23 21:17:56 -0700497 memcpy(blob.data(), pSrc, size);
Jack Palevichdee4cb02010-12-13 11:13:32 -0800498 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800499 bitmap->unlockPixels();
Jeff Brown6579a9d2011-09-23 21:17:56 -0700500
501 blob.release();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 return true;
503}
504
505static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
506 const SkBitmap* src, const SkPaint* paint,
507 jintArray offsetXY) {
508 SkIPoint offset;
509 SkBitmap* dst = new SkBitmap;
Patrick Dubroye4ac2d62010-12-01 11:23:13 -0800510 JavaPixelAllocator allocator(env);
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800511
Patrick Dubroye4ac2d62010-12-01 11:23:13 -0800512 src->extractAlpha(dst, paint, &allocator, &offset);
Eric Hassoldef7be262011-02-23 16:46:11 -0800513 // If Skia can't allocate pixels for destination bitmap, it resets
514 // it, that is set its pixels buffer to NULL, and zero width and height.
515 if (dst->getPixels() == NULL && src->getPixels() != NULL) {
516 delete dst;
517 doThrowOOME(env, "failed to allocate pixels for alpha");
518 return NULL;
519 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
521 int* array = env->GetIntArrayElements(offsetXY, NULL);
522 array[0] = offset.fX;
523 array[1] = offset.fY;
524 env->ReleaseIntArrayElements(offsetXY, array, 0);
525 }
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800526
Amith Yamasaniec4a5042012-04-04 10:27:15 -0700527 return GraphicsJNI::createBitmap(env, dst, allocator.getStorageObj(), true, NULL, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528}
529
530///////////////////////////////////////////////////////////////////////////////
531
532static int Bitmap_getPixel(JNIEnv* env, jobject, const SkBitmap* bitmap,
533 int x, int y) {
534 SkAutoLockPixels alp(*bitmap);
535
536 ToColorProc proc = ChooseToColorProc(*bitmap);
537 if (NULL == proc) {
538 return 0;
539 }
540 const void* src = bitmap->getAddr(x, y);
541 if (NULL == src) {
542 return 0;
543 }
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800544
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800545 SkColor dst[1];
546 proc(dst, src, 1, bitmap->getColorTable());
547 return dst[0];
548}
549
550static void Bitmap_getPixels(JNIEnv* env, jobject, const SkBitmap* bitmap,
551 jintArray pixelArray, int offset, int stride,
552 int x, int y, int width, int height) {
553 SkAutoLockPixels alp(*bitmap);
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800554
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555 ToColorProc proc = ChooseToColorProc(*bitmap);
556 if (NULL == proc) {
557 return;
558 }
559 const void* src = bitmap->getAddr(x, y);
560 if (NULL == src) {
561 return;
562 }
563
564 SkColorTable* ctable = bitmap->getColorTable();
565 jint* dst = env->GetIntArrayElements(pixelArray, NULL);
566 SkColor* d = (SkColor*)dst + offset;
567 while (--height >= 0) {
568 proc(d, src, width, ctable);
569 d += stride;
570 src = (void*)((const char*)src + bitmap->rowBytes());
571 }
572 env->ReleaseIntArrayElements(pixelArray, dst, 0);
573}
574
575///////////////////////////////////////////////////////////////////////////////
576
577static void Bitmap_setPixel(JNIEnv* env, jobject, const SkBitmap* bitmap,
578 int x, int y, SkColor color) {
579 SkAutoLockPixels alp(*bitmap);
580 if (NULL == bitmap->getPixels()) {
581 return;
582 }
583
584 FromColorProc proc = ChooseFromColorProc(bitmap->config());
585 if (NULL == proc) {
586 return;
587 }
588
589 proc(bitmap->getAddr(x, y), &color, 1, x, y);
Romain Guy1a81aea2011-03-21 15:24:51 -0700590 bitmap->notifyPixelsChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591}
592
593static void Bitmap_setPixels(JNIEnv* env, jobject, const SkBitmap* bitmap,
594 jintArray pixelArray, int offset, int stride,
595 int x, int y, int width, int height) {
596 GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
597 x, y, width, height, *bitmap);
598}
599
600static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
601 const SkBitmap* bitmap, jobject jbuffer) {
602 SkAutoLockPixels alp(*bitmap);
603 const void* src = bitmap->getPixels();
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800604
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800605 if (NULL != src) {
606 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
607
608 // the java side has already checked that buffer is large enough
609 memcpy(abp.pointer(), src, bitmap->getSize());
610 }
611}
612
613static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,
614 const SkBitmap* bitmap, jobject jbuffer) {
615 SkAutoLockPixels alp(*bitmap);
616 void* dst = bitmap->getPixels();
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800617
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800618 if (NULL != dst) {
619 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);
620 // the java side has already checked that buffer is large enough
621 memcpy(dst, abp.pointer(), bitmap->getSize());
Romain Guy2c183fa2011-10-18 17:56:06 -0700622 bitmap->notifyPixelsChanged();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800623 }
624}
625
Mike Reed76d1e012010-03-05 17:42:30 -0500626static bool Bitmap_sameAs(JNIEnv* env, jobject, const SkBitmap* bm0,
627 const SkBitmap* bm1) {
628 if (bm0->width() != bm1->width() ||
629 bm0->height() != bm1->height() ||
630 bm0->config() != bm1->config()) {
631 return false;
632 }
633
634 SkAutoLockPixels alp0(*bm0);
635 SkAutoLockPixels alp1(*bm1);
636
637 // if we can't load the pixels, return false
638 if (NULL == bm0->getPixels() || NULL == bm1->getPixels()) {
639 return false;
640 }
641
642 if (bm0->config() == SkBitmap::kIndex8_Config) {
643 SkColorTable* ct0 = bm0->getColorTable();
644 SkColorTable* ct1 = bm1->getColorTable();
645 if (NULL == ct0 || NULL == ct1) {
646 return false;
647 }
648 if (ct0->count() != ct1->count()) {
649 return false;
650 }
651
652 SkAutoLockColors alc0(ct0);
653 SkAutoLockColors alc1(ct1);
654 const size_t size = ct0->count() * sizeof(SkPMColor);
655 if (memcmp(alc0.colors(), alc1.colors(), size) != 0) {
656 return false;
657 }
658 }
659
660 // now compare each scanline. We can't do the entire buffer at once,
661 // since we don't care about the pixel values that might extend beyond
662 // the width (since the scanline might be larger than the logical width)
663 const int h = bm0->height();
664 const size_t size = bm0->width() * bm0->bytesPerPixel();
665 for (int y = 0; y < h; y++) {
666 if (memcmp(bm0->getAddr(0, y), bm1->getAddr(0, y), size) != 0) {
667 return false;
668 }
669 }
670 return true;
671}
672
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800673static void Bitmap_prepareToDraw(JNIEnv* env, jobject, SkBitmap* bitmap) {
674 bitmap->lockPixels();
675 bitmap->unlockPixels();
676}
677
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678///////////////////////////////////////////////////////////////////////////////
679
680#include <android_runtime/AndroidRuntime.h>
681
682static JNINativeMethod gBitmapMethods[] = {
683 { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;",
684 (void*)Bitmap_creator },
685 { "nativeCopy", "(IIZ)Landroid/graphics/Bitmap;",
686 (void*)Bitmap_copy },
687 { "nativeDestructor", "(I)V", (void*)Bitmap_destructor },
Chet Haase547e6652012-10-22 15:07:26 -0700688 { "nativeRecycle", "(I)Z", (void*)Bitmap_recycle },
Chris Craikc84d2032013-07-12 19:35:52 -0700689 { "nativeReconfigure", "(IIIII)V", (void*)Bitmap_reconfigure },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800690 { "nativeCompress", "(IIILjava/io/OutputStream;[B)Z",
691 (void*)Bitmap_compress },
692 { "nativeErase", "(II)V", (void*)Bitmap_erase },
693 { "nativeWidth", "(I)I", (void*)Bitmap_width },
694 { "nativeHeight", "(I)I", (void*)Bitmap_height },
695 { "nativeRowBytes", "(I)I", (void*)Bitmap_rowBytes },
696 { "nativeConfig", "(I)I", (void*)Bitmap_config },
697 { "nativeHasAlpha", "(I)Z", (void*)Bitmap_hasAlpha },
Mike Reeda78b0a22009-10-07 11:38:05 -0700698 { "nativeSetHasAlpha", "(IZ)V", (void*)Bitmap_setHasAlpha },
Romain Guy713e1bb2012-10-16 18:44:09 -0700699 { "nativeHasMipMap", "(I)Z", (void*)Bitmap_hasMipMap },
700 { "nativeSetHasMipMap", "(IZ)V", (void*)Bitmap_setHasMipMap },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 { "nativeCreateFromParcel",
702 "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
703 (void*)Bitmap_createFromParcel },
Dianne Hackbornde0dfb72009-09-23 14:09:34 -0700704 { "nativeWriteToParcel", "(IZILandroid/os/Parcel;)Z",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800705 (void*)Bitmap_writeToParcel },
706 { "nativeExtractAlpha", "(II[I)Landroid/graphics/Bitmap;",
707 (void*)Bitmap_extractAlpha },
Romain Guy0bbae082010-06-15 18:03:40 -0700708 { "nativeGenerationId", "(I)I", (void*)Bitmap_getGenerationId },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800709 { "nativeGetPixel", "(III)I", (void*)Bitmap_getPixel },
710 { "nativeGetPixels", "(I[IIIIIII)V", (void*)Bitmap_getPixels },
711 { "nativeSetPixel", "(IIII)V", (void*)Bitmap_setPixel },
712 { "nativeSetPixels", "(I[IIIIIII)V", (void*)Bitmap_setPixels },
713 { "nativeCopyPixelsToBuffer", "(ILjava/nio/Buffer;)V",
714 (void*)Bitmap_copyPixelsToBuffer },
715 { "nativeCopyPixelsFromBuffer", "(ILjava/nio/Buffer;)V",
Wei-Ta Chen8cdcb122009-06-18 19:14:38 +0800716 (void*)Bitmap_copyPixelsFromBuffer },
Mike Reed76d1e012010-03-05 17:42:30 -0500717 { "nativeSameAs", "(II)Z", (void*)Bitmap_sameAs },
718 { "nativePrepareToDraw", "(I)V", (void*)Bitmap_prepareToDraw },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800719};
720
721#define kClassPathName "android/graphics/Bitmap"
722
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723int register_android_graphics_Bitmap(JNIEnv* env)
724{
725 return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
726 gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods));
727}