Bitmap.cpp revision 1eabed3d14fdc47ac6939cfa98521adcb45bc224
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    SkEncodedImageFormat fm;
672    switch (format) {
673    case kJPEG_JavaEncodeFormat:
674        fm = SkEncodedImageFormat::kJPEG;
675        break;
676    case kPNG_JavaEncodeFormat:
677        fm = SkEncodedImageFormat::kPNG;
678        break;
679    case kWEBP_JavaEncodeFormat:
680        fm = SkEncodedImageFormat::kWEBP;
681        break;
682    default:
683        return JNI_FALSE;
684    }
685
686    LocalScopedBitmap bitmap(bitmapHandle);
687    if (!bitmap.valid()) {
688        return JNI_FALSE;
689    }
690
691    std::unique_ptr<SkWStream> strm(CreateJavaOutputStreamAdaptor(env, jstream, jstorage));
692    if (!strm.get()) {
693        return JNI_FALSE;
694    }
695
696    SkBitmap skbitmap;
697    bitmap->getSkBitmap(&skbitmap);
698    return SkEncodeImage(strm.get(), skbitmap, fm, quality) ? JNI_TRUE : JNI_FALSE;
699}
700
701static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) {
702    LocalScopedBitmap bitmap(bitmapHandle);
703    SkBitmap skBitmap;
704    bitmap->getSkBitmap(&skBitmap);
705    skBitmap.eraseColor(color);
706}
707
708static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {
709    LocalScopedBitmap bitmap(bitmapHandle);
710    return static_cast<jint>(bitmap->rowBytes());
711}
712
713static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) {
714    LocalScopedBitmap bitmap(bitmapHandle);
715    if (bitmap->bitmap().isHardware()) {
716        return GraphicsJNI::hardwareLegacyBitmapConfig();
717    }
718    return GraphicsJNI::colorTypeToLegacyBitmapConfig(bitmap->info().colorType());
719}
720
721static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {
722    LocalScopedBitmap bitmap(bitmapHandle);
723    return static_cast<jint>(bitmap->getGenerationID());
724}
725
726static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) {
727    LocalScopedBitmap bitmap(bitmapHandle);
728    if (bitmap->info().alphaType() == kPremul_SkAlphaType) {
729        return JNI_TRUE;
730    }
731    return JNI_FALSE;
732}
733
734static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) {
735    LocalScopedBitmap bitmap(bitmapHandle);
736    return !bitmap->info().isOpaque() ? JNI_TRUE : JNI_FALSE;
737}
738
739static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle,
740        jboolean hasAlpha, jboolean requestPremul) {
741    LocalScopedBitmap bitmap(bitmapHandle);
742    if (hasAlpha) {
743        bitmap->setAlphaType(
744                requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
745    } else {
746        bitmap->setAlphaType(kOpaque_SkAlphaType);
747    }
748}
749
750static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
751        jboolean isPremul) {
752    LocalScopedBitmap bitmap(bitmapHandle);
753    if (!bitmap->info().isOpaque()) {
754        if (isPremul) {
755            bitmap->setAlphaType(kPremul_SkAlphaType);
756        } else {
757            bitmap->setAlphaType(kUnpremul_SkAlphaType);
758        }
759    }
760}
761
762static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) {
763    LocalScopedBitmap bitmap(bitmapHandle);
764    return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE;
765}
766
767static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle,
768                                jboolean hasMipMap) {
769    LocalScopedBitmap bitmap(bitmapHandle);
770    bitmap->setHasHardwareMipMap(hasMipMap);
771}
772
773///////////////////////////////////////////////////////////////////////////////
774
775static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
776    if (parcel == NULL) {
777        SkDebugf("-------- unparcel parcel is NULL\n");
778        return NULL;
779    }
780
781    android::Parcel* p = android::parcelForJavaObject(env, parcel);
782
783    const bool        isMutable = p->readInt32() != 0;
784    const SkColorType colorType = (SkColorType)p->readInt32();
785    const SkAlphaType alphaType = (SkAlphaType)p->readInt32();
786    const bool        isSRGB = p->readInt32() != 0;
787    const int         width = p->readInt32();
788    const int         height = p->readInt32();
789    const int         rowBytes = p->readInt32();
790    const int         density = p->readInt32();
791
792    if (kN32_SkColorType != colorType &&
793            kRGB_565_SkColorType != colorType &&
794            kARGB_4444_SkColorType != colorType &&
795            kIndex_8_SkColorType != colorType &&
796            kAlpha_8_SkColorType != colorType) {
797        SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType);
798        return NULL;
799    }
800
801    std::unique_ptr<SkBitmap> bitmap(new SkBitmap);
802
803    if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType,
804            isSRGB ? SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named) : nullptr), rowBytes)) {
805        return NULL;
806    }
807
808    SkColorTable* ctable = NULL;
809    if (colorType == kIndex_8_SkColorType) {
810        int count = p->readInt32();
811        if (count < 0 || count > 256) {
812            // The data is corrupt, since SkColorTable enforces a value between 0 and 256,
813            // inclusive.
814            return NULL;
815        }
816        if (count > 0) {
817            size_t size = count * sizeof(SkPMColor);
818            const SkPMColor* src = (const SkPMColor*)p->readInplace(size);
819            if (src == NULL) {
820                return NULL;
821            }
822            ctable = new SkColorTable(src, count);
823        }
824    }
825
826    // Read the bitmap blob.
827    size_t size = bitmap->getSize();
828    android::Parcel::ReadableBlob blob;
829    android::status_t status = p->readBlob(size, &blob);
830    if (status) {
831        SkSafeUnref(ctable);
832        doThrowRE(env, "Could not read bitmap blob.");
833        return NULL;
834    }
835
836    // Map the bitmap in place from the ashmem region if possible otherwise copy.
837    sk_sp<Bitmap> nativeBitmap;
838    if (blob.fd() >= 0 && (blob.isMutable() || !isMutable) && (size >= ASHMEM_BITMAP_MIN_SIZE)) {
839#if DEBUG_PARCEL
840        ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob "
841                "(fds %s)",
842                isMutable ? "mutable" : "immutable",
843                blob.isMutable() ? "mutable" : "immutable",
844                p->allowFds() ? "allowed" : "forbidden");
845#endif
846        // Dup the file descriptor so we can keep a reference to it after the Parcel
847        // is disposed.
848        int dupFd = dup(blob.fd());
849        if (dupFd < 0) {
850            ALOGE("Error allocating dup fd. Error:%d", errno);
851            blob.release();
852            SkSafeUnref(ctable);
853            doThrowRE(env, "Could not allocate dup blob fd.");
854            return NULL;
855        }
856
857        // Map the pixels in place and take ownership of the ashmem region.
858        nativeBitmap = sk_sp<Bitmap>(GraphicsJNI::mapAshmemBitmap(env, bitmap.get(),
859                ctable, dupFd, const_cast<void*>(blob.data()), size, !isMutable));
860        SkSafeUnref(ctable);
861        if (!nativeBitmap) {
862            close(dupFd);
863            blob.release();
864            doThrowRE(env, "Could not allocate ashmem pixel ref.");
865            return NULL;
866        }
867
868        // Clear the blob handle, don't release it.
869        blob.clear();
870    } else {
871#if DEBUG_PARCEL
872        if (blob.fd() >= 0) {
873            ALOGD("Bitmap.createFromParcel: copied contents of mutable bitmap "
874                    "from immutable blob (fds %s)",
875                    p->allowFds() ? "allowed" : "forbidden");
876        } else {
877            ALOGD("Bitmap.createFromParcel: copied contents from %s blob "
878                    "(fds %s)",
879                    blob.isMutable() ? "mutable" : "immutable",
880                    p->allowFds() ? "allowed" : "forbidden");
881        }
882#endif
883
884        // Copy the pixels into a new buffer.
885        nativeBitmap = Bitmap::allocateHeapBitmap(bitmap.get(), ctable);
886        SkSafeUnref(ctable);
887        if (!nativeBitmap) {
888            blob.release();
889            doThrowRE(env, "Could not allocate java pixel ref.");
890            return NULL;
891        }
892        bitmap->lockPixels();
893        memcpy(bitmap->getPixels(), blob.data(), size);
894        bitmap->unlockPixels();
895
896        // Release the blob handle.
897        blob.release();
898    }
899
900    return createBitmap(env, nativeBitmap.release(),
901            getPremulBitmapCreateFlags(isMutable), NULL, NULL, density);
902}
903
904static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
905                                     jlong bitmapHandle,
906                                     jboolean isMutable, jint density,
907                                     jobject parcel) {
908    if (parcel == NULL) {
909        SkDebugf("------- writeToParcel null parcel\n");
910        return JNI_FALSE;
911    }
912
913    android::Parcel* p = android::parcelForJavaObject(env, parcel);
914    SkBitmap bitmap;
915
916    auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle);
917    bitmapWrapper->getSkBitmap(&bitmap);
918
919    sk_sp<SkColorSpace> sRGB = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
920    bool isSRGB = bitmap.colorSpace() == sRGB.get();
921
922    p->writeInt32(isMutable);
923    p->writeInt32(bitmap.colorType());
924    p->writeInt32(bitmap.alphaType());
925    p->writeInt32(isSRGB); // TODO: We should write the color space (b/32072280)
926    p->writeInt32(bitmap.width());
927    p->writeInt32(bitmap.height());
928    p->writeInt32(bitmap.rowBytes());
929    p->writeInt32(density);
930
931    if (bitmap.colorType() == kIndex_8_SkColorType) {
932        // The bitmap needs to be locked to access its color table.
933        SkAutoLockPixels alp(bitmap);
934        SkColorTable* ctable = bitmap.getColorTable();
935        if (ctable != NULL) {
936            int count = ctable->count();
937            p->writeInt32(count);
938            memcpy(p->writeInplace(count * sizeof(SkPMColor)),
939                   ctable->readColors(), count * sizeof(SkPMColor));
940        } else {
941            p->writeInt32(0);   // indicate no ctable
942        }
943    }
944
945    // Transfer the underlying ashmem region if we have one and it's immutable.
946    android::status_t status;
947    int fd = bitmapWrapper->bitmap().getAshmemFd();
948    if (fd >= 0 && !isMutable && p->allowFds()) {
949#if DEBUG_PARCEL
950        ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as "
951                "immutable blob (fds %s)",
952                p->allowFds() ? "allowed" : "forbidden");
953#endif
954
955        status = p->writeDupImmutableBlobFileDescriptor(fd);
956        if (status) {
957            doThrowRE(env, "Could not write bitmap blob file descriptor.");
958            return JNI_FALSE;
959        }
960        return JNI_TRUE;
961    }
962
963    // Copy the bitmap to a new blob.
964    bool mutableCopy = isMutable;
965#if DEBUG_PARCEL
966    ALOGD("Bitmap.writeToParcel: copying %s bitmap into new %s blob (fds %s)",
967            isMutable ? "mutable" : "immutable",
968            mutableCopy ? "mutable" : "immutable",
969            p->allowFds() ? "allowed" : "forbidden");
970#endif
971
972    size_t size = bitmap.getSize();
973    android::Parcel::WritableBlob blob;
974    status = p->writeBlob(size, mutableCopy, &blob);
975    if (status) {
976        doThrowRE(env, "Could not copy bitmap to parcel blob.");
977        return JNI_FALSE;
978    }
979
980    bitmap.lockPixels();
981    const void* pSrc =  bitmap.getPixels();
982    if (pSrc == NULL) {
983        memset(blob.data(), 0, size);
984    } else {
985        memcpy(blob.data(), pSrc, size);
986    }
987    bitmap.unlockPixels();
988
989    blob.release();
990    return JNI_TRUE;
991}
992
993static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
994                                   jlong srcHandle, jlong paintHandle,
995                                   jintArray offsetXY) {
996    SkBitmap src;
997    reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src);
998    const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle);
999    SkIPoint  offset;
1000    SkBitmap dst;
1001    HeapAllocator allocator;
1002
1003    src.extractAlpha(&dst, paint, &allocator, &offset);
1004    // If Skia can't allocate pixels for destination bitmap, it resets
1005    // it, that is set its pixels buffer to NULL, and zero width and height.
1006    if (dst.getPixels() == NULL && src.getPixels() != NULL) {
1007        doThrowOOME(env, "failed to allocate pixels for alpha");
1008        return NULL;
1009    }
1010    if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
1011        int* array = env->GetIntArrayElements(offsetXY, NULL);
1012        array[0] = offset.fX;
1013        array[1] = offset.fY;
1014        env->ReleaseIntArrayElements(offsetXY, array, 0);
1015    }
1016
1017    return createBitmap(env, allocator.getStorageObjAndReset(),
1018            getPremulBitmapCreateFlags(true));
1019}
1020
1021///////////////////////////////////////////////////////////////////////////////
1022
1023static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
1024        jint x, jint y) {
1025    SkBitmap bitmap;
1026    reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1027    SkAutoLockPixels alp(bitmap);
1028
1029    ToColorProc proc = ChooseToColorProc(bitmap);
1030    if (NULL == proc) {
1031        return 0;
1032    }
1033    const void* src = bitmap.getAddr(x, y);
1034    if (NULL == src) {
1035        return 0;
1036    }
1037
1038    SkColor dst[1];
1039    proc(dst, src, 1, bitmap.getColorTable());
1040    return static_cast<jint>(dst[0]);
1041}
1042
1043static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,
1044        jintArray pixelArray, jint offset, jint stride,
1045        jint x, jint y, jint width, jint height) {
1046    SkBitmap bitmap;
1047    reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1048    SkAutoLockPixels alp(bitmap);
1049
1050    ToColorProc proc = ChooseToColorProc(bitmap);
1051    if (NULL == proc) {
1052        return;
1053    }
1054    const void* src = bitmap.getAddr(x, y);
1055    if (NULL == src) {
1056        return;
1057    }
1058
1059    SkColorTable* ctable = bitmap.getColorTable();
1060    jint* dst = env->GetIntArrayElements(pixelArray, NULL);
1061    SkColor* d = (SkColor*)dst + offset;
1062    while (--height >= 0) {
1063        proc(d, src, width, ctable);
1064        d += stride;
1065        src = (void*)((const char*)src + bitmap.rowBytes());
1066    }
1067    env->ReleaseIntArrayElements(pixelArray, dst, 0);
1068}
1069
1070///////////////////////////////////////////////////////////////////////////////
1071
1072static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle,
1073        jint x, jint y, jint colorHandle) {
1074    SkBitmap bitmap;
1075    reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1076    SkColor color = static_cast<SkColor>(colorHandle);
1077    SkAutoLockPixels alp(bitmap);
1078    if (NULL == bitmap.getPixels()) {
1079        return;
1080    }
1081
1082    FromColorProc proc = ChooseFromColorProc(bitmap);
1083    if (NULL == proc) {
1084        return;
1085    }
1086
1087    proc(bitmap.getAddr(x, y), &color, 1, x, y);
1088    bitmap.notifyPixelsChanged();
1089}
1090
1091static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,
1092        jintArray pixelArray, jint offset, jint stride,
1093        jint x, jint y, jint width, jint height) {
1094    SkBitmap bitmap;
1095    reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1096    GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
1097            x, y, width, height, bitmap);
1098}
1099
1100static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
1101                                      jlong bitmapHandle, jobject jbuffer) {
1102    SkBitmap bitmap;
1103    reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1104    SkAutoLockPixels alp(bitmap);
1105    const void* src = bitmap.getPixels();
1106
1107    if (NULL != src) {
1108        android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
1109
1110        // the java side has already checked that buffer is large enough
1111        memcpy(abp.pointer(), src, bitmap.getSize());
1112    }
1113}
1114
1115static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,
1116                                        jlong bitmapHandle, jobject jbuffer) {
1117    SkBitmap bitmap;
1118    reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap);
1119    SkAutoLockPixels alp(bitmap);
1120    void* dst = bitmap.getPixels();
1121
1122    if (NULL != dst) {
1123        android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);
1124        // the java side has already checked that buffer is large enough
1125        memcpy(dst, abp.pointer(), bitmap.getSize());
1126        bitmap.notifyPixelsChanged();
1127    }
1128}
1129
1130static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle,
1131                              jlong bm1Handle) {
1132    SkBitmap bm0;
1133    SkBitmap bm1;
1134
1135    LocalScopedBitmap bitmap0(bm0Handle);
1136    LocalScopedBitmap bitmap1(bm1Handle);
1137
1138    // Paying the price for making Hardware Bitmap as Config:
1139    // later check for colorType will pass successfully,
1140    // because Hardware Config internally may be RGBA8888 or smth like that.
1141    if (bitmap0->bitmap().isHardware() != bitmap1->bitmap().isHardware()) {
1142        return JNI_FALSE;
1143    }
1144
1145    bitmap0->bitmap().getSkBitmap(&bm0);
1146    bitmap1->bitmap().getSkBitmap(&bm1);
1147    if (bm0.width() != bm1.width() ||
1148        bm0.height() != bm1.height() ||
1149        bm0.colorType() != bm1.colorType() ||
1150        bm0.alphaType() != bm1.alphaType() ||
1151        bm0.colorSpace() != bm1.colorSpace()) {
1152        return JNI_FALSE;
1153    }
1154
1155    SkAutoLockPixels alp0(bm0);
1156    SkAutoLockPixels alp1(bm1);
1157
1158    // if we can't load the pixels, return false
1159    if (NULL == bm0.getPixels() || NULL == bm1.getPixels()) {
1160        return JNI_FALSE;
1161    }
1162
1163    if (bm0.colorType() == kIndex_8_SkColorType) {
1164        SkColorTable* ct0 = bm0.getColorTable();
1165        SkColorTable* ct1 = bm1.getColorTable();
1166        if (NULL == ct0 || NULL == ct1) {
1167            return JNI_FALSE;
1168        }
1169        if (ct0->count() != ct1->count()) {
1170            return JNI_FALSE;
1171        }
1172
1173        const size_t size = ct0->count() * sizeof(SkPMColor);
1174        if (memcmp(ct0->readColors(), ct1->readColors(), size) != 0) {
1175            return JNI_FALSE;
1176        }
1177    }
1178
1179    // now compare each scanline. We can't do the entire buffer at once,
1180    // since we don't care about the pixel values that might extend beyond
1181    // the width (since the scanline might be larger than the logical width)
1182    const int h = bm0.height();
1183    const size_t size = bm0.width() * bm0.bytesPerPixel();
1184    for (int y = 0; y < h; y++) {
1185        // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config
1186        // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0
1187        // and bm1 both have pixel data() (have passed NULL == getPixels() check),
1188        // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE
1189        // to warn user those 2 unrecognized config bitmaps may be different.
1190        void *bm0Addr = bm0.getAddr(0, y);
1191        void *bm1Addr = bm1.getAddr(0, y);
1192
1193        if(bm0Addr == NULL || bm1Addr == NULL) {
1194            return JNI_FALSE;
1195        }
1196
1197        if (memcmp(bm0Addr, bm1Addr, size) != 0) {
1198            return JNI_FALSE;
1199        }
1200    }
1201    return JNI_TRUE;
1202}
1203
1204static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapPtr) {
1205    LocalScopedBitmap bitmapHandle(bitmapPtr);
1206    if (!bitmapHandle.valid()) return;
1207    android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmapHandle->bitmap());
1208}
1209
1210static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr) {
1211    LocalScopedBitmap bitmapHandle(bitmapPtr);
1212    return static_cast<jint>(bitmapHandle->getAllocationByteCount());
1213}
1214
1215///////////////////////////////////////////////////////////////////////////////
1216static jclass make_globalref(JNIEnv* env, const char classname[])
1217{
1218    jclass c = env->FindClass(classname);
1219    SkASSERT(c);
1220    return (jclass) env->NewGlobalRef(c);
1221}
1222
1223static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
1224                                const char fieldname[], const char type[])
1225{
1226    jfieldID id = env->GetFieldID(clazz, fieldname, type);
1227    SkASSERT(id);
1228    return id;
1229}
1230
1231static const JNINativeMethod gBitmapMethods[] = {
1232    {   "nativeCreate",             "([IIIIIIZ)Landroid/graphics/Bitmap;",
1233        (void*)Bitmap_creator },
1234    {   "nativeCopy",               "(JIZ)Landroid/graphics/Bitmap;",
1235        (void*)Bitmap_copy },
1236    {   "nativeCopyAshmem",         "(J)Landroid/graphics/Bitmap;",
1237        (void*)Bitmap_copyAshmem },
1238    {   "nativeCopyAshmemConfig",   "(JI)Landroid/graphics/Bitmap;",
1239        (void*)Bitmap_copyAshmemConfig },
1240    {   "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer },
1241    {   "nativeRecycle",            "(J)Z", (void*)Bitmap_recycle },
1242    {   "nativeReconfigure",        "(JIIIZ)V", (void*)Bitmap_reconfigure },
1243    {   "nativeCompress",           "(JIILjava/io/OutputStream;[B)Z",
1244        (void*)Bitmap_compress },
1245    {   "nativeErase",              "(JI)V", (void*)Bitmap_erase },
1246    {   "nativeRowBytes",           "(J)I", (void*)Bitmap_rowBytes },
1247    {   "nativeConfig",             "(J)I", (void*)Bitmap_config },
1248    {   "nativeHasAlpha",           "(J)Z", (void*)Bitmap_hasAlpha },
1249    {   "nativeIsPremultiplied",    "(J)Z", (void*)Bitmap_isPremultiplied},
1250    {   "nativeSetHasAlpha",        "(JZZ)V", (void*)Bitmap_setHasAlpha},
1251    {   "nativeSetPremultiplied",   "(JZ)V", (void*)Bitmap_setPremultiplied},
1252    {   "nativeHasMipMap",          "(J)Z", (void*)Bitmap_hasMipMap },
1253    {   "nativeSetHasMipMap",       "(JZ)V", (void*)Bitmap_setHasMipMap },
1254    {   "nativeCreateFromParcel",
1255        "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
1256        (void*)Bitmap_createFromParcel },
1257    {   "nativeWriteToParcel",      "(JZILandroid/os/Parcel;)Z",
1258        (void*)Bitmap_writeToParcel },
1259    {   "nativeExtractAlpha",       "(JJ[I)Landroid/graphics/Bitmap;",
1260        (void*)Bitmap_extractAlpha },
1261    {   "nativeGenerationId",       "(J)I", (void*)Bitmap_getGenerationId },
1262    {   "nativeGetPixel",           "(JII)I", (void*)Bitmap_getPixel },
1263    {   "nativeGetPixels",          "(J[IIIIIII)V", (void*)Bitmap_getPixels },
1264    {   "nativeSetPixel",           "(JIII)V", (void*)Bitmap_setPixel },
1265    {   "nativeSetPixels",          "(J[IIIIIII)V", (void*)Bitmap_setPixels },
1266    {   "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V",
1267                                            (void*)Bitmap_copyPixelsToBuffer },
1268    {   "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V",
1269                                            (void*)Bitmap_copyPixelsFromBuffer },
1270    {   "nativeSameAs",             "(JJ)Z", (void*)Bitmap_sameAs },
1271    {   "nativePrepareToDraw",      "(J)V", (void*)Bitmap_prepareToDraw },
1272    {   "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount },
1273};
1274
1275int register_android_graphics_Bitmap(JNIEnv* env)
1276{
1277    gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
1278    gBitmap_nativePtr = getFieldIDCheck(env, gBitmap_class, "mNativePtr", "J");
1279    gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
1280    gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "(IIZ)V");
1281    gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I");
1282    return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods,
1283                                         NELEM(gBitmapMethods));
1284}
1285