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