Bitmap.cpp revision 7d5219fb505ff1b178910cda25a40154e7d4d09a
1#define LOG_TAG "Bitmap"
2#include "Bitmap.h"
3
4#include "SkBitmap.h"
5#include "SkPixelRef.h"
6#include "SkImageEncoder.h"
7#include "SkImageInfo.h"
8#include "SkColorPriv.h"
9#include "GraphicsJNI.h"
10#include "SkDither.h"
11#include "SkUnPreMultiply.h"
12#include "SkStream.h"
13
14#include <binder/Parcel.h>
15#include "android_os_Parcel.h"
16#include "android_util_Binder.h"
17#include "android_nio_utils.h"
18#include "CreateJavaOutputStreamAdaptor.h"
19#include <hwui/Paint.h>
20#include <hwui/Bitmap.h>
21#include <renderthread/RenderProxy.h>
22
23#include "core_jni_helpers.h"
24
25#include <jni.h>
26#include <memory>
27#include <string>
28
29#define DEBUG_PARCEL 0
30#define ASHMEM_BITMAP_MIN_SIZE (128 * (1 << 10))
31
32static jclass   gBitmap_class;
33static jfieldID gBitmap_nativePtr;
34static jmethodID gBitmap_constructorMethodID;
35static jmethodID gBitmap_reinitMethodID;
36static jmethodID gBitmap_getAllocationByteCountMethodID;
37
38namespace android {
39
40class BitmapWrapper {
41public:
42    BitmapWrapper(Bitmap* bitmap)
43        : mBitmap(bitmap) { }
44
45    void freePixels() {
46        mInfo = mBitmap->info();
47        mHasHardwareMipMap = mBitmap->hasHardwareMipMap();
48        mAllocationSize = mBitmap->getAllocationByteCount();
49        mRowBytes = mBitmap->rowBytes();
50        mGenerationId = mBitmap->getGenerationID();
51        mBitmap.reset();
52    }
53
54    bool valid() {
55        return mBitmap;
56    }
57
58    Bitmap& bitmap() {
59        assertValid();
60        return *mBitmap;
61    }
62
63    void assertValid() {
64        LOG_ALWAYS_FATAL_IF(!valid(), "Error, cannot access an invalid/free'd bitmap here!");
65    }
66
67    void getSkBitmap(SkBitmap* outBitmap) {
68        assertValid();
69        mBitmap->getSkBitmap(outBitmap);
70    }
71
72    bool hasHardwareMipMap() {
73        if (mBitmap) {
74            return mBitmap->hasHardwareMipMap();
75        }
76        return mHasHardwareMipMap;
77    }
78
79    void setHasHardwareMipMap(bool hasMipMap) {
80        assertValid();
81        mBitmap->setHasHardwareMipMap(hasMipMap);
82    }
83
84    void setAlphaType(SkAlphaType alphaType) {
85        assertValid();
86        mBitmap->setAlphaType(alphaType);
87    }
88
89    const SkImageInfo& info() {
90        if (mBitmap) {
91            return mBitmap->info();
92        }
93        return mInfo;
94    }
95
96    size_t getAllocationByteCount() const {
97        if (mBitmap) {
98            return mBitmap->getAllocationByteCount();
99        }
100        return mAllocationSize;
101    }
102
103    size_t rowBytes() const {
104        if (mBitmap) {
105            return mBitmap->rowBytes();
106        }
107        return mRowBytes;
108    }
109
110    uint32_t getGenerationID() const {
111        if (mBitmap) {
112            return mBitmap->getGenerationID();
113        }
114        return mGenerationId;
115    }
116
117    ~BitmapWrapper() { }
118
119private:
120    sk_sp<Bitmap> mBitmap;
121    SkImageInfo mInfo;
122    bool mHasHardwareMipMap;
123    size_t mAllocationSize;
124    size_t mRowBytes;
125    uint32_t mGenerationId;
126};
127
128// Convenience class that does not take a global ref on the pixels, relying
129// on the caller already having a local JNI ref
130class LocalScopedBitmap {
131public:
132    explicit LocalScopedBitmap(jlong bitmapHandle)
133            : mBitmapWrapper(reinterpret_cast<BitmapWrapper*>(bitmapHandle)) {}
134
135    BitmapWrapper* operator->() {
136        return mBitmapWrapper;
137    }
138
139    void* pixels() {
140        return mBitmapWrapper->bitmap().pixels();
141    }
142
143    bool valid() {
144        return mBitmapWrapper && mBitmapWrapper->valid();
145    }
146
147private:
148    BitmapWrapper* mBitmapWrapper;
149};
150
151namespace bitmap {
152
153// Assert that bitmap's SkAlphaType is consistent with isPremultiplied.
154static void assert_premultiplied(const SkImageInfo& info, bool isPremultiplied) {
155    // kOpaque_SkAlphaType and kIgnore_SkAlphaType mean that isPremultiplied is
156    // irrelevant. This just tests to ensure that the SkAlphaType is not
157    // opposite of isPremultiplied.
158    if (isPremultiplied) {
159        SkASSERT(info.alphaType() != kUnpremul_SkAlphaType);
160    } else {
161        SkASSERT(info.alphaType() != kPremul_SkAlphaType);
162    }
163}
164
165void reinitBitmap(JNIEnv* env, jobject javaBitmap, const SkImageInfo& info,
166        bool isPremultiplied)
167{
168    // The caller needs to have already set the alpha type properly, so the
169    // native SkBitmap stays in sync with the Java Bitmap.
170    assert_premultiplied(info, isPremultiplied);
171
172    env->CallVoidMethod(javaBitmap, gBitmap_reinitMethodID,
173            info.width(), info.height(), isPremultiplied);
174}
175
176int getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap)
177{
178    return env->CallIntMethod(javaBitmap, gBitmap_getAllocationByteCountMethodID);
179}
180
181jobject createBitmap(JNIEnv* env, Bitmap* bitmap,
182        int bitmapCreateFlags, jbyteArray ninePatchChunk, jobject ninePatchInsets,
183        int density) {
184    bool isMutable = bitmapCreateFlags & kBitmapCreateFlag_Mutable;
185    bool isPremultiplied = bitmapCreateFlags & kBitmapCreateFlag_Premultiplied;
186    // The caller needs to have already set the alpha type properly, so the
187    // native SkBitmap stays in sync with the Java Bitmap.
188    assert_premultiplied(bitmap->info(), isPremultiplied);
189    BitmapWrapper* bitmapWrapper = new BitmapWrapper(bitmap);
190    jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
191            reinterpret_cast<jlong>(bitmapWrapper), bitmap->width(), bitmap->height(), density,
192            isMutable, isPremultiplied, ninePatchChunk, ninePatchInsets);
193
194    if (env->ExceptionCheck() != 0) {
195        ALOGE("*** Uncaught exception returned from Java call!\n");
196        env->ExceptionDescribe();
197    }
198    return obj;
199}
200
201void toSkBitmap(jlong bitmapHandle, SkBitmap* outBitmap) {
202    LocalScopedBitmap bitmap(bitmapHandle);
203    bitmap->getSkBitmap(outBitmap);
204}
205
206Bitmap& toBitmap(JNIEnv* env, jobject bitmap) {
207    SkASSERT(env);
208    SkASSERT(bitmap);
209    SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
210    jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
211    LocalScopedBitmap localBitmap(bitmapHandle);
212    return localBitmap->bitmap();
213}
214
215Bitmap& toBitmap(JNIEnv* env, jlong bitmapHandle) {
216    SkASSERT(env);
217    LocalScopedBitmap localBitmap(bitmapHandle);
218    return localBitmap->bitmap();
219}
220
221} // namespace bitmap
222
223} // namespace android
224
225using namespace android;
226using namespace android::bitmap;
227
228///////////////////////////////////////////////////////////////////////////////
229// Conversions to/from SkColor, for get/setPixels, and the create method, which
230// is basically like setPixels
231
232typedef void (*FromColorProc)(void* dst, const SkColor src[], int width,
233                              int x, int y);
234
235static void FromColor_D32(void* dst, const SkColor src[], int width,
236                          int, int) {
237    SkPMColor* d = (SkPMColor*)dst;
238
239    for (int i = 0; i < width; i++) {
240        *d++ = SkPreMultiplyColor(*src++);
241    }
242}
243
244static void FromColor_D32_Raw(void* dst, const SkColor src[], int width,
245                          int, int) {
246    // Needed to thwart the unreachable code detection from clang.
247    static const bool sk_color_ne_zero = SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER;
248
249    // SkColor's ordering may be different from SkPMColor
250    if (sk_color_ne_zero) {
251        memcpy(dst, src, width * sizeof(SkColor));
252        return;
253    }
254
255    // order isn't same, repack each pixel manually
256    SkPMColor* d = (SkPMColor*)dst;
257    for (int i = 0; i < width; i++) {
258        SkColor c = *src++;
259        *d++ = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
260                                   SkColorGetG(c), SkColorGetB(c));
261    }
262}
263
264static void FromColor_D565(void* dst, const SkColor src[], int width,
265                           int x, int y) {
266    uint16_t* d = (uint16_t*)dst;
267
268    DITHER_565_SCAN(y);
269    for (int stop = x + width; x < stop; x++) {
270        SkColor c = *src++;
271        *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c),
272                                DITHER_VALUE(x));
273    }
274}
275
276static void FromColor_D4444(void* dst, const SkColor src[], int width,
277                            int x, int y) {
278    SkPMColor16* d = (SkPMColor16*)dst;
279
280    DITHER_4444_SCAN(y);
281    for (int stop = x + width; x < stop; x++) {
282        SkPMColor pmc = SkPreMultiplyColor(*src++);
283        *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
284//        *d++ = SkPixel32ToPixel4444(pmc);
285    }
286}
287
288static void FromColor_D4444_Raw(void* dst, const SkColor src[], int width,
289                            int x, int y) {
290    SkPMColor16* d = (SkPMColor16*)dst;
291
292    DITHER_4444_SCAN(y);
293    for (int stop = x + width; x < stop; x++) {
294        SkColor c = *src++;
295
296        // SkPMColor is used because the ordering is ARGB32, even though the target actually premultiplied
297        SkPMColor pmc = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
298                                            SkColorGetG(c), SkColorGetB(c));
299        *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
300//        *d++ = SkPixel32ToPixel4444(pmc);
301    }
302}
303
304static void FromColor_DA8(void* dst, const SkColor src[], int width, int x, int y) {
305    uint8_t* d = (uint8_t*)dst;
306
307    for (int stop = x + width; x < stop; x++) {
308        *d++ = SkColorGetA(*src++);
309    }
310}
311
312// can return NULL
313static FromColorProc ChooseFromColorProc(const SkBitmap& bitmap) {
314    switch (bitmap.colorType()) {
315        case kN32_SkColorType:
316            return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D32 : FromColor_D32_Raw;
317        case kARGB_4444_SkColorType:
318            return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D4444 :
319                    FromColor_D4444_Raw;
320        case kRGB_565_SkColorType:
321            return FromColor_D565;
322        case kAlpha_8_SkColorType:
323            return FromColor_DA8;
324        default:
325            break;
326    }
327    return NULL;
328}
329
330bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride,
331        int x, int y, int width, int height, const SkBitmap& dstBitmap) {
332    SkAutoLockPixels alp(dstBitmap);
333    void* dst = dstBitmap.getPixels();
334    FromColorProc proc = ChooseFromColorProc(dstBitmap);
335
336    if (NULL == dst || NULL == proc) {
337        return false;
338    }
339
340    const jint* array = env->GetIntArrayElements(srcColors, NULL);
341    const SkColor* src = (const SkColor*)array + srcOffset;
342
343    // reset to to actual choice from caller
344    dst = dstBitmap.getAddr(x, y);
345    // now copy/convert each scanline
346    for (int y = 0; y < height; y++) {
347        proc(dst, src, width, x, y);
348        src += srcStride;
349        dst = (char*)dst + dstBitmap.rowBytes();
350    }
351
352    dstBitmap.notifyPixelsChanged();
353
354    env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array),
355                                 JNI_ABORT);
356    return true;
357}
358
359//////////////////// ToColor procs
360
361typedef void (*ToColorProc)(SkColor dst[], const void* src, int width,
362                            SkColorTable*);
363
364static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width,
365                              SkColorTable*) {
366    SkASSERT(width > 0);
367    const SkPMColor* s = (const SkPMColor*)src;
368    do {
369        *dst++ = SkUnPreMultiply::PMColorToColor(*s++);
370    } while (--width != 0);
371}
372
373static void ToColor_S32_Raw(SkColor dst[], const void* src, int width,
374                              SkColorTable*) {
375    SkASSERT(width > 0);
376    const SkPMColor* s = (const SkPMColor*)src;
377    do {
378        SkPMColor c = *s++;
379        *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
380                                SkGetPackedG32(c), SkGetPackedB32(c));
381    } while (--width != 0);
382}
383
384static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width,
385                               SkColorTable*) {
386    SkASSERT(width > 0);
387    const SkPMColor* s = (const SkPMColor*)src;
388    do {
389        SkPMColor c = *s++;
390        *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
391                               SkGetPackedB32(c));
392    } while (--width != 0);
393}
394
395static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width,
396                                SkColorTable*) {
397    SkASSERT(width > 0);
398    const SkPMColor16* s = (const SkPMColor16*)src;
399    do {
400        *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++));
401    } while (--width != 0);
402}
403
404static void ToColor_S4444_Raw(SkColor dst[], const void* src, int width,
405                                SkColorTable*) {
406    SkASSERT(width > 0);
407    const SkPMColor16* s = (const SkPMColor16*)src;
408    do {
409        SkPMColor c = SkPixel4444ToPixel32(*s++);
410        *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
411                                SkGetPackedG32(c), SkGetPackedB32(c));
412    } while (--width != 0);
413}
414
415static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width,
416                                 SkColorTable*) {
417    SkASSERT(width > 0);
418    const SkPMColor16* s = (const SkPMColor16*)src;
419    do {
420        SkPMColor c = SkPixel4444ToPixel32(*s++);
421        *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
422                               SkGetPackedB32(c));
423    } while (--width != 0);
424}
425
426static void ToColor_S565(SkColor dst[], const void* src, int width,
427                         SkColorTable*) {
428    SkASSERT(width > 0);
429    const uint16_t* s = (const uint16_t*)src;
430    do {
431        uint16_t c = *s++;
432        *dst++ =  SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c),
433                                SkPacked16ToB32(c));
434    } while (--width != 0);
435}
436
437static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width,
438                              SkColorTable* ctable) {
439    SkASSERT(width > 0);
440    const uint8_t* s = (const uint8_t*)src;
441    const SkPMColor* colors = ctable->readColors();
442    do {
443        *dst++ = SkUnPreMultiply::PMColorToColor(colors[*s++]);
444    } while (--width != 0);
445}
446
447static void ToColor_SI8_Raw(SkColor dst[], const void* src, int width,
448                              SkColorTable* ctable) {
449    SkASSERT(width > 0);
450    const uint8_t* s = (const uint8_t*)src;
451    const SkPMColor* colors = ctable->readColors();
452    do {
453        SkPMColor c = colors[*s++];
454        *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
455                                SkGetPackedG32(c), SkGetPackedB32(c));
456    } while (--width != 0);
457}
458
459static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width,
460                               SkColorTable* ctable) {
461    SkASSERT(width > 0);
462    const uint8_t* s = (const uint8_t*)src;
463    const SkPMColor* colors = ctable->readColors();
464    do {
465        SkPMColor c = colors[*s++];
466        *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
467                               SkGetPackedB32(c));
468    } while (--width != 0);
469}
470
471static void ToColor_SA8(SkColor dst[], const void* src, int width, SkColorTable*) {
472    SkASSERT(width > 0);
473    const uint8_t* s = (const uint8_t*)src;
474    do {
475        uint8_t c = *s++;
476        *dst++ = SkColorSetARGB(c, c, c, c);
477    } while (--width != 0);
478}
479
480// can return NULL
481static ToColorProc ChooseToColorProc(const SkBitmap& src) {
482    switch (src.colorType()) {
483        case kN32_SkColorType:
484            switch (src.alphaType()) {
485                case kOpaque_SkAlphaType:
486                    return ToColor_S32_Opaque;
487                case kPremul_SkAlphaType:
488                    return ToColor_S32_Alpha;
489                case kUnpremul_SkAlphaType:
490                    return ToColor_S32_Raw;
491                default:
492                    return NULL;
493            }
494        case kARGB_4444_SkColorType:
495            switch (src.alphaType()) {
496                case kOpaque_SkAlphaType:
497                    return ToColor_S4444_Opaque;
498                case kPremul_SkAlphaType:
499                    return ToColor_S4444_Alpha;
500                case kUnpremul_SkAlphaType:
501                    return ToColor_S4444_Raw;
502                default:
503                    return NULL;
504            }
505        case kRGB_565_SkColorType:
506            return ToColor_S565;
507        case kIndex_8_SkColorType:
508            if (src.getColorTable() == NULL) {
509                return NULL;
510            }
511            switch (src.alphaType()) {
512                case kOpaque_SkAlphaType:
513                    return ToColor_SI8_Opaque;
514                case kPremul_SkAlphaType:
515                    return ToColor_SI8_Alpha;
516                case kUnpremul_SkAlphaType:
517                    return ToColor_SI8_Raw;
518                default:
519                    return NULL;
520            }
521        case kAlpha_8_SkColorType:
522            return ToColor_SA8;
523        default:
524            break;
525    }
526    return NULL;
527}
528
529///////////////////////////////////////////////////////////////////////////////
530///////////////////////////////////////////////////////////////////////////////
531
532static int getPremulBitmapCreateFlags(bool isMutable) {
533    int flags = android::bitmap::kBitmapCreateFlag_Premultiplied;
534    if (isMutable) flags |= android::bitmap::kBitmapCreateFlag_Mutable;
535    return flags;
536}
537
538static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
539                              jint offset, jint stride, jint width, jint height,
540                              jint configHandle, jboolean isMutable) {
541    SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
542    if (NULL != jColors) {
543        size_t n = env->GetArrayLength(jColors);
544        if (n < SkAbs32(stride) * (size_t)height) {
545            doThrowAIOOBE(env);
546            return NULL;
547        }
548    }
549
550    // ARGB_4444 is a deprecated format, convert automatically to 8888
551    if (colorType == kARGB_4444_SkColorType) {
552        colorType = kN32_SkColorType;
553    }
554
555    SkBitmap bitmap;
556    bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType,
557            GraphicsJNI::defaultColorSpace()));
558
559    sk_sp<Bitmap> nativeBitmap = Bitmap::allocateHeapBitmap(&bitmap, NULL);
560    if (!nativeBitmap) {
561        return NULL;
562    }
563
564    if (jColors != NULL) {
565        GraphicsJNI::SetPixels(env, jColors, offset, stride,
566                0, 0, width, height, bitmap);
567    }
568
569    return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable));
570}
571
572static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle,
573                           jint dstConfigHandle, jboolean isMutable) {
574    SkBitmap src;
575    reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
576    SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
577    SkBitmap result;
578    HeapAllocator allocator;
579
580    if (!src.copyTo(&result, dstCT, &allocator)) {
581        return NULL;
582    }
583    auto bitmap = allocator.getStorageObjAndReset();
584    return createBitmap(env, bitmap, getPremulBitmapCreateFlags(isMutable));
585}
586
587static Bitmap* Bitmap_copyAshmemImpl(JNIEnv* env, SkBitmap& src, SkColorType& dstCT) {
588    SkBitmap result;
589
590    AshmemPixelAllocator allocator(env);
591    if (!src.copyTo(&result, dstCT, &allocator)) {
592        return NULL;
593    }
594    auto bitmap = allocator.getStorageObjAndReset();
595    bitmap->setImmutable();
596    return bitmap;
597}
598
599static jobject Bitmap_copyAshmem(JNIEnv* env, jobject, jlong srcHandle) {
600    SkBitmap src;
601    reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
602    SkColorType dstCT = src.colorType();
603    auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
604    jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
605    return ret;
606}
607
608static jobject Bitmap_copyAshmemConfig(JNIEnv* env, jobject, jlong srcHandle, jint dstConfigHandle) {
609    SkBitmap src;
610    reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
611    SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
612    auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
613    jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
614    return ret;
615}
616
617static void Bitmap_destruct(BitmapWrapper* bitmap) {
618    delete bitmap;
619}
620
621static jlong Bitmap_getNativeFinalizer(JNIEnv*, jobject) {
622    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Bitmap_destruct));
623}
624
625static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {
626    LocalScopedBitmap bitmap(bitmapHandle);
627    bitmap->freePixels();
628    return JNI_TRUE;
629}
630
631static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
632        jint width, jint height, jint configHandle, jboolean requestPremul) {
633    LocalScopedBitmap bitmap(bitmapHandle);
634    bitmap->assertValid();
635    SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
636
637    // ARGB_4444 is a deprecated format, convert automatically to 8888
638    if (colorType == kARGB_4444_SkColorType) {
639        colorType = kN32_SkColorType;
640    }
641    size_t requestedSize = width * height * SkColorTypeBytesPerPixel(colorType);
642    if (requestedSize > bitmap->getAllocationByteCount()) {
643        // done in native as there's no way to get BytesPerPixel in Java
644        doThrowIAE(env, "Bitmap not large enough to support new configuration");
645        return;
646    }
647    SkAlphaType alphaType;
648    if (bitmap->info().colorType() != kRGB_565_SkColorType
649            && bitmap->info().alphaType() == kOpaque_SkAlphaType) {
650        // If the original bitmap was set to opaque, keep that setting, unless it
651        // was 565, which is required to be opaque.
652        alphaType = kOpaque_SkAlphaType;
653    } else {
654        // Otherwise respect the premultiplied request.
655        alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
656    }
657    bitmap->bitmap().reconfigure(SkImageInfo::Make(width, height, colorType, alphaType,
658            sk_ref_sp(bitmap->info().colorSpace())));
659}
660
661// These must match the int values in Bitmap.java
662enum JavaEncodeFormat {
663    kJPEG_JavaEncodeFormat = 0,
664    kPNG_JavaEncodeFormat = 1,
665    kWEBP_JavaEncodeFormat = 2
666};
667
668static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle,
669                                jint format, jint quality,
670                                jobject jstream, jbyteArray jstorage) {
671
672    LocalScopedBitmap bitmap(bitmapHandle);
673    SkImageEncoder::Type fm;
674
675    switch (format) {
676    case kJPEG_JavaEncodeFormat:
677        fm = SkImageEncoder::kJPEG_Type;
678        break;
679    case kPNG_JavaEncodeFormat:
680        fm = SkImageEncoder::kPNG_Type;
681        break;
682    case kWEBP_JavaEncodeFormat:
683        fm = SkImageEncoder::kWEBP_Type;
684        break;
685    default:
686        return JNI_FALSE;
687    }
688
689    if (!bitmap.valid()) {
690        return JNI_FALSE;
691    }
692
693    bool success = false;
694
695    std::unique_ptr<SkWStream> strm(CreateJavaOutputStreamAdaptor(env, jstream, jstorage));
696    if (!strm.get()) {
697        return JNI_FALSE;
698    }
699
700    std::unique_ptr<SkImageEncoder> encoder(SkImageEncoder::Create(fm));
701    if (encoder.get()) {
702        SkBitmap skbitmap;
703        bitmap->getSkBitmap(&skbitmap);
704        success = encoder->encodeStream(strm.get(), skbitmap, quality);
705    }
706    return success ? JNI_TRUE : JNI_FALSE;
707}
708
709static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) {
710    LocalScopedBitmap bitmap(bitmapHandle);
711    SkBitmap skBitmap;
712    bitmap->getSkBitmap(&skBitmap);
713    skBitmap.eraseColor(color);
714}
715
716static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {
717    LocalScopedBitmap bitmap(bitmapHandle);
718    return static_cast<jint>(bitmap->rowBytes());
719}
720
721static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) {
722    LocalScopedBitmap bitmap(bitmapHandle);
723    return GraphicsJNI::colorTypeToLegacyBitmapConfig(bitmap->info().colorType());
724}
725
726static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {
727    LocalScopedBitmap bitmap(bitmapHandle);
728    return static_cast<jint>(bitmap->getGenerationID());
729}
730
731static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) {
732    LocalScopedBitmap bitmap(bitmapHandle);
733    if (bitmap->info().alphaType() == kPremul_SkAlphaType) {
734        return JNI_TRUE;
735    }
736    return JNI_FALSE;
737}
738
739static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) {
740    LocalScopedBitmap bitmap(bitmapHandle);
741    return !bitmap->info().isOpaque() ? JNI_TRUE : JNI_FALSE;
742}
743
744static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle,
745        jboolean hasAlpha, jboolean requestPremul) {
746    LocalScopedBitmap bitmap(bitmapHandle);
747    if (hasAlpha) {
748        bitmap->setAlphaType(
749                requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
750    } else {
751        bitmap->setAlphaType(kOpaque_SkAlphaType);
752    }
753}
754
755static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
756        jboolean isPremul) {
757    LocalScopedBitmap bitmap(bitmapHandle);
758    if (!bitmap->info().isOpaque()) {
759        if (isPremul) {
760            bitmap->setAlphaType(kPremul_SkAlphaType);
761        } else {
762            bitmap->setAlphaType(kUnpremul_SkAlphaType);
763        }
764    }
765}
766
767static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) {
768    LocalScopedBitmap bitmap(bitmapHandle);
769    return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE;
770}
771
772static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle,
773                                jboolean hasMipMap) {
774    LocalScopedBitmap bitmap(bitmapHandle);
775    bitmap->setHasHardwareMipMap(hasMipMap);
776}
777
778///////////////////////////////////////////////////////////////////////////////
779
780static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
781    if (parcel == NULL) {
782        SkDebugf("-------- unparcel parcel is NULL\n");
783        return NULL;
784    }
785
786    android::Parcel* p = android::parcelForJavaObject(env, parcel);
787
788    const bool        isMutable = p->readInt32() != 0;
789    const SkColorType colorType = (SkColorType)p->readInt32();
790    const SkAlphaType alphaType = (SkAlphaType)p->readInt32();
791    const bool        isSRGB = p->readInt32() != 0;
792    const int         width = p->readInt32();
793    const int         height = p->readInt32();
794    const int         rowBytes = p->readInt32();
795    const int         density = p->readInt32();
796
797    if (kN32_SkColorType != colorType &&
798            kRGB_565_SkColorType != colorType &&
799            kARGB_4444_SkColorType != colorType &&
800            kIndex_8_SkColorType != colorType &&
801            kAlpha_8_SkColorType != colorType) {
802        SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType);
803        return NULL;
804    }
805
806    std::unique_ptr<SkBitmap> bitmap(new SkBitmap);
807
808    if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType,
809            isSRGB ? SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named) : nullptr), rowBytes)) {
810        return NULL;
811    }
812
813    SkColorTable* ctable = NULL;
814    if (colorType == kIndex_8_SkColorType) {
815        int count = p->readInt32();
816        if (count < 0 || count > 256) {
817            // The data is corrupt, since SkColorTable enforces a value between 0 and 256,
818            // inclusive.
819            return NULL;
820        }
821        if (count > 0) {
822            size_t size = count * sizeof(SkPMColor);
823            const SkPMColor* src = (const SkPMColor*)p->readInplace(size);
824            if (src == NULL) {
825                return NULL;
826            }
827            ctable = new SkColorTable(src, count);
828        }
829    }
830
831    // Read the bitmap blob.
832    size_t size = bitmap->getSize();
833    android::Parcel::ReadableBlob blob;
834    android::status_t status = p->readBlob(size, &blob);
835    if (status) {
836        SkSafeUnref(ctable);
837        doThrowRE(env, "Could not read bitmap blob.");
838        return NULL;
839    }
840
841    // Map the bitmap in place from the ashmem region if possible otherwise copy.
842    sk_sp<Bitmap> nativeBitmap;
843    if (blob.fd() >= 0 && (blob.isMutable() || !isMutable) && (size >= ASHMEM_BITMAP_MIN_SIZE)) {
844#if DEBUG_PARCEL
845        ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob "
846                "(fds %s)",
847                isMutable ? "mutable" : "immutable",
848                blob.isMutable() ? "mutable" : "immutable",
849                p->allowFds() ? "allowed" : "forbidden");
850#endif
851        // Dup the file descriptor so we can keep a reference to it after the Parcel
852        // is disposed.
853        int dupFd = dup(blob.fd());
854        if (dupFd < 0) {
855            ALOGE("Error allocating dup fd. Error:%d", errno);
856            blob.release();
857            SkSafeUnref(ctable);
858            doThrowRE(env, "Could not allocate dup blob fd.");
859            return NULL;
860        }
861
862        // Map the pixels in place and take ownership of the ashmem region.
863        nativeBitmap = sk_sp<Bitmap>(GraphicsJNI::mapAshmemBitmap(env, bitmap.get(),
864                ctable, dupFd, const_cast<void*>(blob.data()), size, !isMutable));
865        SkSafeUnref(ctable);
866        if (!nativeBitmap) {
867            close(dupFd);
868            blob.release();
869            doThrowRE(env, "Could not allocate ashmem pixel ref.");
870            return NULL;
871        }
872
873        // Clear the blob handle, don't release it.
874        blob.clear();
875    } else {
876#if DEBUG_PARCEL
877        if (blob.fd() >= 0) {
878            ALOGD("Bitmap.createFromParcel: copied contents of mutable bitmap "
879                    "from immutable blob (fds %s)",
880                    p->allowFds() ? "allowed" : "forbidden");
881        } else {
882            ALOGD("Bitmap.createFromParcel: copied contents from %s blob "
883                    "(fds %s)",
884                    blob.isMutable() ? "mutable" : "immutable",
885                    p->allowFds() ? "allowed" : "forbidden");
886        }
887#endif
888
889        // Copy the pixels into a new buffer.
890        nativeBitmap = Bitmap::allocateHeapBitmap(bitmap.get(), ctable);
891        SkSafeUnref(ctable);
892        if (!nativeBitmap) {
893            blob.release();
894            doThrowRE(env, "Could not allocate java pixel ref.");
895            return NULL;
896        }
897        bitmap->lockPixels();
898        memcpy(bitmap->getPixels(), blob.data(), size);
899        bitmap->unlockPixels();
900
901        // Release the blob handle.
902        blob.release();
903    }
904
905    return createBitmap(env, nativeBitmap.release(),
906            getPremulBitmapCreateFlags(isMutable), NULL, NULL, density);
907}
908
909static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
910                                     jlong bitmapHandle,
911                                     jboolean isMutable, jint density,
912                                     jobject parcel) {
913    if (parcel == NULL) {
914        SkDebugf("------- writeToParcel null parcel\n");
915        return JNI_FALSE;
916    }
917
918    android::Parcel* p = android::parcelForJavaObject(env, parcel);
919    SkBitmap bitmap;
920
921    auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle);
922    bitmapWrapper->getSkBitmap(&bitmap);
923
924    sk_sp<SkColorSpace> sRGB = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
925    bool isSRGB = bitmap.colorSpace() == sRGB.get();
926
927    p->writeInt32(isMutable);
928    p->writeInt32(bitmap.colorType());
929    p->writeInt32(bitmap.alphaType());
930    p->writeInt32(isSRGB); // TODO: We should write the color space (b/32072280)
931    p->writeInt32(bitmap.width());
932    p->writeInt32(bitmap.height());
933    p->writeInt32(bitmap.rowBytes());
934    p->writeInt32(density);
935
936    if (bitmap.colorType() == kIndex_8_SkColorType) {
937        // The bitmap needs to be locked to access its color table.
938        SkAutoLockPixels alp(bitmap);
939        SkColorTable* ctable = bitmap.getColorTable();
940        if (ctable != NULL) {
941            int count = ctable->count();
942            p->writeInt32(count);
943            memcpy(p->writeInplace(count * sizeof(SkPMColor)),
944                   ctable->readColors(), count * sizeof(SkPMColor));
945        } else {
946            p->writeInt32(0);   // indicate no ctable
947        }
948    }
949
950    // Transfer the underlying ashmem region if we have one and it's immutable.
951    android::status_t status;
952    int fd = bitmapWrapper->bitmap().getAshmemFd();
953    if (fd >= 0 && !isMutable && p->allowFds()) {
954#if DEBUG_PARCEL
955        ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as "
956                "immutable blob (fds %s)",
957                p->allowFds() ? "allowed" : "forbidden");
958#endif
959
960        status = p->writeDupImmutableBlobFileDescriptor(fd);
961        if (status) {
962            doThrowRE(env, "Could not write bitmap blob file descriptor.");
963            return JNI_FALSE;
964        }
965        return JNI_TRUE;
966    }
967
968    // Copy the bitmap to a new blob.
969    bool mutableCopy = isMutable;
970#if DEBUG_PARCEL
971    ALOGD("Bitmap.writeToParcel: copying %s bitmap into new %s blob (fds %s)",
972            isMutable ? "mutable" : "immutable",
973            mutableCopy ? "mutable" : "immutable",
974            p->allowFds() ? "allowed" : "forbidden");
975#endif
976
977    size_t size = bitmap.getSize();
978    android::Parcel::WritableBlob blob;
979    status = p->writeBlob(size, mutableCopy, &blob);
980    if (status) {
981        doThrowRE(env, "Could not copy bitmap to parcel blob.");
982        return JNI_FALSE;
983    }
984
985    bitmap.lockPixels();
986    const void* pSrc =  bitmap.getPixels();
987    if (pSrc == NULL) {
988        memset(blob.data(), 0, size);
989    } else {
990        memcpy(blob.data(), pSrc, size);
991    }
992    bitmap.unlockPixels();
993
994    blob.release();
995    return JNI_TRUE;
996}
997
998static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
999                                   jlong srcHandle, jlong paintHandle,
1000                                   jintArray offsetXY) {
1001    SkBitmap src;
1002    reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
1003    const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle);
1004    SkIPoint  offset;
1005    SkBitmap dst;
1006    HeapAllocator allocator;
1007
1008    src.extractAlpha(&dst, paint, &allocator, &offset);
1009    // If Skia can't allocate pixels for destination bitmap, it resets
1010    // it, that is set its pixels buffer to NULL, and zero width and height.
1011    if (dst.getPixels() == NULL && src.getPixels() != NULL) {
1012        doThrowOOME(env, "failed to allocate pixels for alpha");
1013        return NULL;
1014    }
1015    if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
1016        int* array = env->GetIntArrayElements(offsetXY, NULL);
1017        array[0] = offset.fX;
1018        array[1] = offset.fY;
1019        env->ReleaseIntArrayElements(offsetXY, array, 0);
1020    }
1021
1022    return createBitmap(env, allocator.getStorageObjAndReset(),
1023            getPremulBitmapCreateFlags(true));
1024}
1025
1026///////////////////////////////////////////////////////////////////////////////
1027
1028static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
1029        jint x, jint y) {
1030    SkBitmap bitmap;
1031    reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1032    SkAutoLockPixels alp(bitmap);
1033
1034    ToColorProc proc = ChooseToColorProc(bitmap);
1035    if (NULL == proc) {
1036        return 0;
1037    }
1038    const void* src = bitmap.getAddr(x, y);
1039    if (NULL == src) {
1040        return 0;
1041    }
1042
1043    SkColor dst[1];
1044    proc(dst, src, 1, bitmap.getColorTable());
1045    return static_cast<jint>(dst[0]);
1046}
1047
1048static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,
1049        jintArray pixelArray, jint offset, jint stride,
1050        jint x, jint y, jint width, jint height) {
1051    SkBitmap bitmap;
1052    reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1053    SkAutoLockPixels alp(bitmap);
1054
1055    ToColorProc proc = ChooseToColorProc(bitmap);
1056    if (NULL == proc) {
1057        return;
1058    }
1059    const void* src = bitmap.getAddr(x, y);
1060    if (NULL == src) {
1061        return;
1062    }
1063
1064    SkColorTable* ctable = bitmap.getColorTable();
1065    jint* dst = env->GetIntArrayElements(pixelArray, NULL);
1066    SkColor* d = (SkColor*)dst + offset;
1067    while (--height >= 0) {
1068        proc(d, src, width, ctable);
1069        d += stride;
1070        src = (void*)((const char*)src + bitmap.rowBytes());
1071    }
1072    env->ReleaseIntArrayElements(pixelArray, dst, 0);
1073}
1074
1075///////////////////////////////////////////////////////////////////////////////
1076
1077static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle,
1078        jint x, jint y, jint colorHandle) {
1079    SkBitmap bitmap;
1080    reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1081    SkColor color = static_cast<SkColor>(colorHandle);
1082    SkAutoLockPixels alp(bitmap);
1083    if (NULL == bitmap.getPixels()) {
1084        return;
1085    }
1086
1087    FromColorProc proc = ChooseFromColorProc(bitmap);
1088    if (NULL == proc) {
1089        return;
1090    }
1091
1092    proc(bitmap.getAddr(x, y), &color, 1, x, y);
1093    bitmap.notifyPixelsChanged();
1094}
1095
1096static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,
1097        jintArray pixelArray, jint offset, jint stride,
1098        jint x, jint y, jint width, jint height) {
1099    SkBitmap bitmap;
1100    reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1101    GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
1102            x, y, width, height, bitmap);
1103}
1104
1105static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
1106                                      jlong bitmapHandle, jobject jbuffer) {
1107    SkBitmap bitmap;
1108    reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1109    SkAutoLockPixels alp(bitmap);
1110    const void* src = bitmap.getPixels();
1111
1112    if (NULL != src) {
1113        android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
1114
1115        // the java side has already checked that buffer is large enough
1116        memcpy(abp.pointer(), src, bitmap.getSize());
1117    }
1118}
1119
1120static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,
1121                                        jlong bitmapHandle, jobject jbuffer) {
1122    SkBitmap bitmap;
1123    reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1124    SkAutoLockPixels alp(bitmap);
1125    void* dst = bitmap.getPixels();
1126
1127    if (NULL != dst) {
1128        android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);
1129        // the java side has already checked that buffer is large enough
1130        memcpy(dst, abp.pointer(), bitmap.getSize());
1131        bitmap.notifyPixelsChanged();
1132    }
1133}
1134
1135static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle,
1136                              jlong bm1Handle) {
1137    SkBitmap bm0;
1138    SkBitmap bm1;
1139    reinterpret_cast<BitmapWrapper*>(bm0Handle)->getSkBitmap(&bm0);
1140    reinterpret_cast<BitmapWrapper*>(bm1Handle)->getSkBitmap(&bm1);
1141    if (bm0.width() != bm1.width() ||
1142        bm0.height() != bm1.height() ||
1143        bm0.colorType() != bm1.colorType() ||
1144        bm0.alphaType() != bm1.alphaType() ||
1145        bm0.colorSpace() != bm1.colorSpace()) {
1146        return JNI_FALSE;
1147    }
1148
1149    SkAutoLockPixels alp0(bm0);
1150    SkAutoLockPixels alp1(bm1);
1151
1152    // if we can't load the pixels, return false
1153    if (NULL == bm0.getPixels() || NULL == bm1.getPixels()) {
1154        return JNI_FALSE;
1155    }
1156
1157    if (bm0.colorType() == kIndex_8_SkColorType) {
1158        SkColorTable* ct0 = bm0.getColorTable();
1159        SkColorTable* ct1 = bm1.getColorTable();
1160        if (NULL == ct0 || NULL == ct1) {
1161            return JNI_FALSE;
1162        }
1163        if (ct0->count() != ct1->count()) {
1164            return JNI_FALSE;
1165        }
1166
1167        const size_t size = ct0->count() * sizeof(SkPMColor);
1168        if (memcmp(ct0->readColors(), ct1->readColors(), size) != 0) {
1169            return JNI_FALSE;
1170        }
1171    }
1172
1173    // now compare each scanline. We can't do the entire buffer at once,
1174    // since we don't care about the pixel values that might extend beyond
1175    // the width (since the scanline might be larger than the logical width)
1176    const int h = bm0.height();
1177    const size_t size = bm0.width() * bm0.bytesPerPixel();
1178    for (int y = 0; y < h; y++) {
1179        // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config
1180        // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0
1181        // and bm1 both have pixel data() (have passed NULL == getPixels() check),
1182        // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE
1183        // to warn user those 2 unrecognized config bitmaps may be different.
1184        void *bm0Addr = bm0.getAddr(0, y);
1185        void *bm1Addr = bm1.getAddr(0, y);
1186
1187        if(bm0Addr == NULL || bm1Addr == NULL) {
1188            return JNI_FALSE;
1189        }
1190
1191        if (memcmp(bm0Addr, bm1Addr, size) != 0) {
1192            return JNI_FALSE;
1193        }
1194    }
1195    return JNI_TRUE;
1196}
1197
1198static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapPtr) {
1199    LocalScopedBitmap bitmapHandle(bitmapPtr);
1200    if (!bitmapHandle.valid()) return;
1201    android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmapHandle->bitmap());
1202}
1203
1204static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr) {
1205    LocalScopedBitmap bitmapHandle(bitmapPtr);
1206    return static_cast<jint>(bitmapHandle->getAllocationByteCount());
1207}
1208
1209///////////////////////////////////////////////////////////////////////////////
1210static jclass make_globalref(JNIEnv* env, const char classname[])
1211{
1212    jclass c = env->FindClass(classname);
1213    SkASSERT(c);
1214    return (jclass) env->NewGlobalRef(c);
1215}
1216
1217static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
1218                                const char fieldname[], const char type[])
1219{
1220    jfieldID id = env->GetFieldID(clazz, fieldname, type);
1221    SkASSERT(id);
1222    return id;
1223}
1224
1225static const JNINativeMethod gBitmapMethods[] = {
1226    {   "nativeCreate",             "([IIIIIIZ)Landroid/graphics/Bitmap;",
1227        (void*)Bitmap_creator },
1228    {   "nativeCopy",               "(JIZ)Landroid/graphics/Bitmap;",
1229        (void*)Bitmap_copy },
1230    {   "nativeCopyAshmem",         "(J)Landroid/graphics/Bitmap;",
1231        (void*)Bitmap_copyAshmem },
1232    {   "nativeCopyAshmemConfig",   "(JI)Landroid/graphics/Bitmap;",
1233        (void*)Bitmap_copyAshmemConfig },
1234    {   "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer },
1235    {   "nativeRecycle",            "(J)Z", (void*)Bitmap_recycle },
1236    {   "nativeReconfigure",        "(JIIIZ)V", (void*)Bitmap_reconfigure },
1237    {   "nativeCompress",           "(JIILjava/io/OutputStream;[B)Z",
1238        (void*)Bitmap_compress },
1239    {   "nativeErase",              "(JI)V", (void*)Bitmap_erase },
1240    {   "nativeRowBytes",           "(J)I", (void*)Bitmap_rowBytes },
1241    {   "nativeConfig",             "(J)I", (void*)Bitmap_config },
1242    {   "nativeHasAlpha",           "(J)Z", (void*)Bitmap_hasAlpha },
1243    {   "nativeIsPremultiplied",    "(J)Z", (void*)Bitmap_isPremultiplied},
1244    {   "nativeSetHasAlpha",        "(JZZ)V", (void*)Bitmap_setHasAlpha},
1245    {   "nativeSetPremultiplied",   "(JZ)V", (void*)Bitmap_setPremultiplied},
1246    {   "nativeHasMipMap",          "(J)Z", (void*)Bitmap_hasMipMap },
1247    {   "nativeSetHasMipMap",       "(JZ)V", (void*)Bitmap_setHasMipMap },
1248    {   "nativeCreateFromParcel",
1249        "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
1250        (void*)Bitmap_createFromParcel },
1251    {   "nativeWriteToParcel",      "(JZILandroid/os/Parcel;)Z",
1252        (void*)Bitmap_writeToParcel },
1253    {   "nativeExtractAlpha",       "(JJ[I)Landroid/graphics/Bitmap;",
1254        (void*)Bitmap_extractAlpha },
1255    {   "nativeGenerationId",       "(J)I", (void*)Bitmap_getGenerationId },
1256    {   "nativeGetPixel",           "(JII)I", (void*)Bitmap_getPixel },
1257    {   "nativeGetPixels",          "(J[IIIIIII)V", (void*)Bitmap_getPixels },
1258    {   "nativeSetPixel",           "(JIII)V", (void*)Bitmap_setPixel },
1259    {   "nativeSetPixels",          "(J[IIIIIII)V", (void*)Bitmap_setPixels },
1260    {   "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V",
1261                                            (void*)Bitmap_copyPixelsToBuffer },
1262    {   "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V",
1263                                            (void*)Bitmap_copyPixelsFromBuffer },
1264    {   "nativeSameAs",             "(JJ)Z", (void*)Bitmap_sameAs },
1265    {   "nativePrepareToDraw",      "(J)V", (void*)Bitmap_prepareToDraw },
1266    {   "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount },
1267};
1268
1269int register_android_graphics_Bitmap(JNIEnv* env)
1270{
1271    gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
1272    gBitmap_nativePtr = getFieldIDCheck(env, gBitmap_class, "mNativePtr", "J");
1273    gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
1274    gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "(IIZ)V");
1275    gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I");
1276    return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods,
1277                                         NELEM(gBitmapMethods));
1278}
1279