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