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