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