• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "SkBitmap.h"
2 #include "SkPixelRef.h"
3 #include "SkImageEncoder.h"
4 #include "SkColorPriv.h"
5 #include "GraphicsJNI.h"
6 #include "SkDither.h"
7 #include "SkUnPreMultiply.h"
8 #include "SkStream.h"
9 
10 #include <binder/Parcel.h>
11 #include "android_os_Parcel.h"
12 #include "android_util_Binder.h"
13 #include "android_nio_utils.h"
14 #include "CreateJavaOutputStreamAdaptor.h"
15 
16 #include <jni.h>
17 
18 #include <Caches.h>
19 
20 #if 0
21     #define TRACE_BITMAP(code)  code
22 #else
23     #define TRACE_BITMAP(code)
24 #endif
25 
26 ///////////////////////////////////////////////////////////////////////////////
27 // Conversions to/from SkColor, for get/setPixels, and the create method, which
28 // is basically like setPixels
29 
30 typedef void (*FromColorProc)(void* dst, const SkColor src[], int width,
31                               int x, int y);
32 
FromColor_D32(void * dst,const SkColor src[],int width,int,int)33 static void FromColor_D32(void* dst, const SkColor src[], int width,
34                           int, int) {
35     SkPMColor* d = (SkPMColor*)dst;
36 
37     for (int i = 0; i < width; i++) {
38         *d++ = SkPreMultiplyColor(*src++);
39     }
40 }
41 
FromColor_D32_Raw(void * dst,const SkColor src[],int width,int,int)42 static void FromColor_D32_Raw(void* dst, const SkColor src[], int width,
43                           int, int) {
44     // SkColor's ordering may be different from SkPMColor
45     if (SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER) {
46         memcpy(dst, src, width * sizeof(SkColor));
47         return;
48     }
49 
50     // order isn't same, repack each pixel manually
51     SkPMColor* d = (SkPMColor*)dst;
52     for (int i = 0; i < width; i++) {
53         SkColor c = *src++;
54         *d++ = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
55                                    SkColorGetG(c), SkColorGetB(c));
56     }
57 }
58 
FromColor_D565(void * dst,const SkColor src[],int width,int x,int y)59 static void FromColor_D565(void* dst, const SkColor src[], int width,
60                            int x, int y) {
61     uint16_t* d = (uint16_t*)dst;
62 
63     DITHER_565_SCAN(y);
64     for (int stop = x + width; x < stop; x++) {
65         SkColor c = *src++;
66         *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c),
67                                 DITHER_VALUE(x));
68     }
69 }
70 
FromColor_D4444(void * dst,const SkColor src[],int width,int x,int y)71 static void FromColor_D4444(void* dst, const SkColor src[], int width,
72                             int x, int y) {
73     SkPMColor16* d = (SkPMColor16*)dst;
74 
75     DITHER_4444_SCAN(y);
76     for (int stop = x + width; x < stop; x++) {
77         SkPMColor pmc = SkPreMultiplyColor(*src++);
78         *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
79 //        *d++ = SkPixel32ToPixel4444(pmc);
80     }
81 }
82 
FromColor_D4444_Raw(void * dst,const SkColor src[],int width,int x,int y)83 static void FromColor_D4444_Raw(void* dst, const SkColor src[], int width,
84                             int x, int y) {
85     SkPMColor16* d = (SkPMColor16*)dst;
86 
87     DITHER_4444_SCAN(y);
88     for (int stop = x + width; x < stop; x++) {
89         SkColor c = *src++;
90 
91         // SkPMColor is used because the ordering is ARGB32, even though the target actually premultiplied
92         SkPMColor pmc = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
93                                             SkColorGetG(c), SkColorGetB(c));
94         *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
95 //        *d++ = SkPixel32ToPixel4444(pmc);
96     }
97 }
98 
99 // can return NULL
ChooseFromColorProc(SkBitmap::Config config,bool isPremultiplied)100 static FromColorProc ChooseFromColorProc(SkBitmap::Config config, bool isPremultiplied) {
101     switch (config) {
102         case SkBitmap::kARGB_8888_Config:
103             return isPremultiplied ? FromColor_D32 : FromColor_D32_Raw;
104         case SkBitmap::kARGB_4444_Config:
105             return isPremultiplied ? FromColor_D4444 : FromColor_D4444_Raw;
106         case SkBitmap::kRGB_565_Config:
107             return FromColor_D565;
108         default:
109             break;
110     }
111     return NULL;
112 }
113 
SetPixels(JNIEnv * env,jintArray srcColors,int srcOffset,int srcStride,int x,int y,int width,int height,const SkBitmap & dstBitmap,bool isPremultiplied)114 bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride,
115         int x, int y, int width, int height,
116         const SkBitmap& dstBitmap, bool isPremultiplied) {
117     SkAutoLockPixels alp(dstBitmap);
118     void* dst = dstBitmap.getPixels();
119     FromColorProc proc = ChooseFromColorProc(dstBitmap.config(), isPremultiplied);
120 
121     if (NULL == dst || NULL == proc) {
122         return false;
123     }
124 
125     const jint* array = env->GetIntArrayElements(srcColors, NULL);
126     const SkColor* src = (const SkColor*)array + srcOffset;
127 
128     // reset to to actual choice from caller
129     dst = dstBitmap.getAddr(x, y);
130     // now copy/convert each scanline
131     for (int y = 0; y < height; y++) {
132         proc(dst, src, width, x, y);
133         src += srcStride;
134         dst = (char*)dst + dstBitmap.rowBytes();
135     }
136 
137     dstBitmap.notifyPixelsChanged();
138 
139     env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array),
140                                  JNI_ABORT);
141     return true;
142 }
143 
144 //////////////////// ToColor procs
145 
146 typedef void (*ToColorProc)(SkColor dst[], const void* src, int width,
147                             SkColorTable*);
148 
ToColor_S32_Alpha(SkColor dst[],const void * src,int width,SkColorTable *)149 static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width,
150                               SkColorTable*) {
151     SkASSERT(width > 0);
152     const SkPMColor* s = (const SkPMColor*)src;
153     do {
154         *dst++ = SkUnPreMultiply::PMColorToColor(*s++);
155     } while (--width != 0);
156 }
157 
ToColor_S32_Raw(SkColor dst[],const void * src,int width,SkColorTable *)158 static void ToColor_S32_Raw(SkColor dst[], const void* src, int width,
159                               SkColorTable*) {
160     SkASSERT(width > 0);
161     const SkPMColor* s = (const SkPMColor*)src;
162     do {
163         SkPMColor c = *s++;
164         *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
165                                 SkGetPackedG32(c), SkGetPackedB32(c));
166     } while (--width != 0);
167 }
168 
ToColor_S32_Opaque(SkColor dst[],const void * src,int width,SkColorTable *)169 static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width,
170                                SkColorTable*) {
171     SkASSERT(width > 0);
172     const SkPMColor* s = (const SkPMColor*)src;
173     do {
174         SkPMColor c = *s++;
175         *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
176                                SkGetPackedB32(c));
177     } while (--width != 0);
178 }
179 
ToColor_S4444_Alpha(SkColor dst[],const void * src,int width,SkColorTable *)180 static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width,
181                                 SkColorTable*) {
182     SkASSERT(width > 0);
183     const SkPMColor16* s = (const SkPMColor16*)src;
184     do {
185         *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++));
186     } while (--width != 0);
187 }
188 
ToColor_S4444_Raw(SkColor dst[],const void * src,int width,SkColorTable *)189 static void ToColor_S4444_Raw(SkColor dst[], const void* src, int width,
190                                 SkColorTable*) {
191     SkASSERT(width > 0);
192     const SkPMColor16* s = (const SkPMColor16*)src;
193     do {
194         SkPMColor c = SkPixel4444ToPixel32(*s++);
195         *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
196                                 SkGetPackedG32(c), SkGetPackedB32(c));
197     } while (--width != 0);
198 }
199 
ToColor_S4444_Opaque(SkColor dst[],const void * src,int width,SkColorTable *)200 static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width,
201                                  SkColorTable*) {
202     SkASSERT(width > 0);
203     const SkPMColor16* s = (const SkPMColor16*)src;
204     do {
205         SkPMColor c = SkPixel4444ToPixel32(*s++);
206         *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
207                                SkGetPackedB32(c));
208     } while (--width != 0);
209 }
210 
ToColor_S565(SkColor dst[],const void * src,int width,SkColorTable *)211 static void ToColor_S565(SkColor dst[], const void* src, int width,
212                          SkColorTable*) {
213     SkASSERT(width > 0);
214     const uint16_t* s = (const uint16_t*)src;
215     do {
216         uint16_t c = *s++;
217         *dst++ =  SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c),
218                                 SkPacked16ToB32(c));
219     } while (--width != 0);
220 }
221 
ToColor_SI8_Alpha(SkColor dst[],const void * src,int width,SkColorTable * ctable)222 static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width,
223                               SkColorTable* ctable) {
224     SkASSERT(width > 0);
225     const uint8_t* s = (const uint8_t*)src;
226     const SkPMColor* colors = ctable->lockColors();
227     do {
228         *dst++ = SkUnPreMultiply::PMColorToColor(colors[*s++]);
229     } while (--width != 0);
230     ctable->unlockColors();
231 }
232 
ToColor_SI8_Raw(SkColor dst[],const void * src,int width,SkColorTable * ctable)233 static void ToColor_SI8_Raw(SkColor dst[], const void* src, int width,
234                               SkColorTable* ctable) {
235     SkASSERT(width > 0);
236     const uint8_t* s = (const uint8_t*)src;
237     const SkPMColor* colors = ctable->lockColors();
238     do {
239         SkPMColor c = colors[*s++];
240         *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
241                                 SkGetPackedG32(c), SkGetPackedB32(c));
242     } while (--width != 0);
243     ctable->unlockColors();
244 }
245 
ToColor_SI8_Opaque(SkColor dst[],const void * src,int width,SkColorTable * ctable)246 static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width,
247                                SkColorTable* ctable) {
248     SkASSERT(width > 0);
249     const uint8_t* s = (const uint8_t*)src;
250     const SkPMColor* colors = ctable->lockColors();
251     do {
252         SkPMColor c = colors[*s++];
253         *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
254                                SkGetPackedB32(c));
255     } while (--width != 0);
256     ctable->unlockColors();
257 }
258 
259 // can return NULL
ChooseToColorProc(const SkBitmap & src,bool isPremultiplied)260 static ToColorProc ChooseToColorProc(const SkBitmap& src, bool isPremultiplied) {
261     switch (src.config()) {
262         case SkBitmap::kARGB_8888_Config:
263             if (src.isOpaque()) return ToColor_S32_Opaque;
264             return isPremultiplied ? ToColor_S32_Alpha : ToColor_S32_Raw;
265         case SkBitmap::kARGB_4444_Config:
266             if (src.isOpaque()) return ToColor_S4444_Opaque;
267             return isPremultiplied ? ToColor_S4444_Alpha : ToColor_S4444_Raw;
268         case SkBitmap::kRGB_565_Config:
269             return ToColor_S565;
270         case SkBitmap::kIndex8_Config:
271             if (src.getColorTable() == NULL) {
272                 return NULL;
273             }
274             if (src.isOpaque()) return ToColor_SI8_Opaque;
275             return isPremultiplied ? ToColor_SI8_Raw : ToColor_SI8_Alpha;
276         default:
277             break;
278     }
279     return NULL;
280 }
281 
282 ///////////////////////////////////////////////////////////////////////////////
283 ///////////////////////////////////////////////////////////////////////////////
284 
getPremulBitmapCreateFlags(bool isMutable)285 static int getPremulBitmapCreateFlags(bool isMutable) {
286     int flags = GraphicsJNI::kBitmapCreateFlag_Premultiplied;
287     if (isMutable) flags |= GraphicsJNI::kBitmapCreateFlag_Mutable;
288     return flags;
289 }
290 
Bitmap_creator(JNIEnv * env,jobject,jintArray jColors,int offset,int stride,int width,int height,SkBitmap::Config config,jboolean isMutable)291 static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
292                               int offset, int stride, int width, int height,
293                               SkBitmap::Config config, jboolean isMutable) {
294     if (NULL != jColors) {
295         size_t n = env->GetArrayLength(jColors);
296         if (n < SkAbs32(stride) * (size_t)height) {
297             doThrowAIOOBE(env);
298             return NULL;
299         }
300     }
301 
302     // ARGB_4444 is a deprecated format, convert automatically to 8888
303     if (config == SkBitmap::kARGB_4444_Config) {
304         config = SkBitmap::kARGB_8888_Config;
305     }
306 
307     SkBitmap bitmap;
308     bitmap.setConfig(config, width, height);
309 
310     jbyteArray buff = GraphicsJNI::allocateJavaPixelRef(env, &bitmap, NULL);
311     if (NULL == buff) {
312         return NULL;
313     }
314 
315     if (jColors != NULL) {
316         GraphicsJNI::SetPixels(env, jColors, offset, stride,
317                 0, 0, width, height, bitmap, true);
318     }
319 
320     return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), buff,
321             getPremulBitmapCreateFlags(isMutable), NULL, NULL);
322 }
323 
Bitmap_copy(JNIEnv * env,jobject,const SkBitmap * src,SkBitmap::Config dstConfig,jboolean isMutable)324 static jobject Bitmap_copy(JNIEnv* env, jobject, const SkBitmap* src,
325                            SkBitmap::Config dstConfig, jboolean isMutable) {
326     SkBitmap            result;
327     JavaPixelAllocator  allocator(env);
328 
329     if (!src->copyTo(&result, dstConfig, &allocator)) {
330         return NULL;
331     }
332     return GraphicsJNI::createBitmap(env, new SkBitmap(result), allocator.getStorageObj(),
333             getPremulBitmapCreateFlags(isMutable), NULL, NULL);
334 }
335 
Bitmap_destructor(JNIEnv * env,jobject,SkBitmap * bitmap)336 static void Bitmap_destructor(JNIEnv* env, jobject, SkBitmap* bitmap) {
337 #ifdef USE_OPENGL_RENDERER
338     if (android::uirenderer::Caches::hasInstance()) {
339         android::uirenderer::Caches::getInstance().resourceCache.destructor(bitmap);
340         return;
341     }
342 #endif // USE_OPENGL_RENDERER
343     delete bitmap;
344 }
345 
Bitmap_recycle(JNIEnv * env,jobject,SkBitmap * bitmap)346 static jboolean Bitmap_recycle(JNIEnv* env, jobject, SkBitmap* bitmap) {
347 #ifdef USE_OPENGL_RENDERER
348     if (android::uirenderer::Caches::hasInstance()) {
349         return android::uirenderer::Caches::getInstance().resourceCache.recycle(bitmap);
350     }
351 #endif // USE_OPENGL_RENDERER
352     bitmap->setPixels(NULL, NULL);
353     return true;
354 }
355 
Bitmap_reconfigure(JNIEnv * env,jobject clazz,jint bitmapInt,int width,int height,SkBitmap::Config config,int allocSize)356 static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jint bitmapInt,
357         int width, int height, SkBitmap::Config config, int allocSize) {
358     if (width * height * SkBitmap::ComputeBytesPerPixel(config) > allocSize) {
359         // done in native as there's no way to get BytesPerPixel in Java
360         doThrowIAE(env, "Bitmap not large enough to support new configuration");
361         return;
362     }
363     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapInt);
364     SkPixelRef* ref = bitmap->pixelRef();
365     SkSafeRef(ref);
366     bitmap->setConfig(config, width, height);
367     bitmap->setPixelRef(ref);
368 
369     // notifyPixelsChanged will increment the generation ID even though the actual pixel data
370     // hasn't been touched. This signals the renderer that the bitmap (including width, height,
371     // and config) has changed.
372     ref->notifyPixelsChanged();
373     SkSafeUnref(ref);
374 }
375 
376 // These must match the int values in Bitmap.java
377 enum JavaEncodeFormat {
378     kJPEG_JavaEncodeFormat = 0,
379     kPNG_JavaEncodeFormat = 1,
380     kWEBP_JavaEncodeFormat = 2
381 };
382 
Bitmap_compress(JNIEnv * env,jobject clazz,SkBitmap * bitmap,int format,int quality,jobject jstream,jbyteArray jstorage)383 static bool Bitmap_compress(JNIEnv* env, jobject clazz, SkBitmap* bitmap,
384                             int format, int quality,
385                             jobject jstream, jbyteArray jstorage) {
386     SkImageEncoder::Type fm;
387 
388     switch (format) {
389     case kJPEG_JavaEncodeFormat:
390         fm = SkImageEncoder::kJPEG_Type;
391         break;
392     case kPNG_JavaEncodeFormat:
393         fm = SkImageEncoder::kPNG_Type;
394         break;
395     case kWEBP_JavaEncodeFormat:
396         fm = SkImageEncoder::kWEBP_Type;
397         break;
398     default:
399         return false;
400     }
401 
402     bool success = false;
403     if (NULL != bitmap) {
404         SkAutoLockPixels alp(*bitmap);
405 
406         if (NULL == bitmap->getPixels()) {
407             return false;
408         }
409 
410         SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
411         if (NULL == strm) {
412             return false;
413         }
414 
415         SkImageEncoder* encoder = SkImageEncoder::Create(fm);
416         if (NULL != encoder) {
417             success = encoder->encodeStream(strm, *bitmap, quality);
418             delete encoder;
419         }
420         delete strm;
421     }
422     return success;
423 }
424 
Bitmap_erase(JNIEnv * env,jobject,SkBitmap * bitmap,jint color)425 static void Bitmap_erase(JNIEnv* env, jobject, SkBitmap* bitmap, jint color) {
426     bitmap->eraseColor(color);
427 }
428 
Bitmap_rowBytes(JNIEnv * env,jobject,SkBitmap * bitmap)429 static int Bitmap_rowBytes(JNIEnv* env, jobject, SkBitmap* bitmap) {
430     return bitmap->rowBytes();
431 }
432 
Bitmap_config(JNIEnv * env,jobject,SkBitmap * bitmap)433 static int Bitmap_config(JNIEnv* env, jobject, SkBitmap* bitmap) {
434     return bitmap->config();
435 }
436 
Bitmap_getGenerationId(JNIEnv * env,jobject,SkBitmap * bitmap)437 static int Bitmap_getGenerationId(JNIEnv* env, jobject, SkBitmap* bitmap) {
438     return bitmap->getGenerationID();
439 }
440 
Bitmap_hasAlpha(JNIEnv * env,jobject,SkBitmap * bitmap)441 static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, SkBitmap* bitmap) {
442     return !bitmap->isOpaque();
443 }
444 
Bitmap_setAlphaAndPremultiplied(JNIEnv * env,jobject,SkBitmap * bitmap,jboolean hasAlpha,jboolean isPremul)445 static void Bitmap_setAlphaAndPremultiplied(JNIEnv* env, jobject, SkBitmap* bitmap,
446                                             jboolean hasAlpha, jboolean isPremul) {
447     if (!hasAlpha) {
448         bitmap->setAlphaType(kOpaque_SkAlphaType);
449     } else if (isPremul) {
450         bitmap->setAlphaType(kPremul_SkAlphaType);
451     } else {
452         bitmap->setAlphaType(kUnpremul_SkAlphaType);
453     }
454 }
455 
Bitmap_hasMipMap(JNIEnv * env,jobject,SkBitmap * bitmap)456 static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, SkBitmap* bitmap) {
457     return bitmap->hasHardwareMipMap();
458 }
459 
Bitmap_setHasMipMap(JNIEnv * env,jobject,SkBitmap * bitmap,jboolean hasMipMap)460 static void Bitmap_setHasMipMap(JNIEnv* env, jobject, SkBitmap* bitmap,
461                                 jboolean hasMipMap) {
462     bitmap->setHasHardwareMipMap(hasMipMap);
463 }
464 
465 ///////////////////////////////////////////////////////////////////////////////
466 
Bitmap_createFromParcel(JNIEnv * env,jobject,jobject parcel)467 static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
468     if (parcel == NULL) {
469         SkDebugf("-------- unparcel parcel is NULL\n");
470         return NULL;
471     }
472 
473     android::Parcel* p = android::parcelForJavaObject(env, parcel);
474 
475     const bool              isMutable = p->readInt32() != 0;
476     const SkBitmap::Config  config = (SkBitmap::Config)p->readInt32();
477     const int               width = p->readInt32();
478     const int               height = p->readInt32();
479     const int               rowBytes = p->readInt32();
480     const int               density = p->readInt32();
481 
482     if (SkBitmap::kARGB_8888_Config != config &&
483             SkBitmap::kRGB_565_Config != config &&
484             SkBitmap::kARGB_4444_Config != config &&
485             SkBitmap::kIndex8_Config != config &&
486             SkBitmap::kA8_Config != config) {
487         SkDebugf("Bitmap_createFromParcel unknown config: %d\n", config);
488         return NULL;
489     }
490 
491     SkBitmap* bitmap = new SkBitmap;
492 
493     bitmap->setConfig(config, width, height, rowBytes);
494 
495     SkColorTable* ctable = NULL;
496     if (config == SkBitmap::kIndex8_Config) {
497         int count = p->readInt32();
498         if (count > 0) {
499             size_t size = count * sizeof(SkPMColor);
500             const SkPMColor* src = (const SkPMColor*)p->readInplace(size);
501             ctable = new SkColorTable(src, count);
502         }
503     }
504 
505     jbyteArray buffer = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable);
506     if (NULL == buffer) {
507         SkSafeUnref(ctable);
508         delete bitmap;
509         return NULL;
510     }
511 
512     SkSafeUnref(ctable);
513 
514     size_t size = bitmap->getSize();
515 
516     android::Parcel::ReadableBlob blob;
517     android::status_t status = p->readBlob(size, &blob);
518     if (status) {
519         doThrowRE(env, "Could not read bitmap from parcel blob.");
520         delete bitmap;
521         return NULL;
522     }
523 
524     bitmap->lockPixels();
525     memcpy(bitmap->getPixels(), blob.data(), size);
526     bitmap->unlockPixels();
527 
528     blob.release();
529 
530     return GraphicsJNI::createBitmap(env, bitmap, buffer, getPremulBitmapCreateFlags(isMutable),
531             NULL, NULL, density);
532 }
533 
Bitmap_writeToParcel(JNIEnv * env,jobject,const SkBitmap * bitmap,jboolean isMutable,jint density,jobject parcel)534 static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
535                                      const SkBitmap* bitmap,
536                                      jboolean isMutable, jint density,
537                                      jobject parcel) {
538     if (parcel == NULL) {
539         SkDebugf("------- writeToParcel null parcel\n");
540         return false;
541     }
542 
543     android::Parcel* p = android::parcelForJavaObject(env, parcel);
544 
545     p->writeInt32(isMutable);
546     p->writeInt32(bitmap->config());
547     p->writeInt32(bitmap->width());
548     p->writeInt32(bitmap->height());
549     p->writeInt32(bitmap->rowBytes());
550     p->writeInt32(density);
551 
552     if (bitmap->config() == SkBitmap::kIndex8_Config) {
553         SkColorTable* ctable = bitmap->getColorTable();
554         if (ctable != NULL) {
555             int count = ctable->count();
556             p->writeInt32(count);
557             memcpy(p->writeInplace(count * sizeof(SkPMColor)),
558                    ctable->lockColors(), count * sizeof(SkPMColor));
559             ctable->unlockColors();
560         } else {
561             p->writeInt32(0);   // indicate no ctable
562         }
563     }
564 
565     size_t size = bitmap->getSize();
566 
567     android::Parcel::WritableBlob blob;
568     android::status_t status = p->writeBlob(size, &blob);
569     if (status) {
570         doThrowRE(env, "Could not write bitmap to parcel blob.");
571         return false;
572     }
573 
574     bitmap->lockPixels();
575     const void* pSrc =  bitmap->getPixels();
576     if (pSrc == NULL) {
577         memset(blob.data(), 0, size);
578     } else {
579         memcpy(blob.data(), pSrc, size);
580     }
581     bitmap->unlockPixels();
582 
583     blob.release();
584     return true;
585 }
586 
Bitmap_extractAlpha(JNIEnv * env,jobject clazz,const SkBitmap * src,const SkPaint * paint,jintArray offsetXY)587 static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
588                                    const SkBitmap* src, const SkPaint* paint,
589                                    jintArray offsetXY) {
590     SkIPoint  offset;
591     SkBitmap* dst = new SkBitmap;
592     JavaPixelAllocator allocator(env);
593 
594     src->extractAlpha(dst, paint, &allocator, &offset);
595     // If Skia can't allocate pixels for destination bitmap, it resets
596     // it, that is set its pixels buffer to NULL, and zero width and height.
597     if (dst->getPixels() == NULL && src->getPixels() != NULL) {
598         delete dst;
599         doThrowOOME(env, "failed to allocate pixels for alpha");
600         return NULL;
601     }
602     if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
603         int* array = env->GetIntArrayElements(offsetXY, NULL);
604         array[0] = offset.fX;
605         array[1] = offset.fY;
606         env->ReleaseIntArrayElements(offsetXY, array, 0);
607     }
608 
609     return GraphicsJNI::createBitmap(env, dst, allocator.getStorageObj(),
610             GraphicsJNI::kBitmapCreateFlag_Mutable, NULL, NULL);
611 }
612 
613 ///////////////////////////////////////////////////////////////////////////////
614 
Bitmap_getPixel(JNIEnv * env,jobject,const SkBitmap * bitmap,int x,int y,bool isPremultiplied)615 static int Bitmap_getPixel(JNIEnv* env, jobject, const SkBitmap* bitmap,
616         int x, int y, bool isPremultiplied) {
617     SkAutoLockPixels alp(*bitmap);
618 
619     ToColorProc proc = ChooseToColorProc(*bitmap, isPremultiplied);
620     if (NULL == proc) {
621         return 0;
622     }
623     const void* src = bitmap->getAddr(x, y);
624     if (NULL == src) {
625         return 0;
626     }
627 
628     SkColor dst[1];
629     proc(dst, src, 1, bitmap->getColorTable());
630     return dst[0];
631 }
632 
Bitmap_getPixels(JNIEnv * env,jobject,const SkBitmap * bitmap,jintArray pixelArray,int offset,int stride,int x,int y,int width,int height,bool isPremultiplied)633 static void Bitmap_getPixels(JNIEnv* env, jobject, const SkBitmap* bitmap,
634         jintArray pixelArray, int offset, int stride,
635         int x, int y, int width, int height, bool isPremultiplied) {
636     SkAutoLockPixels alp(*bitmap);
637 
638     ToColorProc proc = ChooseToColorProc(*bitmap, isPremultiplied);
639     if (NULL == proc) {
640         return;
641     }
642     const void* src = bitmap->getAddr(x, y);
643     if (NULL == src) {
644         return;
645     }
646 
647     SkColorTable* ctable = bitmap->getColorTable();
648     jint* dst = env->GetIntArrayElements(pixelArray, NULL);
649     SkColor* d = (SkColor*)dst + offset;
650     while (--height >= 0) {
651         proc(d, src, width, ctable);
652         d += stride;
653         src = (void*)((const char*)src + bitmap->rowBytes());
654     }
655     env->ReleaseIntArrayElements(pixelArray, dst, 0);
656 }
657 
658 ///////////////////////////////////////////////////////////////////////////////
659 
Bitmap_setPixel(JNIEnv * env,jobject,const SkBitmap * bitmap,int x,int y,SkColor color,bool isPremultiplied)660 static void Bitmap_setPixel(JNIEnv* env, jobject, const SkBitmap* bitmap,
661         int x, int y, SkColor color, bool isPremultiplied) {
662     SkAutoLockPixels alp(*bitmap);
663     if (NULL == bitmap->getPixels()) {
664         return;
665     }
666 
667     FromColorProc proc = ChooseFromColorProc(bitmap->config(), isPremultiplied);
668     if (NULL == proc) {
669         return;
670     }
671 
672     proc(bitmap->getAddr(x, y), &color, 1, x, y);
673     bitmap->notifyPixelsChanged();
674 }
675 
Bitmap_setPixels(JNIEnv * env,jobject,const SkBitmap * bitmap,jintArray pixelArray,int offset,int stride,int x,int y,int width,int height,bool isPremultiplied)676 static void Bitmap_setPixels(JNIEnv* env, jobject, const SkBitmap* bitmap,
677         jintArray pixelArray, int offset, int stride,
678         int x, int y, int width, int height, bool isPremultiplied) {
679     GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
680             x, y, width, height, *bitmap, isPremultiplied);
681 }
682 
Bitmap_copyPixelsToBuffer(JNIEnv * env,jobject,const SkBitmap * bitmap,jobject jbuffer)683 static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
684                                       const SkBitmap* bitmap, jobject jbuffer) {
685     SkAutoLockPixels alp(*bitmap);
686     const void* src = bitmap->getPixels();
687 
688     if (NULL != src) {
689         android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
690 
691         // the java side has already checked that buffer is large enough
692         memcpy(abp.pointer(), src, bitmap->getSize());
693     }
694 }
695 
Bitmap_copyPixelsFromBuffer(JNIEnv * env,jobject,const SkBitmap * bitmap,jobject jbuffer)696 static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,
697                                     const SkBitmap* bitmap, jobject jbuffer) {
698     SkAutoLockPixels alp(*bitmap);
699     void* dst = bitmap->getPixels();
700 
701     if (NULL != dst) {
702         android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);
703         // the java side has already checked that buffer is large enough
704         memcpy(dst, abp.pointer(), bitmap->getSize());
705         bitmap->notifyPixelsChanged();
706     }
707 }
708 
Bitmap_sameAs(JNIEnv * env,jobject,const SkBitmap * bm0,const SkBitmap * bm1)709 static bool Bitmap_sameAs(JNIEnv* env, jobject, const SkBitmap* bm0,
710                              const SkBitmap* bm1) {
711     if (bm0->width() != bm1->width() ||
712         bm0->height() != bm1->height() ||
713         bm0->config() != bm1->config()) {
714         return false;
715     }
716 
717     SkAutoLockPixels alp0(*bm0);
718     SkAutoLockPixels alp1(*bm1);
719 
720     // if we can't load the pixels, return false
721     if (NULL == bm0->getPixels() || NULL == bm1->getPixels()) {
722         return false;
723     }
724 
725     if (bm0->config() == SkBitmap::kIndex8_Config) {
726         SkColorTable* ct0 = bm0->getColorTable();
727         SkColorTable* ct1 = bm1->getColorTable();
728         if (NULL == ct0 || NULL == ct1) {
729             return false;
730         }
731         if (ct0->count() != ct1->count()) {
732             return false;
733         }
734 
735         SkAutoLockColors alc0(ct0);
736         SkAutoLockColors alc1(ct1);
737         const size_t size = ct0->count() * sizeof(SkPMColor);
738         if (memcmp(alc0.colors(), alc1.colors(), size) != 0) {
739             return false;
740         }
741     }
742 
743     // now compare each scanline. We can't do the entire buffer at once,
744     // since we don't care about the pixel values that might extend beyond
745     // the width (since the scanline might be larger than the logical width)
746     const int h = bm0->height();
747     const size_t size = bm0->width() * bm0->bytesPerPixel();
748     for (int y = 0; y < h; y++) {
749         if (memcmp(bm0->getAddr(0, y), bm1->getAddr(0, y), size) != 0) {
750             return false;
751         }
752     }
753     return true;
754 }
755 
Bitmap_prepareToDraw(JNIEnv * env,jobject,SkBitmap * bitmap)756 static void Bitmap_prepareToDraw(JNIEnv* env, jobject, SkBitmap* bitmap) {
757     bitmap->lockPixels();
758     bitmap->unlockPixels();
759 }
760 
761 ///////////////////////////////////////////////////////////////////////////////
762 
763 #include <android_runtime/AndroidRuntime.h>
764 
765 static JNINativeMethod gBitmapMethods[] = {
766     {   "nativeCreate",             "([IIIIIIZ)Landroid/graphics/Bitmap;",
767         (void*)Bitmap_creator },
768     {   "nativeCopy",               "(IIZ)Landroid/graphics/Bitmap;",
769         (void*)Bitmap_copy },
770     {   "nativeDestructor",         "(I)V", (void*)Bitmap_destructor },
771     {   "nativeRecycle",            "(I)Z", (void*)Bitmap_recycle },
772     {   "nativeReconfigure",        "(IIIII)V", (void*)Bitmap_reconfigure },
773     {   "nativeCompress",           "(IIILjava/io/OutputStream;[B)Z",
774         (void*)Bitmap_compress },
775     {   "nativeErase",              "(II)V", (void*)Bitmap_erase },
776     {   "nativeRowBytes",           "(I)I", (void*)Bitmap_rowBytes },
777     {   "nativeConfig",             "(I)I", (void*)Bitmap_config },
778     {   "nativeHasAlpha",           "(I)Z", (void*)Bitmap_hasAlpha },
779     {   "nativeSetAlphaAndPremultiplied", "(IZZ)V", (void*)Bitmap_setAlphaAndPremultiplied},
780     {   "nativeHasMipMap",          "(I)Z", (void*)Bitmap_hasMipMap },
781     {   "nativeSetHasMipMap",       "(IZ)V", (void*)Bitmap_setHasMipMap },
782     {   "nativeCreateFromParcel",
783         "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
784         (void*)Bitmap_createFromParcel },
785     {   "nativeWriteToParcel",      "(IZILandroid/os/Parcel;)Z",
786         (void*)Bitmap_writeToParcel },
787     {   "nativeExtractAlpha",       "(II[I)Landroid/graphics/Bitmap;",
788         (void*)Bitmap_extractAlpha },
789     {   "nativeGenerationId",       "(I)I", (void*)Bitmap_getGenerationId },
790     {   "nativeGetPixel",           "(IIIZ)I", (void*)Bitmap_getPixel },
791     {   "nativeGetPixels",          "(I[IIIIIIIZ)V", (void*)Bitmap_getPixels },
792     {   "nativeSetPixel",           "(IIIIZ)V", (void*)Bitmap_setPixel },
793     {   "nativeSetPixels",          "(I[IIIIIIIZ)V", (void*)Bitmap_setPixels },
794     {   "nativeCopyPixelsToBuffer", "(ILjava/nio/Buffer;)V",
795                                             (void*)Bitmap_copyPixelsToBuffer },
796     {   "nativeCopyPixelsFromBuffer", "(ILjava/nio/Buffer;)V",
797                                             (void*)Bitmap_copyPixelsFromBuffer },
798     {   "nativeSameAs",             "(II)Z", (void*)Bitmap_sameAs },
799     {   "nativePrepareToDraw",      "(I)V", (void*)Bitmap_prepareToDraw },
800 };
801 
802 #define kClassPathName  "android/graphics/Bitmap"
803 
register_android_graphics_Bitmap(JNIEnv * env)804 int register_android_graphics_Bitmap(JNIEnv* env)
805 {
806     return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
807                                 gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods));
808 }
809