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