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