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