OSDN Git Service

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