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