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