blob: e79732100e5310e3860671677284e59b4342b2cc [file] [log] [blame]
John Reckf29ed282015-04-07 07:32:03 -07001#define LOG_TAG "Bitmap"
John Reckf29ed282015-04-07 07:32:03 -07002#include "Bitmap.h"
3
Chris Craik32054b02014-05-09 13:58:56 -07004#include "SkBitmap.h"
5#include "SkPixelRef.h"
6#include "SkImageEncoder.h"
Leon Scroggins III57ee6202014-06-04 18:51:07 -04007#include "SkImageInfo.h"
Chris Craik32054b02014-05-09 13:58:56 -07008#include "SkColorPriv.h"
9#include "GraphicsJNI.h"
10#include "SkDither.h"
11#include "SkUnPreMultiply.h"
12#include "SkStream.h"
13
14#include <binder/Parcel.h>
15#include "android_os_Parcel.h"
16#include "android_util_Binder.h"
17#include "android_nio_utils.h"
18#include "CreateJavaOutputStreamAdaptor.h"
John Reckf29ed282015-04-07 07:32:03 -070019#include <Caches.h>
sergeyvdccca442016-03-21 15:38:21 -070020#include <hwui/Paint.h>
John Reck43871902016-08-01 14:39:24 -070021#include <renderthread/RenderProxy.h>
Chris Craik32054b02014-05-09 13:58:56 -070022
Andreas Gampeed6b9df2014-11-20 22:02:20 -080023#include "core_jni_helpers.h"
24
Chris Craik32054b02014-05-09 13:58:56 -070025#include <jni.h>
Riley Andrews39d7f302014-11-13 17:43:25 -080026#include <memory>
27#include <string>
28#include <sys/mman.h>
29#include <cutils/ashmem.h>
Chris Craik32054b02014-05-09 13:58:56 -070030
Jeff Browna316c5d2015-06-05 15:14:06 -070031#define DEBUG_PARCEL 0
Riley Andrews8cee7c12015-11-01 23:36:04 -080032#define ASHMEM_BITMAP_MIN_SIZE (128 * (1 << 10))
Jeff Browna316c5d2015-06-05 15:14:06 -070033
sergeyvc69853c2016-10-07 14:14:09 -070034static jclass gBitmap_class;
35static jfieldID gBitmap_nativePtr;
36static jmethodID gBitmap_constructorMethodID;
37static jmethodID gBitmap_reinitMethodID;
38static jmethodID gBitmap_getAllocationByteCountMethodID;
39
John Reckf29ed282015-04-07 07:32:03 -070040namespace android {
41
sergeyvc69853c2016-10-07 14:14:09 -070042class Bitmap {
John Reckf29ed282015-04-07 07:32:03 -070043public:
sergeyvc69853c2016-10-07 14:14:09 -070044 Bitmap(PixelRef* pixelRef)
45 : mPixelRef(pixelRef) { }
46
47 void freePixels() {
48 mInfo = mPixelRef->info();
49 mHasHardwareMipMap = mPixelRef->hasHardwareMipMap();
50 mAllocationSize = mPixelRef->getAllocationByteCount();
51 mRowBytes = mPixelRef->rowBytes();
52 mGenerationId = mPixelRef->getGenerationID();
53 mPixelRef.reset();
John Reckf29ed282015-04-07 07:32:03 -070054 }
55
sergeyvc69853c2016-10-07 14:14:09 -070056 bool valid() {
57 return !!mPixelRef;
John Reckf29ed282015-04-07 07:32:03 -070058 }
59
sergeyvc69853c2016-10-07 14:14:09 -070060 PixelRef* pixelRef() { return mPixelRef.get(); }
61
62 void assertValid() {
63 LOG_ALWAYS_FATAL_IF(!valid(), "Error, cannot access an invalid/free'd bitmap here!");
64 }
65
66 void getSkBitmap(SkBitmap* outBitmap) {
67 assertValid();
68 mPixelRef->getSkBitmap(outBitmap);
69 }
70
71 bool hasHardwareMipMap() {
72 if (mPixelRef) {
73 return mPixelRef->hasHardwareMipMap();
John Reckf29ed282015-04-07 07:32:03 -070074 }
John Reckf29ed282015-04-07 07:32:03 -070075 return mHasHardwareMipMap;
76 }
77
78 void setHasHardwareMipMap(bool hasMipMap) {
sergeyvc69853c2016-10-07 14:14:09 -070079 assertValid();
80 mPixelRef->setHasHardwareMipMap(hasMipMap);
John Reckf29ed282015-04-07 07:32:03 -070081 }
82
sergeyvc69853c2016-10-07 14:14:09 -070083 void setAlphaType(SkAlphaType alphaType) {
84 assertValid();
85 mPixelRef->setAlphaType(alphaType);
John Reckf29ed282015-04-07 07:32:03 -070086 }
87
sergeyvc69853c2016-10-07 14:14:09 -070088 const SkImageInfo& info() {
89 if (mPixelRef) {
90 return mPixelRef->info();
91 }
92 return mInfo;
John Reckf29ed282015-04-07 07:32:03 -070093 }
94
sergeyvc69853c2016-10-07 14:14:09 -070095 size_t getAllocationByteCount() const {
96 if (mPixelRef) {
97 return mPixelRef->getAllocationByteCount();
98 }
99 return mAllocationSize;
John Reckf29ed282015-04-07 07:32:03 -0700100 }
101
sergeyvc69853c2016-10-07 14:14:09 -0700102 size_t rowBytes() const {
103 if (mPixelRef) {
104 return mPixelRef->rowBytes();
105 }
106 return mRowBytes;
107 }
108
109 uint32_t getGenerationID() const {
110 if (mPixelRef) {
111 return mPixelRef->getGenerationID();
112 }
113 return mGenerationId;
114 }
115
116 ~Bitmap() { }
117
John Reckf29ed282015-04-07 07:32:03 -0700118private:
sergeyvc69853c2016-10-07 14:14:09 -0700119 sk_sp<PixelRef> mPixelRef;
120 SkImageInfo mInfo;
121 bool mHasHardwareMipMap;
122 size_t mAllocationSize;
123 size_t mRowBytes;
124 uint32_t mGenerationId;
John Reckf29ed282015-04-07 07:32:03 -0700125};
126
sergeyvc69853c2016-10-07 14:14:09 -0700127void PixelRef::reconfigure(const SkImageInfo& newInfo, size_t rowBytes, SkColorTable* ctable) {
128 if (kIndex_8_SkColorType != newInfo.colorType()) {
129 ctable = nullptr;
130 }
131 mRowBytes = rowBytes;
132 if (mColorTable.get() != ctable) {
133 mColorTable.reset(ctable);
134 }
135
136 // Need to validate the alpha type to filter against the color type
137 // to prevent things like a non-opaque RGB565 bitmap
138 SkAlphaType alphaType;
139 LOG_ALWAYS_FATAL_IF(!SkColorTypeValidateAlphaType(
140 newInfo.colorType(), newInfo.alphaType(), &alphaType),
141 "Failed to validate alpha type!");
142
143 // Dirty hack is dirty
144 // TODO: Figure something out here, Skia's current design makes this
145 // really hard to work with. Skia really, really wants immutable objects,
146 // but with the nested-ref-count hackery going on that's just not
147 // feasible without going insane trying to figure it out
148 SkImageInfo* myInfo = const_cast<SkImageInfo*>(&this->info());
149 *myInfo = newInfo;
150 changeAlphaType(alphaType);
151
152 // Docs say to only call this in the ctor, but we're going to call
153 // it anyway even if this isn't always the ctor.
154 // TODO: Fix this too as part of the above TODO
155 setPreLocked(getStorage(), mRowBytes, mColorTable.get());
John Reckf29ed282015-04-07 07:32:03 -0700156}
157
sergeyvc69853c2016-10-07 14:14:09 -0700158PixelRef::PixelRef(void* address, size_t size, const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
159 : SkPixelRef(info)
160 , mPixelStorageType(PixelStorageType::Heap) {
161 mPixelStorage.heap.address = address;
162 mPixelStorage.heap.size = size;
163 reconfigure(info, rowBytes, ctable);
164}
165
166PixelRef::PixelRef(void* address, void* context, FreeFunc freeFunc,
167 const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
168 : SkPixelRef(info)
169 , mPixelStorageType(PixelStorageType::External) {
John Reckf29ed282015-04-07 07:32:03 -0700170 mPixelStorage.external.address = address;
171 mPixelStorage.external.context = context;
172 mPixelStorage.external.freeFunc = freeFunc;
sergeyvc69853c2016-10-07 14:14:09 -0700173 reconfigure(info, rowBytes, ctable);
John Reckf29ed282015-04-07 07:32:03 -0700174}
175
sergeyvc69853c2016-10-07 14:14:09 -0700176PixelRef::PixelRef(void* address, int fd, size_t mappedSize,
177 const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
178 : SkPixelRef(info)
179 , mPixelStorageType(PixelStorageType::Ashmem) {
Riley Andrews39d7f302014-11-13 17:43:25 -0800180 mPixelStorage.ashmem.address = address;
181 mPixelStorage.ashmem.fd = fd;
John Reck003bdee2016-09-12 10:43:35 -0700182 mPixelStorage.ashmem.size = mappedSize;
sergeyvc69853c2016-10-07 14:14:09 -0700183 reconfigure(info, rowBytes, ctable);
John Reckf29ed282015-04-07 07:32:03 -0700184}
185
sergeyvc69853c2016-10-07 14:14:09 -0700186PixelRef::~PixelRef() {
John Reckf29ed282015-04-07 07:32:03 -0700187 switch (mPixelStorageType) {
John Reckf29ed282015-04-07 07:32:03 -0700188 case PixelStorageType::External:
189 mPixelStorage.external.freeFunc(mPixelStorage.external.address,
190 mPixelStorage.external.context);
191 break;
Riley Andrews39d7f302014-11-13 17:43:25 -0800192 case PixelStorageType::Ashmem:
193 munmap(mPixelStorage.ashmem.address, mPixelStorage.ashmem.size);
194 close(mPixelStorage.ashmem.fd);
195 break;
sergeyv45082182016-09-29 18:25:40 -0700196 case PixelStorageType::Heap:
197 free(mPixelStorage.heap.address);
John Reckf29ed282015-04-07 07:32:03 -0700198 break;
199 }
200
201 if (android::uirenderer::Caches::hasInstance()) {
sergeyvc69853c2016-10-07 14:14:09 -0700202 android::uirenderer::Caches::getInstance().textureCache.releaseTexture(getStableID());
John Reckf29ed282015-04-07 07:32:03 -0700203 }
204}
205
sergeyvc69853c2016-10-07 14:14:09 -0700206bool PixelRef::hasHardwareMipMap() const {
207 return mHasHardwareMipMap;
John Reckf29ed282015-04-07 07:32:03 -0700208}
209
sergeyvc69853c2016-10-07 14:14:09 -0700210void PixelRef::setHasHardwareMipMap(bool hasMipMap) {
211 mHasHardwareMipMap = hasMipMap;
John Reckf29ed282015-04-07 07:32:03 -0700212}
213
sergeyvc69853c2016-10-07 14:14:09 -0700214void* PixelRef::getStorage() const {
215 switch (mPixelStorageType) {
216 case PixelStorageType::External:
217 return mPixelStorage.external.address;
218 case PixelStorageType::Ashmem:
219 return mPixelStorage.ashmem.address;
220 case PixelStorageType::Heap:
221 return mPixelStorage.heap.address;
222 }
223}
224
225bool PixelRef::onNewLockPixels(LockRec* rec) {
226 rec->fPixels = getStorage();
227 rec->fRowBytes = mRowBytes;
228 rec->fColorTable = mColorTable.get();
229 return true;
230}
231
232size_t PixelRef::getAllocatedSizeInBytes() const {
233 return info().getSafeSize(mRowBytes);
234}
235
236int PixelRef::getAshmemFd() const {
Riley Andrews39d7f302014-11-13 17:43:25 -0800237 switch (mPixelStorageType) {
238 case PixelStorageType::Ashmem:
239 return mPixelStorage.ashmem.fd;
240 default:
241 return -1;
242 }
243}
244
sergeyvc69853c2016-10-07 14:14:09 -0700245size_t PixelRef::getAllocationByteCount() const {
sergeyv45082182016-09-29 18:25:40 -0700246 switch (mPixelStorageType) {
247 case PixelStorageType::Heap:
248 return mPixelStorage.heap.size;
249 default:
250 return rowBytes() * height();
251 }
252}
253
sergeyvc69853c2016-10-07 14:14:09 -0700254void PixelRef::reconfigure(const SkImageInfo& info) {
Derek Sollenberger2a94a102015-05-07 13:56:14 -0400255 reconfigure(info, info.minRowBytes(), nullptr);
John Reckf29ed282015-04-07 07:32:03 -0700256}
257
sergeyvc69853c2016-10-07 14:14:09 -0700258void PixelRef::setAlphaType(SkAlphaType alphaType) {
John Reck0781a2f2015-05-27 16:29:17 -0700259 if (!SkColorTypeValidateAlphaType(info().colorType(), alphaType, &alphaType)) {
260 return;
261 }
262
sergeyvc69853c2016-10-07 14:14:09 -0700263 changeAlphaType(alphaType);
John Reck0781a2f2015-05-27 16:29:17 -0700264}
265
sergeyvc69853c2016-10-07 14:14:09 -0700266void PixelRef::getSkBitmap(SkBitmap* outBitmap) {
267 outBitmap->setInfo(info(), rowBytes());
268 outBitmap->setPixelRef(this);
269 outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
John Reckf29ed282015-04-07 07:32:03 -0700270}
271
John Reckf29ed282015-04-07 07:32:03 -0700272
273// Convenience class that does not take a global ref on the pixels, relying
274// on the caller already having a local JNI ref
275class LocalScopedBitmap {
276public:
Chih-Hung Hsiehc6baf562016-04-27 11:29:23 -0700277 explicit LocalScopedBitmap(jlong bitmapHandle)
John Reckf29ed282015-04-07 07:32:03 -0700278 : mBitmap(reinterpret_cast<Bitmap*>(bitmapHandle)) {}
279
280 Bitmap* operator->() {
281 return mBitmap;
282 }
283
284 void* pixels() {
sergeyvc69853c2016-10-07 14:14:09 -0700285 return mBitmap->pixelRef()->pixels();
John Reckf29ed282015-04-07 07:32:03 -0700286 }
287
288 bool valid() {
289 return mBitmap && mBitmap->valid();
290 }
291
292private:
293 Bitmap* mBitmap;
294};
295
sergeyvc69853c2016-10-07 14:14:09 -0700296namespace bitmap {
297
298// Assert that bitmap's SkAlphaType is consistent with isPremultiplied.
299static void assert_premultiplied(const SkImageInfo& info, bool isPremultiplied) {
300 // kOpaque_SkAlphaType and kIgnore_SkAlphaType mean that isPremultiplied is
301 // irrelevant. This just tests to ensure that the SkAlphaType is not
302 // opposite of isPremultiplied.
303 if (isPremultiplied) {
304 SkASSERT(info.alphaType() != kUnpremul_SkAlphaType);
305 } else {
306 SkASSERT(info.alphaType() != kPremul_SkAlphaType);
307 }
308}
309
310void reinitBitmap(JNIEnv* env, jobject javaBitmap, const SkImageInfo& info,
311 bool isPremultiplied)
312{
313 // The caller needs to have already set the alpha type properly, so the
314 // native SkBitmap stays in sync with the Java Bitmap.
315 assert_premultiplied(info, isPremultiplied);
316
317 env->CallVoidMethod(javaBitmap, gBitmap_reinitMethodID,
318 info.width(), info.height(), isPremultiplied);
319}
320
321int getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap)
322{
323 return env->CallIntMethod(javaBitmap, gBitmap_getAllocationByteCountMethodID);
324}
325
326jobject createBitmap(JNIEnv* env, PixelRef* pixelRef,
327 int bitmapCreateFlags, jbyteArray ninePatchChunk, jobject ninePatchInsets,
328 int density) {
329 bool isMutable = bitmapCreateFlags & kBitmapCreateFlag_Mutable;
330 bool isPremultiplied = bitmapCreateFlags & kBitmapCreateFlag_Premultiplied;
331 // The caller needs to have already set the alpha type properly, so the
332 // native SkBitmap stays in sync with the Java Bitmap.
333 assert_premultiplied(pixelRef->info(), isPremultiplied);
334 Bitmap* bitmap = new Bitmap(pixelRef);
335 jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
336 reinterpret_cast<jlong>(bitmap), pixelRef->width(), pixelRef->height(), density, isMutable,
337 isPremultiplied, ninePatchChunk, ninePatchInsets);
338
339 if (env->ExceptionCheck() != 0) {
340 ALOGE("*** Uncaught exception returned from Java call!\n");
341 env->ExceptionDescribe();
342 }
343 return obj;
344}
345
346void toSkBitmap(jlong bitmapHandle, SkBitmap* outBitmap) {
347 LocalScopedBitmap bitmap(bitmapHandle);
348 bitmap->getSkBitmap(outBitmap);
349}
350
351PixelRef* toPixelRef(JNIEnv* env, jobject bitmap) {
352 SkASSERT(env);
353 SkASSERT(bitmap);
354 SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
355 jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
356 LocalScopedBitmap localBitmap(bitmapHandle);
357 localBitmap->assertValid();
358 return localBitmap->pixelRef();
359}
360
361} // namespace bitmap
362
363} // namespace android
364
365using namespace android;
366using namespace android::bitmap;
367
Chris Craik32054b02014-05-09 13:58:56 -0700368///////////////////////////////////////////////////////////////////////////////
369// Conversions to/from SkColor, for get/setPixels, and the create method, which
370// is basically like setPixels
371
372typedef void (*FromColorProc)(void* dst, const SkColor src[], int width,
373 int x, int y);
374
375static void FromColor_D32(void* dst, const SkColor src[], int width,
376 int, int) {
377 SkPMColor* d = (SkPMColor*)dst;
378
379 for (int i = 0; i < width; i++) {
380 *d++ = SkPreMultiplyColor(*src++);
381 }
382}
383
384static void FromColor_D32_Raw(void* dst, const SkColor src[], int width,
385 int, int) {
Dan Albert46d84442014-11-18 16:07:51 -0800386 // Needed to thwart the unreachable code detection from clang.
387 static const bool sk_color_ne_zero = SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER;
388
Chris Craik32054b02014-05-09 13:58:56 -0700389 // SkColor's ordering may be different from SkPMColor
Dan Albert46d84442014-11-18 16:07:51 -0800390 if (sk_color_ne_zero) {
Chris Craik32054b02014-05-09 13:58:56 -0700391 memcpy(dst, src, width * sizeof(SkColor));
392 return;
393 }
394
395 // order isn't same, repack each pixel manually
396 SkPMColor* d = (SkPMColor*)dst;
397 for (int i = 0; i < width; i++) {
398 SkColor c = *src++;
399 *d++ = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
400 SkColorGetG(c), SkColorGetB(c));
401 }
402}
403
404static void FromColor_D565(void* dst, const SkColor src[], int width,
405 int x, int y) {
406 uint16_t* d = (uint16_t*)dst;
407
408 DITHER_565_SCAN(y);
409 for (int stop = x + width; x < stop; x++) {
410 SkColor c = *src++;
411 *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c),
412 DITHER_VALUE(x));
413 }
414}
415
416static void FromColor_D4444(void* dst, const SkColor src[], int width,
417 int x, int y) {
418 SkPMColor16* d = (SkPMColor16*)dst;
419
420 DITHER_4444_SCAN(y);
421 for (int stop = x + width; x < stop; x++) {
422 SkPMColor pmc = SkPreMultiplyColor(*src++);
423 *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
424// *d++ = SkPixel32ToPixel4444(pmc);
425 }
426}
427
428static void FromColor_D4444_Raw(void* dst, const SkColor src[], int width,
429 int x, int y) {
430 SkPMColor16* d = (SkPMColor16*)dst;
431
432 DITHER_4444_SCAN(y);
433 for (int stop = x + width; x < stop; x++) {
434 SkColor c = *src++;
435
436 // SkPMColor is used because the ordering is ARGB32, even though the target actually premultiplied
437 SkPMColor pmc = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
438 SkColorGetG(c), SkColorGetB(c));
439 *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
440// *d++ = SkPixel32ToPixel4444(pmc);
441 }
442}
443
Chris Craik6260b222015-07-24 15:17:29 -0700444static void FromColor_DA8(void* dst, const SkColor src[], int width, int x, int y) {
445 uint8_t* d = (uint8_t*)dst;
446
447 for (int stop = x + width; x < stop; x++) {
448 *d++ = SkColorGetA(*src++);
449 }
450}
451
Chris Craik32054b02014-05-09 13:58:56 -0700452// can return NULL
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400453static FromColorProc ChooseFromColorProc(const SkBitmap& bitmap) {
454 switch (bitmap.colorType()) {
455 case kN32_SkColorType:
456 return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D32 : FromColor_D32_Raw;
457 case kARGB_4444_SkColorType:
458 return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D4444 :
459 FromColor_D4444_Raw;
460 case kRGB_565_SkColorType:
Chris Craik32054b02014-05-09 13:58:56 -0700461 return FromColor_D565;
Chris Craik6260b222015-07-24 15:17:29 -0700462 case kAlpha_8_SkColorType:
463 return FromColor_DA8;
Chris Craik32054b02014-05-09 13:58:56 -0700464 default:
465 break;
466 }
467 return NULL;
468}
469
470bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride,
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400471 int x, int y, int width, int height, const SkBitmap& dstBitmap) {
Chris Craik32054b02014-05-09 13:58:56 -0700472 SkAutoLockPixels alp(dstBitmap);
473 void* dst = dstBitmap.getPixels();
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400474 FromColorProc proc = ChooseFromColorProc(dstBitmap);
Chris Craik32054b02014-05-09 13:58:56 -0700475
476 if (NULL == dst || NULL == proc) {
477 return false;
478 }
479
480 const jint* array = env->GetIntArrayElements(srcColors, NULL);
481 const SkColor* src = (const SkColor*)array + srcOffset;
482
483 // reset to to actual choice from caller
484 dst = dstBitmap.getAddr(x, y);
485 // now copy/convert each scanline
486 for (int y = 0; y < height; y++) {
487 proc(dst, src, width, x, y);
488 src += srcStride;
489 dst = (char*)dst + dstBitmap.rowBytes();
490 }
491
492 dstBitmap.notifyPixelsChanged();
493
494 env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array),
495 JNI_ABORT);
496 return true;
497}
498
499//////////////////// ToColor procs
500
501typedef void (*ToColorProc)(SkColor dst[], const void* src, int width,
502 SkColorTable*);
503
504static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width,
505 SkColorTable*) {
506 SkASSERT(width > 0);
507 const SkPMColor* s = (const SkPMColor*)src;
508 do {
509 *dst++ = SkUnPreMultiply::PMColorToColor(*s++);
510 } while (--width != 0);
511}
512
513static void ToColor_S32_Raw(SkColor dst[], const void* src, int width,
514 SkColorTable*) {
515 SkASSERT(width > 0);
516 const SkPMColor* s = (const SkPMColor*)src;
517 do {
518 SkPMColor c = *s++;
519 *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
520 SkGetPackedG32(c), SkGetPackedB32(c));
521 } while (--width != 0);
522}
523
524static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width,
525 SkColorTable*) {
526 SkASSERT(width > 0);
527 const SkPMColor* s = (const SkPMColor*)src;
528 do {
529 SkPMColor c = *s++;
530 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
531 SkGetPackedB32(c));
532 } while (--width != 0);
533}
534
535static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width,
536 SkColorTable*) {
537 SkASSERT(width > 0);
538 const SkPMColor16* s = (const SkPMColor16*)src;
539 do {
540 *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++));
541 } while (--width != 0);
542}
543
544static void ToColor_S4444_Raw(SkColor dst[], const void* src, int width,
545 SkColorTable*) {
546 SkASSERT(width > 0);
547 const SkPMColor16* s = (const SkPMColor16*)src;
548 do {
549 SkPMColor c = SkPixel4444ToPixel32(*s++);
550 *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
551 SkGetPackedG32(c), SkGetPackedB32(c));
552 } while (--width != 0);
553}
554
555static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width,
556 SkColorTable*) {
557 SkASSERT(width > 0);
558 const SkPMColor16* s = (const SkPMColor16*)src;
559 do {
560 SkPMColor c = SkPixel4444ToPixel32(*s++);
561 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
562 SkGetPackedB32(c));
563 } while (--width != 0);
564}
565
566static void ToColor_S565(SkColor dst[], const void* src, int width,
567 SkColorTable*) {
568 SkASSERT(width > 0);
569 const uint16_t* s = (const uint16_t*)src;
570 do {
571 uint16_t c = *s++;
572 *dst++ = SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c),
573 SkPacked16ToB32(c));
574 } while (--width != 0);
575}
576
577static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width,
578 SkColorTable* ctable) {
579 SkASSERT(width > 0);
580 const uint8_t* s = (const uint8_t*)src;
Mike Reed71487eb2014-11-19 16:13:20 -0500581 const SkPMColor* colors = ctable->readColors();
Chris Craik32054b02014-05-09 13:58:56 -0700582 do {
583 *dst++ = SkUnPreMultiply::PMColorToColor(colors[*s++]);
584 } while (--width != 0);
Chris Craik32054b02014-05-09 13:58:56 -0700585}
586
587static void ToColor_SI8_Raw(SkColor dst[], const void* src, int width,
588 SkColorTable* ctable) {
589 SkASSERT(width > 0);
590 const uint8_t* s = (const uint8_t*)src;
Mike Reed71487eb2014-11-19 16:13:20 -0500591 const SkPMColor* colors = ctable->readColors();
Chris Craik32054b02014-05-09 13:58:56 -0700592 do {
593 SkPMColor c = colors[*s++];
594 *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
595 SkGetPackedG32(c), SkGetPackedB32(c));
596 } while (--width != 0);
Chris Craik32054b02014-05-09 13:58:56 -0700597}
598
599static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width,
600 SkColorTable* ctable) {
601 SkASSERT(width > 0);
602 const uint8_t* s = (const uint8_t*)src;
Mike Reed71487eb2014-11-19 16:13:20 -0500603 const SkPMColor* colors = ctable->readColors();
Chris Craik32054b02014-05-09 13:58:56 -0700604 do {
605 SkPMColor c = colors[*s++];
606 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
607 SkGetPackedB32(c));
608 } while (--width != 0);
Chris Craik32054b02014-05-09 13:58:56 -0700609}
610
Chris Craik6260b222015-07-24 15:17:29 -0700611static void ToColor_SA8(SkColor dst[], const void* src, int width, SkColorTable*) {
612 SkASSERT(width > 0);
613 const uint8_t* s = (const uint8_t*)src;
614 do {
615 uint8_t c = *s++;
616 *dst++ = SkColorSetARGB(c, c, c, c);
617 } while (--width != 0);
618}
619
Chris Craik32054b02014-05-09 13:58:56 -0700620// can return NULL
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400621static ToColorProc ChooseToColorProc(const SkBitmap& src) {
Mike Reedb9330552014-06-16 17:31:48 -0400622 switch (src.colorType()) {
623 case kN32_SkColorType:
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400624 switch (src.alphaType()) {
625 case kOpaque_SkAlphaType:
626 return ToColor_S32_Opaque;
627 case kPremul_SkAlphaType:
628 return ToColor_S32_Alpha;
629 case kUnpremul_SkAlphaType:
630 return ToColor_S32_Raw;
631 default:
632 return NULL;
633 }
Mike Reedb9330552014-06-16 17:31:48 -0400634 case kARGB_4444_SkColorType:
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400635 switch (src.alphaType()) {
636 case kOpaque_SkAlphaType:
637 return ToColor_S4444_Opaque;
638 case kPremul_SkAlphaType:
639 return ToColor_S4444_Alpha;
640 case kUnpremul_SkAlphaType:
641 return ToColor_S4444_Raw;
642 default:
643 return NULL;
644 }
Mike Reedb9330552014-06-16 17:31:48 -0400645 case kRGB_565_SkColorType:
Chris Craik32054b02014-05-09 13:58:56 -0700646 return ToColor_S565;
Mike Reedb9330552014-06-16 17:31:48 -0400647 case kIndex_8_SkColorType:
Chris Craik32054b02014-05-09 13:58:56 -0700648 if (src.getColorTable() == NULL) {
649 return NULL;
650 }
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400651 switch (src.alphaType()) {
652 case kOpaque_SkAlphaType:
653 return ToColor_SI8_Opaque;
654 case kPremul_SkAlphaType:
655 return ToColor_SI8_Alpha;
656 case kUnpremul_SkAlphaType:
657 return ToColor_SI8_Raw;
658 default:
659 return NULL;
660 }
Chris Craik6260b222015-07-24 15:17:29 -0700661 case kAlpha_8_SkColorType:
662 return ToColor_SA8;
Chris Craik32054b02014-05-09 13:58:56 -0700663 default:
664 break;
665 }
666 return NULL;
667}
668
669///////////////////////////////////////////////////////////////////////////////
670///////////////////////////////////////////////////////////////////////////////
671
672static int getPremulBitmapCreateFlags(bool isMutable) {
sergeyvc69853c2016-10-07 14:14:09 -0700673 int flags = android::bitmap::kBitmapCreateFlag_Premultiplied;
674 if (isMutable) flags |= android::bitmap::kBitmapCreateFlag_Mutable;
Chris Craik32054b02014-05-09 13:58:56 -0700675 return flags;
676}
677
678static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
679 jint offset, jint stride, jint width, jint height,
680 jint configHandle, jboolean isMutable) {
Mike Reed1103b322014-07-08 12:36:44 -0400681 SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700682 if (NULL != jColors) {
683 size_t n = env->GetArrayLength(jColors);
684 if (n < SkAbs32(stride) * (size_t)height) {
685 doThrowAIOOBE(env);
686 return NULL;
687 }
688 }
689
690 // ARGB_4444 is a deprecated format, convert automatically to 8888
Mike Reedb9330552014-06-16 17:31:48 -0400691 if (colorType == kARGB_4444_SkColorType) {
692 colorType = kN32_SkColorType;
Chris Craik32054b02014-05-09 13:58:56 -0700693 }
694
695 SkBitmap bitmap;
Mike Reedb9330552014-06-16 17:31:48 -0400696 bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType));
Chris Craik32054b02014-05-09 13:58:56 -0700697
sergeyvc69853c2016-10-07 14:14:09 -0700698 PixelRef* nativeBitmap = GraphicsJNI::allocateHeapPixelRef(&bitmap, NULL);
John Reckf29ed282015-04-07 07:32:03 -0700699 if (!nativeBitmap) {
Chris Craik32054b02014-05-09 13:58:56 -0700700 return NULL;
701 }
702
703 if (jColors != NULL) {
704 GraphicsJNI::SetPixels(env, jColors, offset, stride,
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400705 0, 0, width, height, bitmap);
Chris Craik32054b02014-05-09 13:58:56 -0700706 }
707
sergeyvc69853c2016-10-07 14:14:09 -0700708 return createBitmap(env, nativeBitmap,
John Reckf29ed282015-04-07 07:32:03 -0700709 getPremulBitmapCreateFlags(isMutable));
Chris Craik32054b02014-05-09 13:58:56 -0700710}
711
712static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle,
713 jint dstConfigHandle, jboolean isMutable) {
John Reckf29ed282015-04-07 07:32:03 -0700714 SkBitmap src;
715 reinterpret_cast<Bitmap*>(srcHandle)->getSkBitmap(&src);
Mike Reed1103b322014-07-08 12:36:44 -0400716 SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
sergeyv45082182016-09-29 18:25:40 -0700717 SkBitmap result;
718 HeapAllocator allocator;
Chris Craik32054b02014-05-09 13:58:56 -0700719
John Reckf29ed282015-04-07 07:32:03 -0700720 if (!src.copyTo(&result, dstCT, &allocator)) {
Chris Craik32054b02014-05-09 13:58:56 -0700721 return NULL;
722 }
sergeyvc69853c2016-10-07 14:14:09 -0700723 auto pixelRef = allocator.getStorageObjAndReset();
724 return createBitmap(env, pixelRef, getPremulBitmapCreateFlags(isMutable));
Chris Craik32054b02014-05-09 13:58:56 -0700725}
726
sergeyvc69853c2016-10-07 14:14:09 -0700727static PixelRef* Bitmap_copyAshmemImpl(JNIEnv* env, SkBitmap& src, SkColorType& dstCT) {
Riley Andrews721ae5f2015-05-11 16:08:22 -0700728 SkBitmap result;
729
730 AshmemPixelAllocator allocator(env);
Winsona5fdde92016-04-14 15:27:15 -0700731 if (!src.copyTo(&result, dstCT, &allocator)) {
Riley Andrews721ae5f2015-05-11 16:08:22 -0700732 return NULL;
733 }
sergeyvc69853c2016-10-07 14:14:09 -0700734 auto pixelRef = allocator.getStorageObjAndReset();
735 pixelRef->setImmutable();
736 return pixelRef;
Winsona5fdde92016-04-14 15:27:15 -0700737}
738
739static jobject Bitmap_copyAshmem(JNIEnv* env, jobject, jlong srcHandle) {
740 SkBitmap src;
741 reinterpret_cast<Bitmap*>(srcHandle)->getSkBitmap(&src);
742 SkColorType dstCT = src.colorType();
sergeyvc69853c2016-10-07 14:14:09 -0700743 auto pixelRef = Bitmap_copyAshmemImpl(env, src, dstCT);
744 jobject ret = createBitmap(env, pixelRef, getPremulBitmapCreateFlags(false));
Winsona5fdde92016-04-14 15:27:15 -0700745 return ret;
746}
747
748static jobject Bitmap_copyAshmemConfig(JNIEnv* env, jobject, jlong srcHandle, jint dstConfigHandle) {
749 SkBitmap src;
750 reinterpret_cast<Bitmap*>(srcHandle)->getSkBitmap(&src);
751 SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
sergeyvc69853c2016-10-07 14:14:09 -0700752 auto pixelRef = Bitmap_copyAshmemImpl(env, src, dstCT);
753 jobject ret = createBitmap(env, pixelRef, getPremulBitmapCreateFlags(false));
Riley Andrews721ae5f2015-05-11 16:08:22 -0700754 return ret;
755}
756
Richard Uhler775873a2015-12-29 12:37:39 -0800757static void Bitmap_destruct(Bitmap* bitmap) {
sergeyvc69853c2016-10-07 14:14:09 -0700758 delete bitmap;
Chris Craik32054b02014-05-09 13:58:56 -0700759}
760
Richard Uhler775873a2015-12-29 12:37:39 -0800761static jlong Bitmap_getNativeFinalizer(JNIEnv*, jobject) {
762 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Bitmap_destruct));
763}
764
Chris Craik32054b02014-05-09 13:58:56 -0700765static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700766 LocalScopedBitmap bitmap(bitmapHandle);
767 bitmap->freePixels();
Chris Craik32054b02014-05-09 13:58:56 -0700768 return JNI_TRUE;
769}
770
771static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
sergeyv45082182016-09-29 18:25:40 -0700772 jint width, jint height, jint configHandle, jboolean requestPremul) {
John Reckf29ed282015-04-07 07:32:03 -0700773 LocalScopedBitmap bitmap(bitmapHandle);
sergeyvc69853c2016-10-07 14:14:09 -0700774 bitmap->assertValid();
Mike Reed1103b322014-07-08 12:36:44 -0400775 SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
Leon Scroggins III17a8bfc2014-06-03 16:15:15 -0400776
777 // ARGB_4444 is a deprecated format, convert automatically to 8888
778 if (colorType == kARGB_4444_SkColorType) {
779 colorType = kN32_SkColorType;
780 }
sergeyv45082182016-09-29 18:25:40 -0700781 size_t requestedSize = width * height * SkColorTypeBytesPerPixel(colorType);
782 if (requestedSize > bitmap->getAllocationByteCount()) {
Chris Craik32054b02014-05-09 13:58:56 -0700783 // done in native as there's no way to get BytesPerPixel in Java
784 doThrowIAE(env, "Bitmap not large enough to support new configuration");
785 return;
786 }
Leon Scroggins III17a8bfc2014-06-03 16:15:15 -0400787 SkAlphaType alphaType;
John Reckf29ed282015-04-07 07:32:03 -0700788 if (bitmap->info().colorType() != kRGB_565_SkColorType
789 && bitmap->info().alphaType() == kOpaque_SkAlphaType) {
Leon Scroggins III17a8bfc2014-06-03 16:15:15 -0400790 // If the original bitmap was set to opaque, keep that setting, unless it
791 // was 565, which is required to be opaque.
792 alphaType = kOpaque_SkAlphaType;
793 } else {
794 // Otherwise respect the premultiplied request.
795 alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
796 }
sergeyvc69853c2016-10-07 14:14:09 -0700797 bitmap->pixelRef()->reconfigure(SkImageInfo::Make(width, height, colorType, alphaType));
Chris Craik32054b02014-05-09 13:58:56 -0700798}
799
800// These must match the int values in Bitmap.java
801enum JavaEncodeFormat {
802 kJPEG_JavaEncodeFormat = 0,
803 kPNG_JavaEncodeFormat = 1,
804 kWEBP_JavaEncodeFormat = 2
805};
806
807static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle,
808 jint format, jint quality,
809 jobject jstream, jbyteArray jstorage) {
John Reckf29ed282015-04-07 07:32:03 -0700810
811 LocalScopedBitmap bitmap(bitmapHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700812 SkImageEncoder::Type fm;
813
814 switch (format) {
815 case kJPEG_JavaEncodeFormat:
816 fm = SkImageEncoder::kJPEG_Type;
817 break;
818 case kPNG_JavaEncodeFormat:
819 fm = SkImageEncoder::kPNG_Type;
820 break;
821 case kWEBP_JavaEncodeFormat:
822 fm = SkImageEncoder::kWEBP_Type;
823 break;
824 default:
825 return JNI_FALSE;
826 }
827
John Reckf29ed282015-04-07 07:32:03 -0700828 if (!bitmap.valid()) {
829 return JNI_FALSE;
830 }
831
Chris Craik32054b02014-05-09 13:58:56 -0700832 bool success = false;
Chris Craik32054b02014-05-09 13:58:56 -0700833
John Reckf29ed282015-04-07 07:32:03 -0700834 std::unique_ptr<SkWStream> strm(CreateJavaOutputStreamAdaptor(env, jstream, jstorage));
835 if (!strm.get()) {
836 return JNI_FALSE;
837 }
Chris Craik32054b02014-05-09 13:58:56 -0700838
John Reckf29ed282015-04-07 07:32:03 -0700839 std::unique_ptr<SkImageEncoder> encoder(SkImageEncoder::Create(fm));
840 if (encoder.get()) {
841 SkBitmap skbitmap;
842 bitmap->getSkBitmap(&skbitmap);
843 success = encoder->encodeStream(strm.get(), skbitmap, quality);
Chris Craik32054b02014-05-09 13:58:56 -0700844 }
845 return success ? JNI_TRUE : JNI_FALSE;
846}
847
848static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) {
John Reckf29ed282015-04-07 07:32:03 -0700849 LocalScopedBitmap bitmap(bitmapHandle);
850 SkBitmap skBitmap;
851 bitmap->getSkBitmap(&skBitmap);
852 skBitmap.eraseColor(color);
Chris Craik32054b02014-05-09 13:58:56 -0700853}
854
855static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700856 LocalScopedBitmap bitmap(bitmapHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700857 return static_cast<jint>(bitmap->rowBytes());
858}
859
860static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700861 LocalScopedBitmap bitmap(bitmapHandle);
862 return GraphicsJNI::colorTypeToLegacyBitmapConfig(bitmap->info().colorType());
Chris Craik32054b02014-05-09 13:58:56 -0700863}
864
865static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700866 LocalScopedBitmap bitmap(bitmapHandle);
sergeyvc69853c2016-10-07 14:14:09 -0700867 return static_cast<jint>(bitmap->getGenerationID());
Chris Craik32054b02014-05-09 13:58:56 -0700868}
869
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400870static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700871 LocalScopedBitmap bitmap(bitmapHandle);
872 if (bitmap->info().alphaType() == kPremul_SkAlphaType) {
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400873 return JNI_TRUE;
874 }
875 return JNI_FALSE;
876}
877
Chris Craik32054b02014-05-09 13:58:56 -0700878static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700879 LocalScopedBitmap bitmap(bitmapHandle);
880 return !bitmap->info().isOpaque() ? JNI_TRUE : JNI_FALSE;
Chris Craik32054b02014-05-09 13:58:56 -0700881}
882
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400883static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle,
884 jboolean hasAlpha, jboolean requestPremul) {
John Reckf29ed282015-04-07 07:32:03 -0700885 LocalScopedBitmap bitmap(bitmapHandle);
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400886 if (hasAlpha) {
John Reck0781a2f2015-05-27 16:29:17 -0700887 bitmap->setAlphaType(
John Reckf29ed282015-04-07 07:32:03 -0700888 requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
Chris Craik32054b02014-05-09 13:58:56 -0700889 } else {
John Reck0781a2f2015-05-27 16:29:17 -0700890 bitmap->setAlphaType(kOpaque_SkAlphaType);
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400891 }
892}
893
894static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
895 jboolean isPremul) {
John Reckf29ed282015-04-07 07:32:03 -0700896 LocalScopedBitmap bitmap(bitmapHandle);
897 if (!bitmap->info().isOpaque()) {
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400898 if (isPremul) {
John Reck0781a2f2015-05-27 16:29:17 -0700899 bitmap->setAlphaType(kPremul_SkAlphaType);
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400900 } else {
John Reck0781a2f2015-05-27 16:29:17 -0700901 bitmap->setAlphaType(kUnpremul_SkAlphaType);
Leon Scroggins III57ee6202014-06-04 18:51:07 -0400902 }
Chris Craik32054b02014-05-09 13:58:56 -0700903 }
904}
905
906static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -0700907 LocalScopedBitmap bitmap(bitmapHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700908 return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE;
909}
910
911static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle,
912 jboolean hasMipMap) {
John Reckf29ed282015-04-07 07:32:03 -0700913 LocalScopedBitmap bitmap(bitmapHandle);
Chris Craik32054b02014-05-09 13:58:56 -0700914 bitmap->setHasHardwareMipMap(hasMipMap);
915}
916
917///////////////////////////////////////////////////////////////////////////////
918
919static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
920 if (parcel == NULL) {
921 SkDebugf("-------- unparcel parcel is NULL\n");
922 return NULL;
923 }
924
925 android::Parcel* p = android::parcelForJavaObject(env, parcel);
926
Mike Reedb9330552014-06-16 17:31:48 -0400927 const bool isMutable = p->readInt32() != 0;
928 const SkColorType colorType = (SkColorType)p->readInt32();
929 const SkAlphaType alphaType = (SkAlphaType)p->readInt32();
930 const int width = p->readInt32();
931 const int height = p->readInt32();
932 const int rowBytes = p->readInt32();
933 const int density = p->readInt32();
Chris Craik32054b02014-05-09 13:58:56 -0700934
Mike Reedb9330552014-06-16 17:31:48 -0400935 if (kN32_SkColorType != colorType &&
936 kRGB_565_SkColorType != colorType &&
937 kARGB_4444_SkColorType != colorType &&
938 kIndex_8_SkColorType != colorType &&
939 kAlpha_8_SkColorType != colorType) {
940 SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType);
Chris Craik32054b02014-05-09 13:58:56 -0700941 return NULL;
942 }
943
Leon Scroggins IIIec419e02015-03-11 13:12:06 -0400944 std::unique_ptr<SkBitmap> bitmap(new SkBitmap);
Chris Craik32054b02014-05-09 13:58:56 -0700945
Leon Scroggins IIIec419e02015-03-11 13:12:06 -0400946 if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType), rowBytes)) {
947 return NULL;
948 }
Chris Craik32054b02014-05-09 13:58:56 -0700949
950 SkColorTable* ctable = NULL;
Mike Reedb9330552014-06-16 17:31:48 -0400951 if (colorType == kIndex_8_SkColorType) {
Chris Craik32054b02014-05-09 13:58:56 -0700952 int count = p->readInt32();
Leon Scroggins IIIec419e02015-03-11 13:12:06 -0400953 if (count < 0 || count > 256) {
954 // The data is corrupt, since SkColorTable enforces a value between 0 and 256,
955 // inclusive.
956 return NULL;
957 }
Chris Craik32054b02014-05-09 13:58:56 -0700958 if (count > 0) {
959 size_t size = count * sizeof(SkPMColor);
960 const SkPMColor* src = (const SkPMColor*)p->readInplace(size);
Leon Scroggins IIIec419e02015-03-11 13:12:06 -0400961 if (src == NULL) {
962 return NULL;
963 }
Chris Craik32054b02014-05-09 13:58:56 -0700964 ctable = new SkColorTable(src, count);
965 }
966 }
967
Jeff Browna316c5d2015-06-05 15:14:06 -0700968 // Read the bitmap blob.
969 size_t size = bitmap->getSize();
970 android::Parcel::ReadableBlob blob;
971 android::status_t status = p->readBlob(size, &blob);
972 if (status) {
Chris Craik32054b02014-05-09 13:58:56 -0700973 SkSafeUnref(ctable);
Jeff Browna316c5d2015-06-05 15:14:06 -0700974 doThrowRE(env, "Could not read bitmap blob.");
Chris Craik32054b02014-05-09 13:58:56 -0700975 return NULL;
976 }
977
Jeff Browna316c5d2015-06-05 15:14:06 -0700978 // Map the bitmap in place from the ashmem region if possible otherwise copy.
sergeyvc69853c2016-10-07 14:14:09 -0700979 PixelRef* nativeBitmap;
Riley Andrews8cee7c12015-11-01 23:36:04 -0800980 if (blob.fd() >= 0 && (blob.isMutable() || !isMutable) && (size >= ASHMEM_BITMAP_MIN_SIZE)) {
Jeff Browna316c5d2015-06-05 15:14:06 -0700981#if DEBUG_PARCEL
982 ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob "
983 "(fds %s)",
984 isMutable ? "mutable" : "immutable",
985 blob.isMutable() ? "mutable" : "immutable",
986 p->allowFds() ? "allowed" : "forbidden");
987#endif
988 // Dup the file descriptor so we can keep a reference to it after the Parcel
989 // is disposed.
990 int dupFd = dup(blob.fd());
991 if (dupFd < 0) {
Erik Wolsheimer211abad2015-11-13 11:54:47 -0800992 ALOGE("Error allocating dup fd. Error:%d", errno);
Jeff Browna316c5d2015-06-05 15:14:06 -0700993 blob.release();
994 SkSafeUnref(ctable);
995 doThrowRE(env, "Could not allocate dup blob fd.");
996 return NULL;
997 }
998
999 // Map the pixels in place and take ownership of the ashmem region.
1000 nativeBitmap = GraphicsJNI::mapAshmemPixelRef(env, bitmap.get(),
John Reck003bdee2016-09-12 10:43:35 -07001001 ctable, dupFd, const_cast<void*>(blob.data()), size, !isMutable);
Jeff Browna316c5d2015-06-05 15:14:06 -07001002 SkSafeUnref(ctable);
1003 if (!nativeBitmap) {
1004 close(dupFd);
1005 blob.release();
1006 doThrowRE(env, "Could not allocate ashmem pixel ref.");
1007 return NULL;
1008 }
1009
1010 // Clear the blob handle, don't release it.
1011 blob.clear();
1012 } else {
1013#if DEBUG_PARCEL
1014 if (blob.fd() >= 0) {
1015 ALOGD("Bitmap.createFromParcel: copied contents of mutable bitmap "
1016 "from immutable blob (fds %s)",
1017 p->allowFds() ? "allowed" : "forbidden");
1018 } else {
1019 ALOGD("Bitmap.createFromParcel: copied contents from %s blob "
1020 "(fds %s)",
1021 blob.isMutable() ? "mutable" : "immutable",
1022 p->allowFds() ? "allowed" : "forbidden");
1023 }
1024#endif
1025
1026 // Copy the pixels into a new buffer.
sergeyv45082182016-09-29 18:25:40 -07001027 nativeBitmap = GraphicsJNI::allocateHeapPixelRef(bitmap.get(), ctable);
Jeff Browna316c5d2015-06-05 15:14:06 -07001028 SkSafeUnref(ctable);
1029 if (!nativeBitmap) {
1030 blob.release();
1031 doThrowRE(env, "Could not allocate java pixel ref.");
1032 return NULL;
1033 }
1034 bitmap->lockPixels();
1035 memcpy(bitmap->getPixels(), blob.data(), size);
1036 bitmap->unlockPixels();
1037
1038 // Release the blob handle.
1039 blob.release();
Chris Craik32054b02014-05-09 13:58:56 -07001040 }
Chris Craik32054b02014-05-09 13:58:56 -07001041
sergeyvc69853c2016-10-07 14:14:09 -07001042 return createBitmap(env, nativeBitmap,
Leon Scroggins IIIec419e02015-03-11 13:12:06 -04001043 getPremulBitmapCreateFlags(isMutable), NULL, NULL, density);
Chris Craik32054b02014-05-09 13:58:56 -07001044}
1045
1046static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
1047 jlong bitmapHandle,
1048 jboolean isMutable, jint density,
1049 jobject parcel) {
Chris Craik32054b02014-05-09 13:58:56 -07001050 if (parcel == NULL) {
1051 SkDebugf("------- writeToParcel null parcel\n");
1052 return JNI_FALSE;
1053 }
1054
1055 android::Parcel* p = android::parcelForJavaObject(env, parcel);
John Reckf29ed282015-04-07 07:32:03 -07001056 SkBitmap bitmap;
Riley Andrews39d7f302014-11-13 17:43:25 -08001057
sergeyvc69853c2016-10-07 14:14:09 -07001058 auto androidBitmap = reinterpret_cast<Bitmap*>(bitmapHandle);
Riley Andrews39d7f302014-11-13 17:43:25 -08001059 androidBitmap->getSkBitmap(&bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001060
1061 p->writeInt32(isMutable);
John Reckf29ed282015-04-07 07:32:03 -07001062 p->writeInt32(bitmap.colorType());
1063 p->writeInt32(bitmap.alphaType());
1064 p->writeInt32(bitmap.width());
1065 p->writeInt32(bitmap.height());
1066 p->writeInt32(bitmap.rowBytes());
Chris Craik32054b02014-05-09 13:58:56 -07001067 p->writeInt32(density);
1068
John Reckf29ed282015-04-07 07:32:03 -07001069 if (bitmap.colorType() == kIndex_8_SkColorType) {
Leon Scroggins III66ce1c32016-02-02 11:11:55 -05001070 // The bitmap needs to be locked to access its color table.
1071 SkAutoLockPixels alp(bitmap);
John Reckf29ed282015-04-07 07:32:03 -07001072 SkColorTable* ctable = bitmap.getColorTable();
Chris Craik32054b02014-05-09 13:58:56 -07001073 if (ctable != NULL) {
1074 int count = ctable->count();
1075 p->writeInt32(count);
1076 memcpy(p->writeInplace(count * sizeof(SkPMColor)),
Mike Reed71487eb2014-11-19 16:13:20 -05001077 ctable->readColors(), count * sizeof(SkPMColor));
Chris Craik32054b02014-05-09 13:58:56 -07001078 } else {
1079 p->writeInt32(0); // indicate no ctable
1080 }
1081 }
1082
Jeff Browna316c5d2015-06-05 15:14:06 -07001083 // Transfer the underlying ashmem region if we have one and it's immutable.
1084 android::status_t status;
sergeyvc69853c2016-10-07 14:14:09 -07001085 int fd = androidBitmap->pixelRef()->getAshmemFd();
Jeff Browna316c5d2015-06-05 15:14:06 -07001086 if (fd >= 0 && !isMutable && p->allowFds()) {
1087#if DEBUG_PARCEL
1088 ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as "
1089 "immutable blob (fds %s)",
1090 p->allowFds() ? "allowed" : "forbidden");
1091#endif
1092
1093 status = p->writeDupImmutableBlobFileDescriptor(fd);
1094 if (status) {
1095 doThrowRE(env, "Could not write bitmap blob file descriptor.");
Riley Andrews39d7f302014-11-13 17:43:25 -08001096 return JNI_FALSE;
1097 }
Jeff Browna316c5d2015-06-05 15:14:06 -07001098 return JNI_TRUE;
Riley Andrews39d7f302014-11-13 17:43:25 -08001099 }
Jeff Browna316c5d2015-06-05 15:14:06 -07001100
1101 // Copy the bitmap to a new blob.
1102 bool mutableCopy = isMutable;
1103#if DEBUG_PARCEL
1104 ALOGD("Bitmap.writeToParcel: copying %s bitmap into new %s blob (fds %s)",
1105 isMutable ? "mutable" : "immutable",
1106 mutableCopy ? "mutable" : "immutable",
1107 p->allowFds() ? "allowed" : "forbidden");
1108#endif
1109
1110 size_t size = bitmap.getSize();
1111 android::Parcel::WritableBlob blob;
1112 status = p->writeBlob(size, mutableCopy, &blob);
1113 if (status) {
1114 doThrowRE(env, "Could not copy bitmap to parcel blob.");
1115 return JNI_FALSE;
1116 }
1117
1118 bitmap.lockPixels();
1119 const void* pSrc = bitmap.getPixels();
1120 if (pSrc == NULL) {
1121 memset(blob.data(), 0, size);
1122 } else {
1123 memcpy(blob.data(), pSrc, size);
1124 }
1125 bitmap.unlockPixels();
1126
1127 blob.release();
Chris Craik32054b02014-05-09 13:58:56 -07001128 return JNI_TRUE;
1129}
1130
1131static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
1132 jlong srcHandle, jlong paintHandle,
1133 jintArray offsetXY) {
John Reckf29ed282015-04-07 07:32:03 -07001134 SkBitmap src;
1135 reinterpret_cast<Bitmap*>(srcHandle)->getSkBitmap(&src);
Behdad Esfahbod6ba30b82014-07-15 16:22:32 -04001136 const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle);
Chris Craik32054b02014-05-09 13:58:56 -07001137 SkIPoint offset;
John Reckf29ed282015-04-07 07:32:03 -07001138 SkBitmap dst;
sergeyv45082182016-09-29 18:25:40 -07001139 HeapAllocator allocator;
Chris Craik32054b02014-05-09 13:58:56 -07001140
John Reckf29ed282015-04-07 07:32:03 -07001141 src.extractAlpha(&dst, paint, &allocator, &offset);
Chris Craik32054b02014-05-09 13:58:56 -07001142 // If Skia can't allocate pixels for destination bitmap, it resets
1143 // it, that is set its pixels buffer to NULL, and zero width and height.
John Reckf29ed282015-04-07 07:32:03 -07001144 if (dst.getPixels() == NULL && src.getPixels() != NULL) {
Chris Craik32054b02014-05-09 13:58:56 -07001145 doThrowOOME(env, "failed to allocate pixels for alpha");
1146 return NULL;
1147 }
1148 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
1149 int* array = env->GetIntArrayElements(offsetXY, NULL);
1150 array[0] = offset.fX;
1151 array[1] = offset.fY;
1152 env->ReleaseIntArrayElements(offsetXY, array, 0);
1153 }
1154
sergeyvc69853c2016-10-07 14:14:09 -07001155 return createBitmap(env, allocator.getStorageObjAndReset(),
John Reckf29ed282015-04-07 07:32:03 -07001156 getPremulBitmapCreateFlags(true));
Chris Craik32054b02014-05-09 13:58:56 -07001157}
1158
1159///////////////////////////////////////////////////////////////////////////////
1160
1161static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
Leon Scroggins III57ee6202014-06-04 18:51:07 -04001162 jint x, jint y) {
John Reckf29ed282015-04-07 07:32:03 -07001163 SkBitmap bitmap;
1164 reinterpret_cast<Bitmap*>(bitmapHandle)->getSkBitmap(&bitmap);
1165 SkAutoLockPixels alp(bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001166
John Reckf29ed282015-04-07 07:32:03 -07001167 ToColorProc proc = ChooseToColorProc(bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001168 if (NULL == proc) {
1169 return 0;
1170 }
John Reckf29ed282015-04-07 07:32:03 -07001171 const void* src = bitmap.getAddr(x, y);
Chris Craik32054b02014-05-09 13:58:56 -07001172 if (NULL == src) {
1173 return 0;
1174 }
1175
1176 SkColor dst[1];
John Reckf29ed282015-04-07 07:32:03 -07001177 proc(dst, src, 1, bitmap.getColorTable());
Chris Craik32054b02014-05-09 13:58:56 -07001178 return static_cast<jint>(dst[0]);
1179}
1180
1181static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,
1182 jintArray pixelArray, jint offset, jint stride,
Leon Scroggins III57ee6202014-06-04 18:51:07 -04001183 jint x, jint y, jint width, jint height) {
John Reckf29ed282015-04-07 07:32:03 -07001184 SkBitmap bitmap;
1185 reinterpret_cast<Bitmap*>(bitmapHandle)->getSkBitmap(&bitmap);
1186 SkAutoLockPixels alp(bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001187
John Reckf29ed282015-04-07 07:32:03 -07001188 ToColorProc proc = ChooseToColorProc(bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001189 if (NULL == proc) {
1190 return;
1191 }
John Reckf29ed282015-04-07 07:32:03 -07001192 const void* src = bitmap.getAddr(x, y);
Chris Craik32054b02014-05-09 13:58:56 -07001193 if (NULL == src) {
1194 return;
1195 }
1196
John Reckf29ed282015-04-07 07:32:03 -07001197 SkColorTable* ctable = bitmap.getColorTable();
Chris Craik32054b02014-05-09 13:58:56 -07001198 jint* dst = env->GetIntArrayElements(pixelArray, NULL);
1199 SkColor* d = (SkColor*)dst + offset;
1200 while (--height >= 0) {
1201 proc(d, src, width, ctable);
1202 d += stride;
John Reckf29ed282015-04-07 07:32:03 -07001203 src = (void*)((const char*)src + bitmap.rowBytes());
Chris Craik32054b02014-05-09 13:58:56 -07001204 }
1205 env->ReleaseIntArrayElements(pixelArray, dst, 0);
1206}
1207
1208///////////////////////////////////////////////////////////////////////////////
1209
1210static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle,
Leon Scroggins III57ee6202014-06-04 18:51:07 -04001211 jint x, jint y, jint colorHandle) {
John Reckf29ed282015-04-07 07:32:03 -07001212 SkBitmap bitmap;
1213 reinterpret_cast<Bitmap*>(bitmapHandle)->getSkBitmap(&bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001214 SkColor color = static_cast<SkColor>(colorHandle);
John Reckf29ed282015-04-07 07:32:03 -07001215 SkAutoLockPixels alp(bitmap);
1216 if (NULL == bitmap.getPixels()) {
Chris Craik32054b02014-05-09 13:58:56 -07001217 return;
1218 }
1219
John Reckf29ed282015-04-07 07:32:03 -07001220 FromColorProc proc = ChooseFromColorProc(bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001221 if (NULL == proc) {
1222 return;
1223 }
1224
John Reckf29ed282015-04-07 07:32:03 -07001225 proc(bitmap.getAddr(x, y), &color, 1, x, y);
1226 bitmap.notifyPixelsChanged();
Chris Craik32054b02014-05-09 13:58:56 -07001227}
1228
1229static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,
1230 jintArray pixelArray, jint offset, jint stride,
Leon Scroggins III57ee6202014-06-04 18:51:07 -04001231 jint x, jint y, jint width, jint height) {
John Reckf29ed282015-04-07 07:32:03 -07001232 SkBitmap bitmap;
1233 reinterpret_cast<Bitmap*>(bitmapHandle)->getSkBitmap(&bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001234 GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
John Reckf29ed282015-04-07 07:32:03 -07001235 x, y, width, height, bitmap);
Chris Craik32054b02014-05-09 13:58:56 -07001236}
1237
1238static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
1239 jlong bitmapHandle, jobject jbuffer) {
John Reckf29ed282015-04-07 07:32:03 -07001240 SkBitmap bitmap;
1241 reinterpret_cast<Bitmap*>(bitmapHandle)->getSkBitmap(&bitmap);
1242 SkAutoLockPixels alp(bitmap);
1243 const void* src = bitmap.getPixels();
Chris Craik32054b02014-05-09 13:58:56 -07001244
1245 if (NULL != src) {
1246 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
1247
1248 // the java side has already checked that buffer is large enough
John Reckf29ed282015-04-07 07:32:03 -07001249 memcpy(abp.pointer(), src, bitmap.getSize());
Chris Craik32054b02014-05-09 13:58:56 -07001250 }
1251}
1252
1253static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,
1254 jlong bitmapHandle, jobject jbuffer) {
John Reckf29ed282015-04-07 07:32:03 -07001255 SkBitmap bitmap;
1256 reinterpret_cast<Bitmap*>(bitmapHandle)->getSkBitmap(&bitmap);
1257 SkAutoLockPixels alp(bitmap);
1258 void* dst = bitmap.getPixels();
Chris Craik32054b02014-05-09 13:58:56 -07001259
1260 if (NULL != dst) {
1261 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);
1262 // the java side has already checked that buffer is large enough
John Reckf29ed282015-04-07 07:32:03 -07001263 memcpy(dst, abp.pointer(), bitmap.getSize());
1264 bitmap.notifyPixelsChanged();
Chris Craik32054b02014-05-09 13:58:56 -07001265 }
1266}
1267
1268static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle,
1269 jlong bm1Handle) {
John Reckf29ed282015-04-07 07:32:03 -07001270 SkBitmap bm0;
1271 SkBitmap bm1;
1272 reinterpret_cast<Bitmap*>(bm0Handle)->getSkBitmap(&bm0);
1273 reinterpret_cast<Bitmap*>(bm1Handle)->getSkBitmap(&bm1);
1274 if (bm0.width() != bm1.width() ||
1275 bm0.height() != bm1.height() ||
1276 bm0.colorType() != bm1.colorType()) {
Chris Craik32054b02014-05-09 13:58:56 -07001277 return JNI_FALSE;
1278 }
1279
John Reckf29ed282015-04-07 07:32:03 -07001280 SkAutoLockPixels alp0(bm0);
1281 SkAutoLockPixels alp1(bm1);
Chris Craik32054b02014-05-09 13:58:56 -07001282
1283 // if we can't load the pixels, return false
John Reckf29ed282015-04-07 07:32:03 -07001284 if (NULL == bm0.getPixels() || NULL == bm1.getPixels()) {
Chris Craik32054b02014-05-09 13:58:56 -07001285 return JNI_FALSE;
1286 }
1287
John Reckf29ed282015-04-07 07:32:03 -07001288 if (bm0.colorType() == kIndex_8_SkColorType) {
1289 SkColorTable* ct0 = bm0.getColorTable();
1290 SkColorTable* ct1 = bm1.getColorTable();
Chris Craik32054b02014-05-09 13:58:56 -07001291 if (NULL == ct0 || NULL == ct1) {
1292 return JNI_FALSE;
1293 }
1294 if (ct0->count() != ct1->count()) {
1295 return JNI_FALSE;
1296 }
1297
Chris Craik32054b02014-05-09 13:58:56 -07001298 const size_t size = ct0->count() * sizeof(SkPMColor);
Mike Reed71487eb2014-11-19 16:13:20 -05001299 if (memcmp(ct0->readColors(), ct1->readColors(), size) != 0) {
Chris Craik32054b02014-05-09 13:58:56 -07001300 return JNI_FALSE;
1301 }
1302 }
1303
1304 // now compare each scanline. We can't do the entire buffer at once,
1305 // since we don't care about the pixel values that might extend beyond
1306 // the width (since the scanline might be larger than the logical width)
John Reckf29ed282015-04-07 07:32:03 -07001307 const int h = bm0.height();
1308 const size_t size = bm0.width() * bm0.bytesPerPixel();
Chris Craik32054b02014-05-09 13:58:56 -07001309 for (int y = 0; y < h; y++) {
henry.uh_chen53001ca2014-07-03 20:40:22 +08001310 // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config
1311 // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0
1312 // and bm1 both have pixel data() (have passed NULL == getPixels() check),
1313 // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE
1314 // to warn user those 2 unrecognized config bitmaps may be different.
John Reckf29ed282015-04-07 07:32:03 -07001315 void *bm0Addr = bm0.getAddr(0, y);
1316 void *bm1Addr = bm1.getAddr(0, y);
henry.uh_chen53001ca2014-07-03 20:40:22 +08001317
1318 if(bm0Addr == NULL || bm1Addr == NULL) {
1319 return JNI_FALSE;
1320 }
1321
1322 if (memcmp(bm0Addr, bm1Addr, size) != 0) {
Chris Craik32054b02014-05-09 13:58:56 -07001323 return JNI_FALSE;
1324 }
1325 }
1326 return JNI_TRUE;
1327}
1328
John Reckc6e2e8f2015-04-15 13:24:47 -07001329static jlong Bitmap_refPixelRef(JNIEnv* env, jobject, jlong bitmapHandle) {
John Reckf29ed282015-04-07 07:32:03 -07001330 LocalScopedBitmap bitmap(bitmapHandle);
sergeyvc69853c2016-10-07 14:14:09 -07001331 SkPixelRef* pixelRef = bitmap->pixelRef();
John Reckc6e2e8f2015-04-15 13:24:47 -07001332 SkSafeRef(pixelRef);
1333 return reinterpret_cast<jlong>(pixelRef);
1334}
1335
John Reck43871902016-08-01 14:39:24 -07001336static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapPtr) {
1337 LocalScopedBitmap bitmapHandle(bitmapPtr);
1338 if (!bitmapHandle.valid()) return;
1339 SkBitmap bitmap;
1340 bitmapHandle->getSkBitmap(&bitmap);
1341 android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmap);
1342}
1343
sergeyv45082182016-09-29 18:25:40 -07001344static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr) {
1345 LocalScopedBitmap bitmapHandle(bitmapPtr);
1346 return static_cast<jint>(bitmapHandle->getAllocationByteCount());
1347}
1348
Chris Craik32054b02014-05-09 13:58:56 -07001349///////////////////////////////////////////////////////////////////////////////
sergeyvc69853c2016-10-07 14:14:09 -07001350static jclass make_globalref(JNIEnv* env, const char classname[])
1351{
1352 jclass c = env->FindClass(classname);
1353 SkASSERT(c);
1354 return (jclass) env->NewGlobalRef(c);
1355}
1356
1357static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
1358 const char fieldname[], const char type[])
1359{
1360 jfieldID id = env->GetFieldID(clazz, fieldname, type);
1361 SkASSERT(id);
1362 return id;
1363}
Chris Craik32054b02014-05-09 13:58:56 -07001364
Daniel Micay76f6a862015-09-19 17:31:01 -04001365static const JNINativeMethod gBitmapMethods[] = {
Chris Craik32054b02014-05-09 13:58:56 -07001366 { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;",
1367 (void*)Bitmap_creator },
1368 { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;",
1369 (void*)Bitmap_copy },
Riley Andrews721ae5f2015-05-11 16:08:22 -07001370 { "nativeCopyAshmem", "(J)Landroid/graphics/Bitmap;",
1371 (void*)Bitmap_copyAshmem },
Winsona5fdde92016-04-14 15:27:15 -07001372 { "nativeCopyAshmemConfig", "(JI)Landroid/graphics/Bitmap;",
1373 (void*)Bitmap_copyAshmemConfig },
Richard Uhler775873a2015-12-29 12:37:39 -08001374 { "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer },
Chris Craik32054b02014-05-09 13:58:56 -07001375 { "nativeRecycle", "(J)Z", (void*)Bitmap_recycle },
sergeyv45082182016-09-29 18:25:40 -07001376 { "nativeReconfigure", "(JIIIZ)V", (void*)Bitmap_reconfigure },
Chris Craik32054b02014-05-09 13:58:56 -07001377 { "nativeCompress", "(JIILjava/io/OutputStream;[B)Z",
1378 (void*)Bitmap_compress },
1379 { "nativeErase", "(JI)V", (void*)Bitmap_erase },
1380 { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes },
1381 { "nativeConfig", "(J)I", (void*)Bitmap_config },
1382 { "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha },
Leon Scroggins III57ee6202014-06-04 18:51:07 -04001383 { "nativeIsPremultiplied", "(J)Z", (void*)Bitmap_isPremultiplied},
1384 { "nativeSetHasAlpha", "(JZZ)V", (void*)Bitmap_setHasAlpha},
1385 { "nativeSetPremultiplied", "(JZ)V", (void*)Bitmap_setPremultiplied},
Chris Craik32054b02014-05-09 13:58:56 -07001386 { "nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap },
1387 { "nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap },
1388 { "nativeCreateFromParcel",
1389 "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
1390 (void*)Bitmap_createFromParcel },
1391 { "nativeWriteToParcel", "(JZILandroid/os/Parcel;)Z",
1392 (void*)Bitmap_writeToParcel },
1393 { "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;",
1394 (void*)Bitmap_extractAlpha },
1395 { "nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId },
Leon Scroggins III57ee6202014-06-04 18:51:07 -04001396 { "nativeGetPixel", "(JII)I", (void*)Bitmap_getPixel },
1397 { "nativeGetPixels", "(J[IIIIIII)V", (void*)Bitmap_getPixels },
1398 { "nativeSetPixel", "(JIII)V", (void*)Bitmap_setPixel },
1399 { "nativeSetPixels", "(J[IIIIIII)V", (void*)Bitmap_setPixels },
Chris Craik32054b02014-05-09 13:58:56 -07001400 { "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V",
1401 (void*)Bitmap_copyPixelsToBuffer },
1402 { "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V",
1403 (void*)Bitmap_copyPixelsFromBuffer },
1404 { "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs },
John Reckc6e2e8f2015-04-15 13:24:47 -07001405 { "nativeRefPixelRef", "(J)J", (void*)Bitmap_refPixelRef },
John Reck43871902016-08-01 14:39:24 -07001406 { "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw },
sergeyv45082182016-09-29 18:25:40 -07001407 { "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount },
Chris Craik32054b02014-05-09 13:58:56 -07001408};
1409
Chris Craik32054b02014-05-09 13:58:56 -07001410int register_android_graphics_Bitmap(JNIEnv* env)
1411{
sergeyvc69853c2016-10-07 14:14:09 -07001412 gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
1413 gBitmap_nativePtr = getFieldIDCheck(env, gBitmap_class, "mNativePtr", "J");
1414 gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
1415 gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "(IIZ)V");
1416 gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I");
Andreas Gampeed6b9df2014-11-20 22:02:20 -08001417 return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods,
1418 NELEM(gBitmapMethods));
sergeyvc69853c2016-10-07 14:14:09 -07001419}