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