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