Bitmap.cpp revision 3d4eed7f1aa99401dabe2e45b82f98fb4fc2d754
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 SkBitmap* bitmap = new SkBitmap; 560 561 bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType), rowBytes); 562 563 SkColorTable* ctable = NULL; 564 if (colorType == kIndex_8_SkColorType) { 565 int count = p->readInt32(); 566 if (count > 0) { 567 size_t size = count * sizeof(SkPMColor); 568 const SkPMColor* src = (const SkPMColor*)p->readInplace(size); 569 ctable = new SkColorTable(src, count); 570 } 571 } 572 573 jbyteArray buffer = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable); 574 if (NULL == buffer) { 575 SkSafeUnref(ctable); 576 delete bitmap; 577 return NULL; 578 } 579 580 SkSafeUnref(ctable); 581 582 size_t size = bitmap->getSize(); 583 584 android::Parcel::ReadableBlob blob; 585 android::status_t status = p->readBlob(size, &blob); 586 if (status) { 587 doThrowRE(env, "Could not read bitmap from parcel blob."); 588 delete bitmap; 589 return NULL; 590 } 591 592 bitmap->lockPixels(); 593 memcpy(bitmap->getPixels(), blob.data(), size); 594 bitmap->unlockPixels(); 595 596 blob.release(); 597 598 return GraphicsJNI::createBitmap(env, bitmap, buffer, getPremulBitmapCreateFlags(isMutable), 599 NULL, NULL, density); 600} 601 602static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, 603 jlong bitmapHandle, 604 jboolean isMutable, jint density, 605 jobject parcel) { 606 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 607 if (parcel == NULL) { 608 SkDebugf("------- writeToParcel null parcel\n"); 609 return JNI_FALSE; 610 } 611 612 android::Parcel* p = android::parcelForJavaObject(env, parcel); 613 614 p->writeInt32(isMutable); 615 p->writeInt32(bitmap->colorType()); 616 p->writeInt32(bitmap->alphaType()); 617 p->writeInt32(bitmap->width()); 618 p->writeInt32(bitmap->height()); 619 p->writeInt32(bitmap->rowBytes()); 620 p->writeInt32(density); 621 622 if (bitmap->colorType() == kIndex_8_SkColorType) { 623 SkColorTable* ctable = bitmap->getColorTable(); 624 if (ctable != NULL) { 625 int count = ctable->count(); 626 p->writeInt32(count); 627 memcpy(p->writeInplace(count * sizeof(SkPMColor)), 628 ctable->readColors(), count * sizeof(SkPMColor)); 629 } else { 630 p->writeInt32(0); // indicate no ctable 631 } 632 } 633 634 size_t size = bitmap->getSize(); 635 636 android::Parcel::WritableBlob blob; 637 android::status_t status = p->writeBlob(size, &blob); 638 if (status) { 639 doThrowRE(env, "Could not write bitmap to parcel blob."); 640 return JNI_FALSE; 641 } 642 643 bitmap->lockPixels(); 644 const void* pSrc = bitmap->getPixels(); 645 if (pSrc == NULL) { 646 memset(blob.data(), 0, size); 647 } else { 648 memcpy(blob.data(), pSrc, size); 649 } 650 bitmap->unlockPixels(); 651 652 blob.release(); 653 return JNI_TRUE; 654} 655 656static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz, 657 jlong srcHandle, jlong paintHandle, 658 jintArray offsetXY) { 659 const SkBitmap* src = reinterpret_cast<SkBitmap*>(srcHandle); 660 const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle); 661 SkIPoint offset; 662 SkBitmap* dst = new SkBitmap; 663 JavaPixelAllocator allocator(env); 664 665 src->extractAlpha(dst, paint, &allocator, &offset); 666 // If Skia can't allocate pixels for destination bitmap, it resets 667 // it, that is set its pixels buffer to NULL, and zero width and height. 668 if (dst->getPixels() == NULL && src->getPixels() != NULL) { 669 delete dst; 670 doThrowOOME(env, "failed to allocate pixels for alpha"); 671 return NULL; 672 } 673 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) { 674 int* array = env->GetIntArrayElements(offsetXY, NULL); 675 array[0] = offset.fX; 676 array[1] = offset.fY; 677 env->ReleaseIntArrayElements(offsetXY, array, 0); 678 } 679 680 return GraphicsJNI::createBitmap(env, dst, allocator.getStorageObj(), 681 getPremulBitmapCreateFlags(true), NULL, NULL); 682} 683 684/////////////////////////////////////////////////////////////////////////////// 685 686static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle, 687 jint x, jint y) { 688 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 689 SkAutoLockPixels alp(*bitmap); 690 691 ToColorProc proc = ChooseToColorProc(*bitmap); 692 if (NULL == proc) { 693 return 0; 694 } 695 const void* src = bitmap->getAddr(x, y); 696 if (NULL == src) { 697 return 0; 698 } 699 700 SkColor dst[1]; 701 proc(dst, src, 1, bitmap->getColorTable()); 702 return static_cast<jint>(dst[0]); 703} 704 705static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle, 706 jintArray pixelArray, jint offset, jint stride, 707 jint x, jint y, jint width, jint height) { 708 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 709 SkAutoLockPixels alp(*bitmap); 710 711 ToColorProc proc = ChooseToColorProc(*bitmap); 712 if (NULL == proc) { 713 return; 714 } 715 const void* src = bitmap->getAddr(x, y); 716 if (NULL == src) { 717 return; 718 } 719 720 SkColorTable* ctable = bitmap->getColorTable(); 721 jint* dst = env->GetIntArrayElements(pixelArray, NULL); 722 SkColor* d = (SkColor*)dst + offset; 723 while (--height >= 0) { 724 proc(d, src, width, ctable); 725 d += stride; 726 src = (void*)((const char*)src + bitmap->rowBytes()); 727 } 728 env->ReleaseIntArrayElements(pixelArray, dst, 0); 729} 730 731/////////////////////////////////////////////////////////////////////////////// 732 733static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle, 734 jint x, jint y, jint colorHandle) { 735 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 736 SkColor color = static_cast<SkColor>(colorHandle); 737 SkAutoLockPixels alp(*bitmap); 738 if (NULL == bitmap->getPixels()) { 739 return; 740 } 741 742 FromColorProc proc = ChooseFromColorProc(*bitmap); 743 if (NULL == proc) { 744 return; 745 } 746 747 proc(bitmap->getAddr(x, y), &color, 1, x, y); 748 bitmap->notifyPixelsChanged(); 749} 750 751static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle, 752 jintArray pixelArray, jint offset, jint stride, 753 jint x, jint y, jint width, jint height) { 754 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 755 GraphicsJNI::SetPixels(env, pixelArray, offset, stride, 756 x, y, width, height, *bitmap); 757} 758 759static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject, 760 jlong bitmapHandle, jobject jbuffer) { 761 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 762 SkAutoLockPixels alp(*bitmap); 763 const void* src = bitmap->getPixels(); 764 765 if (NULL != src) { 766 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE); 767 768 // the java side has already checked that buffer is large enough 769 memcpy(abp.pointer(), src, bitmap->getSize()); 770 } 771} 772 773static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject, 774 jlong bitmapHandle, jobject jbuffer) { 775 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 776 SkAutoLockPixels alp(*bitmap); 777 void* dst = bitmap->getPixels(); 778 779 if (NULL != dst) { 780 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE); 781 // the java side has already checked that buffer is large enough 782 memcpy(dst, abp.pointer(), bitmap->getSize()); 783 bitmap->notifyPixelsChanged(); 784 } 785} 786 787static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle, 788 jlong bm1Handle) { 789 const SkBitmap* bm0 = reinterpret_cast<SkBitmap*>(bm0Handle); 790 const SkBitmap* bm1 = reinterpret_cast<SkBitmap*>(bm1Handle); 791 if (bm0->width() != bm1->width() || 792 bm0->height() != bm1->height() || 793 bm0->colorType() != bm1->colorType()) { 794 return JNI_FALSE; 795 } 796 797 SkAutoLockPixels alp0(*bm0); 798 SkAutoLockPixels alp1(*bm1); 799 800 // if we can't load the pixels, return false 801 if (NULL == bm0->getPixels() || NULL == bm1->getPixels()) { 802 return JNI_FALSE; 803 } 804 805 if (bm0->colorType() == kIndex_8_SkColorType) { 806 SkColorTable* ct0 = bm0->getColorTable(); 807 SkColorTable* ct1 = bm1->getColorTable(); 808 if (NULL == ct0 || NULL == ct1) { 809 return JNI_FALSE; 810 } 811 if (ct0->count() != ct1->count()) { 812 return JNI_FALSE; 813 } 814 815 const size_t size = ct0->count() * sizeof(SkPMColor); 816 if (memcmp(ct0->readColors(), ct1->readColors(), size) != 0) { 817 return JNI_FALSE; 818 } 819 } 820 821 // now compare each scanline. We can't do the entire buffer at once, 822 // since we don't care about the pixel values that might extend beyond 823 // the width (since the scanline might be larger than the logical width) 824 const int h = bm0->height(); 825 const size_t size = bm0->width() * bm0->bytesPerPixel(); 826 for (int y = 0; y < h; y++) { 827 // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config 828 // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0 829 // and bm1 both have pixel data() (have passed NULL == getPixels() check), 830 // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE 831 // to warn user those 2 unrecognized config bitmaps may be different. 832 void *bm0Addr = bm0->getAddr(0, y); 833 void *bm1Addr = bm1->getAddr(0, y); 834 835 if(bm0Addr == NULL || bm1Addr == NULL) { 836 return JNI_FALSE; 837 } 838 839 if (memcmp(bm0Addr, bm1Addr, size) != 0) { 840 return JNI_FALSE; 841 } 842 } 843 return JNI_TRUE; 844} 845 846static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapHandle) { 847 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 848 bitmap->lockPixels(); 849 bitmap->unlockPixels(); 850} 851 852/////////////////////////////////////////////////////////////////////////////// 853 854static JNINativeMethod gBitmapMethods[] = { 855 { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;", 856 (void*)Bitmap_creator }, 857 { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;", 858 (void*)Bitmap_copy }, 859 { "nativeDestructor", "(J)V", (void*)Bitmap_destructor }, 860 { "nativeRecycle", "(J)Z", (void*)Bitmap_recycle }, 861 { "nativeReconfigure", "(JIIIIZ)V", (void*)Bitmap_reconfigure }, 862 { "nativeCompress", "(JIILjava/io/OutputStream;[B)Z", 863 (void*)Bitmap_compress }, 864 { "nativeErase", "(JI)V", (void*)Bitmap_erase }, 865 { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes }, 866 { "nativeConfig", "(J)I", (void*)Bitmap_config }, 867 { "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha }, 868 { "nativeIsPremultiplied", "(J)Z", (void*)Bitmap_isPremultiplied}, 869 { "nativeSetHasAlpha", "(JZZ)V", (void*)Bitmap_setHasAlpha}, 870 { "nativeSetPremultiplied", "(JZ)V", (void*)Bitmap_setPremultiplied}, 871 { "nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap }, 872 { "nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap }, 873 { "nativeCreateFromParcel", 874 "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;", 875 (void*)Bitmap_createFromParcel }, 876 { "nativeWriteToParcel", "(JZILandroid/os/Parcel;)Z", 877 (void*)Bitmap_writeToParcel }, 878 { "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;", 879 (void*)Bitmap_extractAlpha }, 880 { "nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId }, 881 { "nativeGetPixel", "(JII)I", (void*)Bitmap_getPixel }, 882 { "nativeGetPixels", "(J[IIIIIII)V", (void*)Bitmap_getPixels }, 883 { "nativeSetPixel", "(JIII)V", (void*)Bitmap_setPixel }, 884 { "nativeSetPixels", "(J[IIIIIII)V", (void*)Bitmap_setPixels }, 885 { "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V", 886 (void*)Bitmap_copyPixelsToBuffer }, 887 { "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V", 888 (void*)Bitmap_copyPixelsFromBuffer }, 889 { "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs }, 890 { "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw }, 891}; 892 893int register_android_graphics_Bitmap(JNIEnv* env) 894{ 895 return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods, 896 NELEM(gBitmapMethods)); 897} 898