Bitmap.cpp revision 3ed72781a0b155a88e52c8d295f50daab8cfb9ae
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 29typedef void (*FromColorProc)(void* dst, const SkColor src[], int width, 30 int x, int y); 31 32static 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 41static 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 53static 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 66static 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 80bool 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 113typedef void (*ToColorProc)(SkColor dst[], const void* src, int width, 114 SkColorTable*); 115 116static 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 125static 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 136static 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 145static 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 156static 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 167static 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 178static 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 192static 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 214static 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 // ARGB_4444 is a deprecated format, convert automatically to 8888 226 if (config == SkBitmap::kARGB_4444_Config) { 227 config = SkBitmap::kARGB_8888_Config; 228 } 229 230 SkBitmap bitmap; 231 bitmap.setConfig(config, width, height); 232 233 jbyteArray buff = GraphicsJNI::allocateJavaPixelRef(env, &bitmap, NULL); 234 if (NULL == buff) { 235 return NULL; 236 } 237 238 if (jColors != NULL) { 239 GraphicsJNI::SetPixels(env, jColors, offset, stride, 0, 0, width, height, bitmap); 240 } 241 242 return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), buff, isMutable, NULL, NULL); 243} 244 245static jobject Bitmap_copy(JNIEnv* env, jobject, const SkBitmap* src, 246 SkBitmap::Config dstConfig, jboolean isMutable) { 247 SkBitmap result; 248 JavaPixelAllocator allocator(env); 249 250 if (!src->copyTo(&result, dstConfig, &allocator)) { 251 return NULL; 252 } 253 254 return GraphicsJNI::createBitmap(env, new SkBitmap(result), allocator.getStorageObj(), isMutable, NULL, NULL); 255} 256 257static void Bitmap_destructor(JNIEnv* env, jobject, SkBitmap* bitmap) { 258#ifdef USE_OPENGL_RENDERER 259 if (android::uirenderer::Caches::hasInstance()) { 260 android::uirenderer::Caches::getInstance().resourceCache.destructor(bitmap); 261 return; 262 } 263#endif // USE_OPENGL_RENDERER 264 delete bitmap; 265} 266 267static jboolean Bitmap_recycle(JNIEnv* env, jobject, SkBitmap* bitmap) { 268#ifdef USE_OPENGL_RENDERER 269 if (android::uirenderer::Caches::hasInstance()) { 270 return android::uirenderer::Caches::getInstance().resourceCache.recycle(bitmap); 271 } 272#endif // USE_OPENGL_RENDERER 273 bitmap->setPixels(NULL, NULL); 274 return true; 275} 276 277static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jint bitmapInt, 278 int width, int height, SkBitmap::Config config, int allocSize) { 279 if (width * height * SkBitmap::ComputeBytesPerPixel(config) > allocSize) { 280 // done in native as there's no way to get BytesPerPixel in Java 281 doThrowIAE(env, "Bitmap not large enough to support new configuration"); 282 return; 283 } 284 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapInt); 285 SkPixelRef* ref = bitmap->pixelRef(); 286 SkSafeRef(ref); 287 bitmap->setConfig(config, width, height); 288 bitmap->setPixelRef(ref); 289 290 // notifyPixelsChanged will increment the generation ID even though the actual pixel data 291 // hasn't been touched. This signals the renderer that the bitmap (including width, height, 292 // and config) has changed. 293 ref->notifyPixelsChanged(); 294 SkSafeUnref(ref); 295} 296 297// These must match the int values in Bitmap.java 298enum JavaEncodeFormat { 299 kJPEG_JavaEncodeFormat = 0, 300 kPNG_JavaEncodeFormat = 1, 301 kWEBP_JavaEncodeFormat = 2 302}; 303 304static bool Bitmap_compress(JNIEnv* env, jobject clazz, SkBitmap* bitmap, 305 int format, int quality, 306 jobject jstream, jbyteArray jstorage) { 307 SkImageEncoder::Type fm; 308 309 switch (format) { 310 case kJPEG_JavaEncodeFormat: 311 fm = SkImageEncoder::kJPEG_Type; 312 break; 313 case kPNG_JavaEncodeFormat: 314 fm = SkImageEncoder::kPNG_Type; 315 break; 316 case kWEBP_JavaEncodeFormat: 317 fm = SkImageEncoder::kWEBP_Type; 318 break; 319 default: 320 return false; 321 } 322 323 bool success = false; 324 if (NULL != bitmap) { 325 SkAutoLockPixels alp(*bitmap); 326 327 if (NULL == bitmap->getPixels()) { 328 return false; 329 } 330 331 SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage); 332 if (NULL == strm) { 333 return false; 334 } 335 336 SkImageEncoder* encoder = SkImageEncoder::Create(fm); 337 if (NULL != encoder) { 338 success = encoder->encodeStream(strm, *bitmap, quality); 339 delete encoder; 340 } 341 delete strm; 342 } 343 return success; 344} 345 346static void Bitmap_erase(JNIEnv* env, jobject, SkBitmap* bitmap, jint color) { 347 bitmap->eraseColor(color); 348} 349 350static int Bitmap_width(JNIEnv* env, jobject, SkBitmap* bitmap) { 351 return bitmap->width(); 352} 353 354static int Bitmap_height(JNIEnv* env, jobject, SkBitmap* bitmap) { 355 return bitmap->height(); 356} 357 358static int Bitmap_rowBytes(JNIEnv* env, jobject, SkBitmap* bitmap) { 359 return bitmap->rowBytes(); 360} 361 362static int Bitmap_config(JNIEnv* env, jobject, SkBitmap* bitmap) { 363 return bitmap->config(); 364} 365 366static int Bitmap_getGenerationId(JNIEnv* env, jobject, SkBitmap* bitmap) { 367 return bitmap->getGenerationID(); 368} 369 370static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, SkBitmap* bitmap) { 371 return !bitmap->isOpaque(); 372} 373 374static void Bitmap_setHasAlpha(JNIEnv* env, jobject, SkBitmap* bitmap, 375 jboolean hasAlpha) { 376 bitmap->setIsOpaque(!hasAlpha); 377} 378 379static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, SkBitmap* bitmap) { 380 return bitmap->hasHardwareMipMap(); 381} 382 383static void Bitmap_setHasMipMap(JNIEnv* env, jobject, SkBitmap* bitmap, 384 jboolean hasMipMap) { 385 bitmap->setHasHardwareMipMap(hasMipMap); 386} 387 388/////////////////////////////////////////////////////////////////////////////// 389 390static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { 391 if (parcel == NULL) { 392 SkDebugf("-------- unparcel parcel is NULL\n"); 393 return NULL; 394 } 395 396 android::Parcel* p = android::parcelForJavaObject(env, parcel); 397 398 const bool isMutable = p->readInt32() != 0; 399 const SkBitmap::Config config = (SkBitmap::Config)p->readInt32(); 400 const int width = p->readInt32(); 401 const int height = p->readInt32(); 402 const int rowBytes = p->readInt32(); 403 const int density = p->readInt32(); 404 405 if (SkBitmap::kARGB_8888_Config != config && 406 SkBitmap::kRGB_565_Config != config && 407 SkBitmap::kARGB_4444_Config != config && 408 SkBitmap::kIndex8_Config != config && 409 SkBitmap::kA8_Config != config) { 410 SkDebugf("Bitmap_createFromParcel unknown config: %d\n", config); 411 return NULL; 412 } 413 414 SkBitmap* bitmap = new SkBitmap; 415 416 bitmap->setConfig(config, width, height, rowBytes); 417 418 SkColorTable* ctable = NULL; 419 if (config == SkBitmap::kIndex8_Config) { 420 int count = p->readInt32(); 421 if (count > 0) { 422 size_t size = count * sizeof(SkPMColor); 423 const SkPMColor* src = (const SkPMColor*)p->readInplace(size); 424 ctable = new SkColorTable(src, count); 425 } 426 } 427 428 jbyteArray buffer = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable); 429 if (NULL == buffer) { 430 SkSafeUnref(ctable); 431 delete bitmap; 432 return NULL; 433 } 434 435 SkSafeUnref(ctable); 436 437 size_t size = bitmap->getSize(); 438 439 android::Parcel::ReadableBlob blob; 440 android::status_t status = p->readBlob(size, &blob); 441 if (status) { 442 doThrowRE(env, "Could not read bitmap from parcel blob."); 443 delete bitmap; 444 return NULL; 445 } 446 447 bitmap->lockPixels(); 448 memcpy(bitmap->getPixels(), blob.data(), size); 449 bitmap->unlockPixels(); 450 451 blob.release(); 452 return GraphicsJNI::createBitmap(env, bitmap, buffer, isMutable, NULL, NULL, density); 453} 454 455static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, 456 const SkBitmap* bitmap, 457 jboolean isMutable, jint density, 458 jobject parcel) { 459 if (parcel == NULL) { 460 SkDebugf("------- writeToParcel null parcel\n"); 461 return false; 462 } 463 464 android::Parcel* p = android::parcelForJavaObject(env, parcel); 465 466 p->writeInt32(isMutable); 467 p->writeInt32(bitmap->config()); 468 p->writeInt32(bitmap->width()); 469 p->writeInt32(bitmap->height()); 470 p->writeInt32(bitmap->rowBytes()); 471 p->writeInt32(density); 472 473 if (bitmap->getConfig() == SkBitmap::kIndex8_Config) { 474 SkColorTable* ctable = bitmap->getColorTable(); 475 if (ctable != NULL) { 476 int count = ctable->count(); 477 p->writeInt32(count); 478 memcpy(p->writeInplace(count * sizeof(SkPMColor)), 479 ctable->lockColors(), count * sizeof(SkPMColor)); 480 ctable->unlockColors(false); 481 } else { 482 p->writeInt32(0); // indicate no ctable 483 } 484 } 485 486 size_t size = bitmap->getSize(); 487 488 android::Parcel::WritableBlob blob; 489 android::status_t status = p->writeBlob(size, &blob); 490 if (status) { 491 doThrowRE(env, "Could not write bitmap to parcel blob."); 492 return false; 493 } 494 495 bitmap->lockPixels(); 496 const void* pSrc = bitmap->getPixels(); 497 if (pSrc == NULL) { 498 memset(blob.data(), 0, size); 499 } else { 500 memcpy(blob.data(), pSrc, size); 501 } 502 bitmap->unlockPixels(); 503 504 blob.release(); 505 return true; 506} 507 508static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz, 509 const SkBitmap* src, const SkPaint* paint, 510 jintArray offsetXY) { 511 SkIPoint offset; 512 SkBitmap* dst = new SkBitmap; 513 JavaPixelAllocator allocator(env); 514 515 src->extractAlpha(dst, paint, &allocator, &offset); 516 // If Skia can't allocate pixels for destination bitmap, it resets 517 // it, that is set its pixels buffer to NULL, and zero width and height. 518 if (dst->getPixels() == NULL && src->getPixels() != NULL) { 519 delete dst; 520 doThrowOOME(env, "failed to allocate pixels for alpha"); 521 return NULL; 522 } 523 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) { 524 int* array = env->GetIntArrayElements(offsetXY, NULL); 525 array[0] = offset.fX; 526 array[1] = offset.fY; 527 env->ReleaseIntArrayElements(offsetXY, array, 0); 528 } 529 530 return GraphicsJNI::createBitmap(env, dst, allocator.getStorageObj(), true, NULL, NULL); 531} 532 533/////////////////////////////////////////////////////////////////////////////// 534 535static int Bitmap_getPixel(JNIEnv* env, jobject, const SkBitmap* bitmap, 536 int x, int y) { 537 SkAutoLockPixels alp(*bitmap); 538 539 ToColorProc proc = ChooseToColorProc(*bitmap); 540 if (NULL == proc) { 541 return 0; 542 } 543 const void* src = bitmap->getAddr(x, y); 544 if (NULL == src) { 545 return 0; 546 } 547 548 SkColor dst[1]; 549 proc(dst, src, 1, bitmap->getColorTable()); 550 return dst[0]; 551} 552 553static void Bitmap_getPixels(JNIEnv* env, jobject, const SkBitmap* bitmap, 554 jintArray pixelArray, int offset, int stride, 555 int x, int y, int width, int height) { 556 SkAutoLockPixels alp(*bitmap); 557 558 ToColorProc proc = ChooseToColorProc(*bitmap); 559 if (NULL == proc) { 560 return; 561 } 562 const void* src = bitmap->getAddr(x, y); 563 if (NULL == src) { 564 return; 565 } 566 567 SkColorTable* ctable = bitmap->getColorTable(); 568 jint* dst = env->GetIntArrayElements(pixelArray, NULL); 569 SkColor* d = (SkColor*)dst + offset; 570 while (--height >= 0) { 571 proc(d, src, width, ctable); 572 d += stride; 573 src = (void*)((const char*)src + bitmap->rowBytes()); 574 } 575 env->ReleaseIntArrayElements(pixelArray, dst, 0); 576} 577 578/////////////////////////////////////////////////////////////////////////////// 579 580static void Bitmap_setPixel(JNIEnv* env, jobject, const SkBitmap* bitmap, 581 int x, int y, SkColor color) { 582 SkAutoLockPixels alp(*bitmap); 583 if (NULL == bitmap->getPixels()) { 584 return; 585 } 586 587 FromColorProc proc = ChooseFromColorProc(bitmap->config()); 588 if (NULL == proc) { 589 return; 590 } 591 592 proc(bitmap->getAddr(x, y), &color, 1, x, y); 593 bitmap->notifyPixelsChanged(); 594} 595 596static void Bitmap_setPixels(JNIEnv* env, jobject, const SkBitmap* bitmap, 597 jintArray pixelArray, int offset, int stride, 598 int x, int y, int width, int height) { 599 GraphicsJNI::SetPixels(env, pixelArray, offset, stride, 600 x, y, width, height, *bitmap); 601} 602 603static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject, 604 const SkBitmap* bitmap, jobject jbuffer) { 605 SkAutoLockPixels alp(*bitmap); 606 const void* src = bitmap->getPixels(); 607 608 if (NULL != src) { 609 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE); 610 611 // the java side has already checked that buffer is large enough 612 memcpy(abp.pointer(), src, bitmap->getSize()); 613 } 614} 615 616static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject, 617 const SkBitmap* bitmap, jobject jbuffer) { 618 SkAutoLockPixels alp(*bitmap); 619 void* dst = bitmap->getPixels(); 620 621 if (NULL != dst) { 622 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE); 623 // the java side has already checked that buffer is large enough 624 memcpy(dst, abp.pointer(), bitmap->getSize()); 625 bitmap->notifyPixelsChanged(); 626 } 627} 628 629static bool Bitmap_sameAs(JNIEnv* env, jobject, const SkBitmap* bm0, 630 const SkBitmap* bm1) { 631 if (bm0->width() != bm1->width() || 632 bm0->height() != bm1->height() || 633 bm0->config() != bm1->config()) { 634 return false; 635 } 636 637 SkAutoLockPixels alp0(*bm0); 638 SkAutoLockPixels alp1(*bm1); 639 640 // if we can't load the pixels, return false 641 if (NULL == bm0->getPixels() || NULL == bm1->getPixels()) { 642 return false; 643 } 644 645 if (bm0->config() == SkBitmap::kIndex8_Config) { 646 SkColorTable* ct0 = bm0->getColorTable(); 647 SkColorTable* ct1 = bm1->getColorTable(); 648 if (NULL == ct0 || NULL == ct1) { 649 return false; 650 } 651 if (ct0->count() != ct1->count()) { 652 return false; 653 } 654 655 SkAutoLockColors alc0(ct0); 656 SkAutoLockColors alc1(ct1); 657 const size_t size = ct0->count() * sizeof(SkPMColor); 658 if (memcmp(alc0.colors(), alc1.colors(), size) != 0) { 659 return false; 660 } 661 } 662 663 // now compare each scanline. We can't do the entire buffer at once, 664 // since we don't care about the pixel values that might extend beyond 665 // the width (since the scanline might be larger than the logical width) 666 const int h = bm0->height(); 667 const size_t size = bm0->width() * bm0->bytesPerPixel(); 668 for (int y = 0; y < h; y++) { 669 if (memcmp(bm0->getAddr(0, y), bm1->getAddr(0, y), size) != 0) { 670 return false; 671 } 672 } 673 return true; 674} 675 676static void Bitmap_prepareToDraw(JNIEnv* env, jobject, SkBitmap* bitmap) { 677 bitmap->lockPixels(); 678 bitmap->unlockPixels(); 679} 680 681/////////////////////////////////////////////////////////////////////////////// 682 683#include <android_runtime/AndroidRuntime.h> 684 685static JNINativeMethod gBitmapMethods[] = { 686 { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;", 687 (void*)Bitmap_creator }, 688 { "nativeCopy", "(IIZ)Landroid/graphics/Bitmap;", 689 (void*)Bitmap_copy }, 690 { "nativeDestructor", "(I)V", (void*)Bitmap_destructor }, 691 { "nativeRecycle", "(I)Z", (void*)Bitmap_recycle }, 692 { "nativeReconfigure", "(IIIII)V", (void*)Bitmap_reconfigure }, 693 { "nativeCompress", "(IIILjava/io/OutputStream;[B)Z", 694 (void*)Bitmap_compress }, 695 { "nativeErase", "(II)V", (void*)Bitmap_erase }, 696 { "nativeWidth", "(I)I", (void*)Bitmap_width }, 697 { "nativeHeight", "(I)I", (void*)Bitmap_height }, 698 { "nativeRowBytes", "(I)I", (void*)Bitmap_rowBytes }, 699 { "nativeConfig", "(I)I", (void*)Bitmap_config }, 700 { "nativeHasAlpha", "(I)Z", (void*)Bitmap_hasAlpha }, 701 { "nativeSetHasAlpha", "(IZ)V", (void*)Bitmap_setHasAlpha }, 702 { "nativeHasMipMap", "(I)Z", (void*)Bitmap_hasMipMap }, 703 { "nativeSetHasMipMap", "(IZ)V", (void*)Bitmap_setHasMipMap }, 704 { "nativeCreateFromParcel", 705 "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;", 706 (void*)Bitmap_createFromParcel }, 707 { "nativeWriteToParcel", "(IZILandroid/os/Parcel;)Z", 708 (void*)Bitmap_writeToParcel }, 709 { "nativeExtractAlpha", "(II[I)Landroid/graphics/Bitmap;", 710 (void*)Bitmap_extractAlpha }, 711 { "nativeGenerationId", "(I)I", (void*)Bitmap_getGenerationId }, 712 { "nativeGetPixel", "(III)I", (void*)Bitmap_getPixel }, 713 { "nativeGetPixels", "(I[IIIIIII)V", (void*)Bitmap_getPixels }, 714 { "nativeSetPixel", "(IIII)V", (void*)Bitmap_setPixel }, 715 { "nativeSetPixels", "(I[IIIIIII)V", (void*)Bitmap_setPixels }, 716 { "nativeCopyPixelsToBuffer", "(ILjava/nio/Buffer;)V", 717 (void*)Bitmap_copyPixelsToBuffer }, 718 { "nativeCopyPixelsFromBuffer", "(ILjava/nio/Buffer;)V", 719 (void*)Bitmap_copyPixelsFromBuffer }, 720 { "nativeSameAs", "(II)Z", (void*)Bitmap_sameAs }, 721 { "nativePrepareToDraw", "(I)V", (void*)Bitmap_prepareToDraw }, 722}; 723 724#define kClassPathName "android/graphics/Bitmap" 725 726int register_android_graphics_Bitmap(JNIEnv* env) 727{ 728 return android::AndroidRuntime::registerNativeMethods(env, kClassPathName, 729 gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods)); 730} 731