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