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