Bitmap.cpp revision 53fc3cdd5ce88ff6e8c3e7d5eca6c90cb72ea9f8
1#define LOG_TAG "Bitmap" 2#include "Bitmap.h" 3 4#include "GraphicBuffer.h" 5#include "SkBitmap.h" 6#include "SkPixelRef.h" 7#include "SkImageEncoder.h" 8#include "SkImageInfo.h" 9#include "SkColor.h" 10#include "SkColorPriv.h" 11#include "SkHalf.h" 12#include "SkPM4f.h" 13#include "SkPM4fPriv.h" 14#include "GraphicsJNI.h" 15#include "SkDither.h" 16#include "SkUnPreMultiply.h" 17#include "SkStream.h" 18 19#include <binder/Parcel.h> 20#include "android_os_Parcel.h" 21#include "android_util_Binder.h" 22#include "android_nio_utils.h" 23#include "CreateJavaOutputStreamAdaptor.h" 24#include <hwui/Paint.h> 25#include <hwui/Bitmap.h> 26#include <renderthread/RenderProxy.h> 27 28#include "core_jni_helpers.h" 29 30#include <jni.h> 31#include <memory> 32#include <string> 33 34#define DEBUG_PARCEL 0 35#define ASHMEM_BITMAP_MIN_SIZE (128 * (1 << 10)) 36 37static jclass gBitmap_class; 38static jfieldID gBitmap_nativePtr; 39static jmethodID gBitmap_constructorMethodID; 40static jmethodID gBitmap_reinitMethodID; 41static jmethodID gBitmap_getAllocationByteCountMethodID; 42 43namespace android { 44 45class BitmapWrapper { 46public: 47 BitmapWrapper(Bitmap* bitmap) 48 : mBitmap(bitmap) { } 49 50 void freePixels() { 51 mInfo = mBitmap->info(); 52 mHasHardwareMipMap = mBitmap->hasHardwareMipMap(); 53 mAllocationSize = mBitmap->getAllocationByteCount(); 54 mRowBytes = mBitmap->rowBytes(); 55 mGenerationId = mBitmap->getGenerationID(); 56 mIsHardware = mBitmap->isHardware(); 57 mBitmap.reset(); 58 } 59 60 bool valid() { 61 return mBitmap; 62 } 63 64 Bitmap& bitmap() { 65 assertValid(); 66 return *mBitmap; 67 } 68 69 void assertValid() { 70 LOG_ALWAYS_FATAL_IF(!valid(), "Error, cannot access an invalid/free'd bitmap here!"); 71 } 72 73 void getSkBitmap(SkBitmap* outBitmap) { 74 assertValid(); 75 mBitmap->getSkBitmap(outBitmap); 76 } 77 78 bool hasHardwareMipMap() { 79 if (mBitmap) { 80 return mBitmap->hasHardwareMipMap(); 81 } 82 return mHasHardwareMipMap; 83 } 84 85 void setHasHardwareMipMap(bool hasMipMap) { 86 assertValid(); 87 mBitmap->setHasHardwareMipMap(hasMipMap); 88 } 89 90 void setAlphaType(SkAlphaType alphaType) { 91 assertValid(); 92 mBitmap->setAlphaType(alphaType); 93 } 94 95 const SkImageInfo& info() { 96 if (mBitmap) { 97 return mBitmap->info(); 98 } 99 return mInfo; 100 } 101 102 size_t getAllocationByteCount() const { 103 if (mBitmap) { 104 return mBitmap->getAllocationByteCount(); 105 } 106 return mAllocationSize; 107 } 108 109 size_t rowBytes() const { 110 if (mBitmap) { 111 return mBitmap->rowBytes(); 112 } 113 return mRowBytes; 114 } 115 116 uint32_t getGenerationID() const { 117 if (mBitmap) { 118 return mBitmap->getGenerationID(); 119 } 120 return mGenerationId; 121 } 122 123 bool isHardware() { 124 if (mBitmap) { 125 return mBitmap->isHardware(); 126 } 127 return mIsHardware; 128 } 129 130 ~BitmapWrapper() { } 131 132private: 133 sk_sp<Bitmap> mBitmap; 134 SkImageInfo mInfo; 135 bool mHasHardwareMipMap; 136 size_t mAllocationSize; 137 size_t mRowBytes; 138 uint32_t mGenerationId; 139 bool mIsHardware; 140}; 141 142// Convenience class that does not take a global ref on the pixels, relying 143// on the caller already having a local JNI ref 144class LocalScopedBitmap { 145public: 146 explicit LocalScopedBitmap(jlong bitmapHandle) 147 : mBitmapWrapper(reinterpret_cast<BitmapWrapper*>(bitmapHandle)) {} 148 149 BitmapWrapper* operator->() { 150 return mBitmapWrapper; 151 } 152 153 void* pixels() { 154 return mBitmapWrapper->bitmap().pixels(); 155 } 156 157 bool valid() { 158 return mBitmapWrapper && mBitmapWrapper->valid(); 159 } 160 161private: 162 BitmapWrapper* mBitmapWrapper; 163}; 164 165namespace bitmap { 166 167// Assert that bitmap's SkAlphaType is consistent with isPremultiplied. 168static void assert_premultiplied(const SkImageInfo& info, bool isPremultiplied) { 169 // kOpaque_SkAlphaType and kIgnore_SkAlphaType mean that isPremultiplied is 170 // irrelevant. This just tests to ensure that the SkAlphaType is not 171 // opposite of isPremultiplied. 172 if (isPremultiplied) { 173 SkASSERT(info.alphaType() != kUnpremul_SkAlphaType); 174 } else { 175 SkASSERT(info.alphaType() != kPremul_SkAlphaType); 176 } 177} 178 179void reinitBitmap(JNIEnv* env, jobject javaBitmap, const SkImageInfo& info, 180 bool isPremultiplied) 181{ 182 // The caller needs to have already set the alpha type properly, so the 183 // native SkBitmap stays in sync with the Java Bitmap. 184 assert_premultiplied(info, isPremultiplied); 185 186 env->CallVoidMethod(javaBitmap, gBitmap_reinitMethodID, 187 info.width(), info.height(), isPremultiplied); 188} 189 190int getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap) 191{ 192 return env->CallIntMethod(javaBitmap, gBitmap_getAllocationByteCountMethodID); 193} 194 195jobject createBitmap(JNIEnv* env, Bitmap* bitmap, 196 int bitmapCreateFlags, jbyteArray ninePatchChunk, jobject ninePatchInsets, 197 int density) { 198 bool isMutable = bitmapCreateFlags & kBitmapCreateFlag_Mutable; 199 bool isPremultiplied = bitmapCreateFlags & kBitmapCreateFlag_Premultiplied; 200 // The caller needs to have already set the alpha type properly, so the 201 // native SkBitmap stays in sync with the Java Bitmap. 202 assert_premultiplied(bitmap->info(), isPremultiplied); 203 BitmapWrapper* bitmapWrapper = new BitmapWrapper(bitmap); 204 jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID, 205 reinterpret_cast<jlong>(bitmapWrapper), bitmap->width(), bitmap->height(), density, 206 isMutable, isPremultiplied, ninePatchChunk, ninePatchInsets); 207 208 if (env->ExceptionCheck() != 0) { 209 ALOGE("*** Uncaught exception returned from Java call!\n"); 210 env->ExceptionDescribe(); 211 } 212 return obj; 213} 214 215void toSkBitmap(jlong bitmapHandle, SkBitmap* outBitmap) { 216 LocalScopedBitmap bitmap(bitmapHandle); 217 bitmap->getSkBitmap(outBitmap); 218} 219 220Bitmap& toBitmap(JNIEnv* env, jobject bitmap) { 221 SkASSERT(env); 222 SkASSERT(bitmap); 223 SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class)); 224 jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr); 225 LocalScopedBitmap localBitmap(bitmapHandle); 226 return localBitmap->bitmap(); 227} 228 229Bitmap& toBitmap(JNIEnv* env, jlong bitmapHandle) { 230 SkASSERT(env); 231 LocalScopedBitmap localBitmap(bitmapHandle); 232 return localBitmap->bitmap(); 233} 234 235void imageInfo(JNIEnv* env, jobject bitmap, AndroidBitmapInfo* info) { 236 SkASSERT(info); 237 SkASSERT(env); 238 SkASSERT(bitmap); 239 SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class)); 240 jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr); 241 LocalScopedBitmap localBitmap(bitmapHandle); 242 243 const SkImageInfo& imageInfo = localBitmap->info(); 244 info->width = imageInfo.width(); 245 info->height = imageInfo.height(); 246 info->stride = localBitmap->rowBytes(); 247 info->flags = 0; 248 switch (imageInfo.colorType()) { 249 case kN32_SkColorType: 250 info->format = ANDROID_BITMAP_FORMAT_RGBA_8888; 251 break; 252 case kRGB_565_SkColorType: 253 info->format = ANDROID_BITMAP_FORMAT_RGB_565; 254 break; 255 case kARGB_4444_SkColorType: 256 info->format = ANDROID_BITMAP_FORMAT_RGBA_4444; 257 break; 258 case kAlpha_8_SkColorType: 259 info->format = ANDROID_BITMAP_FORMAT_A_8; 260 break; 261 default: 262 info->format = ANDROID_BITMAP_FORMAT_NONE; 263 break; 264 } 265} 266 267void* lockPixels(JNIEnv* env, jobject bitmap) { 268 SkASSERT(env); 269 SkASSERT(bitmap); 270 SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class)); 271 jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr); 272 273 LocalScopedBitmap localBitmap(bitmapHandle); 274 if (!localBitmap->valid()) return nullptr; 275 276 SkPixelRef& pixelRef = localBitmap->bitmap(); 277 pixelRef.lockPixels(); 278 if (!pixelRef.pixels()) { 279 pixelRef.unlockPixels(); 280 return nullptr; 281 } 282 pixelRef.ref(); 283 return pixelRef.pixels(); 284} 285 286bool unlockPixels(JNIEnv* env, jobject bitmap) { 287 SkASSERT(env); 288 SkASSERT(bitmap); 289 SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class)); 290 jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr); 291 292 LocalScopedBitmap localBitmap(bitmapHandle); 293 if (!localBitmap->valid()) return false; 294 295 SkPixelRef& pixelRef = localBitmap->bitmap(); 296 pixelRef.notifyPixelsChanged(); 297 pixelRef.unlockPixels(); 298 pixelRef.unref(); 299 return true; 300} 301 302} // namespace bitmap 303 304} // namespace android 305 306using namespace android; 307using namespace android::bitmap; 308 309/////////////////////////////////////////////////////////////////////////////// 310// Conversions to/from SkColor, for get/setPixels, and the create method, which 311// is basically like setPixels 312 313typedef void (*FromColorProc)(void* dst, const SkColor src[], int width, 314 int x, int y); 315 316static void FromColor_F16(void* dst, const SkColor src[], int width, 317 int, int) { 318 uint64_t* d = (uint64_t*)dst; 319 320 for (int i = 0; i < width; i++) { 321 *d++ = SkColor4f::FromColor(*src++).premul().toF16(); 322 } 323} 324 325static void FromColor_F16_Raw(void* dst, const SkColor src[], int width, 326 int, int) { 327 uint64_t* d = (uint64_t*)dst; 328 329 for (int i = 0; i < width; i++) { 330 const float* color = SkColor4f::FromColor(*src++).vec(); 331 uint16_t* scratch = reinterpret_cast<uint16_t*>(d++); 332 for (int i = 0; i < 4; ++i) { 333 scratch[i] = SkFloatToHalf(color[i]); 334 } 335 } 336} 337 338static void FromColor_D32(void* dst, const SkColor src[], int width, 339 int, int) { 340 SkPMColor* d = (SkPMColor*)dst; 341 342 for (int i = 0; i < width; i++) { 343 *d++ = SkPreMultiplyColor(*src++); 344 } 345} 346 347static void FromColor_D32_Raw(void* dst, const SkColor src[], int width, 348 int, int) { 349 // Needed to thwart the unreachable code detection from clang. 350 static const bool sk_color_ne_zero = SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER; 351 352 // SkColor's ordering may be different from SkPMColor 353 if (sk_color_ne_zero) { 354 memcpy(dst, src, width * sizeof(SkColor)); 355 return; 356 } 357 358 // order isn't same, repack each pixel manually 359 SkPMColor* d = (SkPMColor*)dst; 360 for (int i = 0; i < width; i++) { 361 SkColor c = *src++; 362 *d++ = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c), 363 SkColorGetG(c), SkColorGetB(c)); 364 } 365} 366 367static void FromColor_D565(void* dst, const SkColor src[], int width, 368 int x, int y) { 369 uint16_t* d = (uint16_t*)dst; 370 371 DITHER_565_SCAN(y); 372 for (int stop = x + width; x < stop; x++) { 373 SkColor c = *src++; 374 *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c), 375 DITHER_VALUE(x)); 376 } 377} 378 379static void FromColor_D4444(void* dst, const SkColor src[], int width, 380 int x, int y) { 381 SkPMColor16* d = (SkPMColor16*)dst; 382 383 DITHER_4444_SCAN(y); 384 for (int stop = x + width; x < stop; x++) { 385 SkPMColor pmc = SkPreMultiplyColor(*src++); 386 *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x)); 387// *d++ = SkPixel32ToPixel4444(pmc); 388 } 389} 390 391static void FromColor_D4444_Raw(void* dst, const SkColor src[], int width, 392 int x, int y) { 393 SkPMColor16* d = (SkPMColor16*)dst; 394 395 DITHER_4444_SCAN(y); 396 for (int stop = x + width; x < stop; x++) { 397 SkColor c = *src++; 398 399 // SkPMColor is used because the ordering is ARGB32, even though the target actually premultiplied 400 SkPMColor pmc = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c), 401 SkColorGetG(c), SkColorGetB(c)); 402 *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x)); 403// *d++ = SkPixel32ToPixel4444(pmc); 404 } 405} 406 407static void FromColor_DA8(void* dst, const SkColor src[], int width, int x, int y) { 408 uint8_t* d = (uint8_t*)dst; 409 410 for (int stop = x + width; x < stop; x++) { 411 *d++ = SkColorGetA(*src++); 412 } 413} 414 415// can return NULL 416static FromColorProc ChooseFromColorProc(const SkBitmap& bitmap) { 417 switch (bitmap.colorType()) { 418 case kN32_SkColorType: 419 return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D32 : FromColor_D32_Raw; 420 case kARGB_4444_SkColorType: 421 return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D4444 : 422 FromColor_D4444_Raw; 423 case kRGB_565_SkColorType: 424 return FromColor_D565; 425 case kAlpha_8_SkColorType: 426 return FromColor_DA8; 427 case kRGBA_F16_SkColorType: 428 return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_F16 : FromColor_F16_Raw; 429 default: 430 break; 431 } 432 return NULL; 433} 434 435bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride, 436 int x, int y, int width, int height, const SkBitmap& dstBitmap) { 437 SkAutoLockPixels alp(dstBitmap); 438 void* dst = dstBitmap.getPixels(); 439 FromColorProc proc = ChooseFromColorProc(dstBitmap); 440 441 if (NULL == dst || NULL == proc) { 442 return false; 443 } 444 445 const jint* array = env->GetIntArrayElements(srcColors, NULL); 446 const SkColor* src = (const SkColor*)array + srcOffset; 447 448 // reset to to actual choice from caller 449 dst = dstBitmap.getAddr(x, y); 450 // now copy/convert each scanline 451 for (int y = 0; y < height; y++) { 452 proc(dst, src, width, x, y); 453 src += srcStride; 454 dst = (char*)dst + dstBitmap.rowBytes(); 455 } 456 457 dstBitmap.notifyPixelsChanged(); 458 459 env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array), JNI_ABORT); 460 return true; 461} 462 463//////////////////// ToColor procs 464 465typedef void (*ToColorProc)(SkColor dst[], const void* src, int width, 466 SkColorTable*); 467 468static void ToColor_F16_Alpha(SkColor dst[], const void* src, int width, 469 SkColorTable*) { 470 SkASSERT(width > 0); 471 uint64_t* s = (uint64_t*)src; 472 do { 473 *dst++ = SkPM4f::FromF16((const uint16_t*) s++).unpremul().toSkColor(); 474 } while (--width != 0); 475} 476 477static void ToColor_F16_Raw(SkColor dst[], const void* src, int width, 478 SkColorTable*) { 479 SkASSERT(width > 0); 480 uint64_t* s = (uint64_t*)src; 481 do { 482 *dst++ = Sk4f_toS32(swizzle_rb(SkHalfToFloat_finite_ftz(*s++))); 483 } while (--width != 0); 484} 485 486static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width, 487 SkColorTable*) { 488 SkASSERT(width > 0); 489 const SkPMColor* s = (const SkPMColor*)src; 490 do { 491 *dst++ = SkUnPreMultiply::PMColorToColor(*s++); 492 } while (--width != 0); 493} 494 495static void ToColor_S32_Raw(SkColor dst[], const void* src, int width, 496 SkColorTable*) { 497 SkASSERT(width > 0); 498 const SkPMColor* s = (const SkPMColor*)src; 499 do { 500 SkPMColor c = *s++; 501 *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c), 502 SkGetPackedG32(c), SkGetPackedB32(c)); 503 } while (--width != 0); 504} 505 506static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width, 507 SkColorTable*) { 508 SkASSERT(width > 0); 509 const SkPMColor* s = (const SkPMColor*)src; 510 do { 511 SkPMColor c = *s++; 512 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c), 513 SkGetPackedB32(c)); 514 } while (--width != 0); 515} 516 517static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width, 518 SkColorTable*) { 519 SkASSERT(width > 0); 520 const SkPMColor16* s = (const SkPMColor16*)src; 521 do { 522 *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++)); 523 } while (--width != 0); 524} 525 526static void ToColor_S4444_Raw(SkColor dst[], const void* src, int width, 527 SkColorTable*) { 528 SkASSERT(width > 0); 529 const SkPMColor16* s = (const SkPMColor16*)src; 530 do { 531 SkPMColor c = SkPixel4444ToPixel32(*s++); 532 *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c), 533 SkGetPackedG32(c), SkGetPackedB32(c)); 534 } while (--width != 0); 535} 536 537static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width, 538 SkColorTable*) { 539 SkASSERT(width > 0); 540 const SkPMColor16* s = (const SkPMColor16*)src; 541 do { 542 SkPMColor c = SkPixel4444ToPixel32(*s++); 543 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c), 544 SkGetPackedB32(c)); 545 } while (--width != 0); 546} 547 548static void ToColor_S565(SkColor dst[], const void* src, int width, 549 SkColorTable*) { 550 SkASSERT(width > 0); 551 const uint16_t* s = (const uint16_t*)src; 552 do { 553 uint16_t c = *s++; 554 *dst++ = SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c), 555 SkPacked16ToB32(c)); 556 } while (--width != 0); 557} 558 559static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width, 560 SkColorTable* ctable) { 561 SkASSERT(width > 0); 562 const uint8_t* s = (const uint8_t*)src; 563 const SkPMColor* colors = ctable->readColors(); 564 do { 565 *dst++ = SkUnPreMultiply::PMColorToColor(colors[*s++]); 566 } while (--width != 0); 567} 568 569static void ToColor_SI8_Raw(SkColor dst[], const void* src, int width, 570 SkColorTable* ctable) { 571 SkASSERT(width > 0); 572 const uint8_t* s = (const uint8_t*)src; 573 const SkPMColor* colors = ctable->readColors(); 574 do { 575 SkPMColor c = colors[*s++]; 576 *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c), 577 SkGetPackedG32(c), SkGetPackedB32(c)); 578 } while (--width != 0); 579} 580 581static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width, 582 SkColorTable* ctable) { 583 SkASSERT(width > 0); 584 const uint8_t* s = (const uint8_t*)src; 585 const SkPMColor* colors = ctable->readColors(); 586 do { 587 SkPMColor c = colors[*s++]; 588 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c), 589 SkGetPackedB32(c)); 590 } while (--width != 0); 591} 592 593static void ToColor_SA8(SkColor dst[], const void* src, int width, SkColorTable*) { 594 SkASSERT(width > 0); 595 const uint8_t* s = (const uint8_t*)src; 596 do { 597 uint8_t c = *s++; 598 *dst++ = SkColorSetARGB(c, c, c, c); 599 } while (--width != 0); 600} 601 602// can return NULL 603static ToColorProc ChooseToColorProc(const SkBitmap& src) { 604 switch (src.colorType()) { 605 case kN32_SkColorType: 606 switch (src.alphaType()) { 607 case kOpaque_SkAlphaType: 608 return ToColor_S32_Opaque; 609 case kPremul_SkAlphaType: 610 return ToColor_S32_Alpha; 611 case kUnpremul_SkAlphaType: 612 return ToColor_S32_Raw; 613 default: 614 return NULL; 615 } 616 case kARGB_4444_SkColorType: 617 switch (src.alphaType()) { 618 case kOpaque_SkAlphaType: 619 return ToColor_S4444_Opaque; 620 case kPremul_SkAlphaType: 621 return ToColor_S4444_Alpha; 622 case kUnpremul_SkAlphaType: 623 return ToColor_S4444_Raw; 624 default: 625 return NULL; 626 } 627 case kRGB_565_SkColorType: 628 return ToColor_S565; 629 case kIndex_8_SkColorType: 630 if (src.getColorTable() == NULL) { 631 return NULL; 632 } 633 switch (src.alphaType()) { 634 case kOpaque_SkAlphaType: 635 return ToColor_SI8_Opaque; 636 case kPremul_SkAlphaType: 637 return ToColor_SI8_Alpha; 638 case kUnpremul_SkAlphaType: 639 return ToColor_SI8_Raw; 640 default: 641 return NULL; 642 } 643 case kAlpha_8_SkColorType: 644 return ToColor_SA8; 645 case kRGBA_F16_SkColorType: 646 switch (src.alphaType()) { 647 case kOpaque_SkAlphaType: 648 return ToColor_F16_Raw; 649 case kPremul_SkAlphaType: 650 return ToColor_F16_Alpha; 651 case kUnpremul_SkAlphaType: 652 return ToColor_F16_Raw; 653 default: 654 return NULL; 655 } 656 default: 657 break; 658 } 659 return NULL; 660} 661 662/////////////////////////////////////////////////////////////////////////////// 663/////////////////////////////////////////////////////////////////////////////// 664 665static int getPremulBitmapCreateFlags(bool isMutable) { 666 int flags = android::bitmap::kBitmapCreateFlag_Premultiplied; 667 if (isMutable) flags |= android::bitmap::kBitmapCreateFlag_Mutable; 668 return flags; 669} 670 671static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors, 672 jint offset, jint stride, jint width, jint height, 673 jint configHandle, jboolean isMutable) { 674 SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle); 675 if (NULL != jColors) { 676 size_t n = env->GetArrayLength(jColors); 677 if (n < SkAbs32(stride) * (size_t)height) { 678 doThrowAIOOBE(env); 679 return NULL; 680 } 681 } 682 683 // ARGB_4444 is a deprecated format, convert automatically to 8888 684 if (colorType == kARGB_4444_SkColorType) { 685 colorType = kN32_SkColorType; 686 } 687 688 SkBitmap bitmap; 689 bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType, 690 GraphicsJNI::colorSpaceForType(colorType))); 691 692 sk_sp<Bitmap> nativeBitmap = Bitmap::allocateHeapBitmap(&bitmap, NULL); 693 if (!nativeBitmap) { 694 return NULL; 695 } 696 697 if (jColors != NULL) { 698 GraphicsJNI::SetPixels(env, jColors, offset, stride, 0, 0, width, height, bitmap); 699 } 700 701 return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable)); 702} 703 704static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle, 705 jint dstConfigHandle, jboolean isMutable) { 706 SkBitmap src; 707 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src); 708 if (dstConfigHandle == GraphicsJNI::hardwareLegacyBitmapConfig()) { 709 sk_sp<Bitmap> bitmap(Bitmap::allocateHardwareBitmap(src)); 710 if (!bitmap.get()) { 711 return NULL; 712 } 713 return createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(isMutable)); 714 } 715 716 SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle); 717 SkBitmap result; 718 HeapAllocator allocator; 719 720 if (!src.copyTo(&result, dstCT, &allocator)) { 721 return NULL; 722 } 723 auto bitmap = allocator.getStorageObjAndReset(); 724 return createBitmap(env, bitmap, getPremulBitmapCreateFlags(isMutable)); 725} 726 727static Bitmap* Bitmap_copyAshmemImpl(JNIEnv* env, SkBitmap& src, SkColorType& dstCT) { 728 SkBitmap result; 729 730 AshmemPixelAllocator allocator(env); 731 if (!src.copyTo(&result, dstCT, &allocator)) { 732 return NULL; 733 } 734 auto bitmap = allocator.getStorageObjAndReset(); 735 bitmap->setImmutable(); 736 return bitmap; 737} 738 739static jobject Bitmap_copyAshmem(JNIEnv* env, jobject, jlong srcHandle) { 740 SkBitmap src; 741 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src); 742 SkColorType dstCT = src.colorType(); 743 auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT); 744 jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false)); 745 return ret; 746} 747 748static jobject Bitmap_copyAshmemConfig(JNIEnv* env, jobject, jlong srcHandle, jint dstConfigHandle) { 749 SkBitmap src; 750 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src); 751 SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle); 752 auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT); 753 jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false)); 754 return ret; 755} 756 757static void Bitmap_destruct(BitmapWrapper* bitmap) { 758 delete bitmap; 759} 760 761static jlong Bitmap_getNativeFinalizer(JNIEnv*, jobject) { 762 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Bitmap_destruct)); 763} 764 765static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) { 766 LocalScopedBitmap bitmap(bitmapHandle); 767 bitmap->freePixels(); 768 return JNI_TRUE; 769} 770 771static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle, 772 jint width, jint height, jint configHandle, jboolean requestPremul) { 773 LocalScopedBitmap bitmap(bitmapHandle); 774 bitmap->assertValid(); 775 SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle); 776 777 // ARGB_4444 is a deprecated format, convert automatically to 8888 778 if (colorType == kARGB_4444_SkColorType) { 779 colorType = kN32_SkColorType; 780 } 781 size_t requestedSize = width * height * SkColorTypeBytesPerPixel(colorType); 782 if (requestedSize > bitmap->getAllocationByteCount()) { 783 // done in native as there's no way to get BytesPerPixel in Java 784 doThrowIAE(env, "Bitmap not large enough to support new configuration"); 785 return; 786 } 787 SkAlphaType alphaType; 788 if (bitmap->info().colorType() != kRGB_565_SkColorType 789 && bitmap->info().alphaType() == kOpaque_SkAlphaType) { 790 // If the original bitmap was set to opaque, keep that setting, unless it 791 // was 565, which is required to be opaque. 792 alphaType = kOpaque_SkAlphaType; 793 } else { 794 // Otherwise respect the premultiplied request. 795 alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType; 796 } 797 bitmap->bitmap().reconfigure(SkImageInfo::Make(width, height, colorType, alphaType, 798 sk_ref_sp(bitmap->info().colorSpace()))); 799} 800 801// These must match the int values in Bitmap.java 802enum JavaEncodeFormat { 803 kJPEG_JavaEncodeFormat = 0, 804 kPNG_JavaEncodeFormat = 1, 805 kWEBP_JavaEncodeFormat = 2 806}; 807 808static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle, 809 jint format, jint quality, 810 jobject jstream, jbyteArray jstorage) { 811 SkEncodedImageFormat fm; 812 switch (format) { 813 case kJPEG_JavaEncodeFormat: 814 fm = SkEncodedImageFormat::kJPEG; 815 break; 816 case kPNG_JavaEncodeFormat: 817 fm = SkEncodedImageFormat::kPNG; 818 break; 819 case kWEBP_JavaEncodeFormat: 820 fm = SkEncodedImageFormat::kWEBP; 821 break; 822 default: 823 return JNI_FALSE; 824 } 825 826 LocalScopedBitmap bitmap(bitmapHandle); 827 if (!bitmap.valid()) { 828 return JNI_FALSE; 829 } 830 831 std::unique_ptr<SkWStream> strm(CreateJavaOutputStreamAdaptor(env, jstream, jstorage)); 832 if (!strm.get()) { 833 return JNI_FALSE; 834 } 835 836 SkBitmap skbitmap; 837 bitmap->getSkBitmap(&skbitmap); 838 return SkEncodeImage(strm.get(), skbitmap, fm, quality) ? JNI_TRUE : JNI_FALSE; 839} 840 841static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) { 842 LocalScopedBitmap bitmap(bitmapHandle); 843 SkBitmap skBitmap; 844 bitmap->getSkBitmap(&skBitmap); 845 skBitmap.eraseColor(color); 846} 847 848static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) { 849 LocalScopedBitmap bitmap(bitmapHandle); 850 return static_cast<jint>(bitmap->rowBytes()); 851} 852 853static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) { 854 LocalScopedBitmap bitmap(bitmapHandle); 855 if (bitmap->isHardware()) { 856 return GraphicsJNI::hardwareLegacyBitmapConfig(); 857 } 858 return GraphicsJNI::colorTypeToLegacyBitmapConfig(bitmap->info().colorType()); 859} 860 861static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) { 862 LocalScopedBitmap bitmap(bitmapHandle); 863 return static_cast<jint>(bitmap->getGenerationID()); 864} 865 866static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) { 867 LocalScopedBitmap bitmap(bitmapHandle); 868 if (bitmap->info().alphaType() == kPremul_SkAlphaType) { 869 return JNI_TRUE; 870 } 871 return JNI_FALSE; 872} 873 874static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) { 875 LocalScopedBitmap bitmap(bitmapHandle); 876 return !bitmap->info().isOpaque() ? JNI_TRUE : JNI_FALSE; 877} 878 879static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle, 880 jboolean hasAlpha, jboolean requestPremul) { 881 LocalScopedBitmap bitmap(bitmapHandle); 882 if (hasAlpha) { 883 bitmap->setAlphaType( 884 requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType); 885 } else { 886 bitmap->setAlphaType(kOpaque_SkAlphaType); 887 } 888} 889 890static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle, 891 jboolean isPremul) { 892 LocalScopedBitmap bitmap(bitmapHandle); 893 if (!bitmap->info().isOpaque()) { 894 if (isPremul) { 895 bitmap->setAlphaType(kPremul_SkAlphaType); 896 } else { 897 bitmap->setAlphaType(kUnpremul_SkAlphaType); 898 } 899 } 900} 901 902static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) { 903 LocalScopedBitmap bitmap(bitmapHandle); 904 return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE; 905} 906 907static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle, 908 jboolean hasMipMap) { 909 LocalScopedBitmap bitmap(bitmapHandle); 910 bitmap->setHasHardwareMipMap(hasMipMap); 911} 912 913/////////////////////////////////////////////////////////////////////////////// 914 915static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { 916 if (parcel == NULL) { 917 SkDebugf("-------- unparcel parcel is NULL\n"); 918 return NULL; 919 } 920 921 android::Parcel* p = android::parcelForJavaObject(env, parcel); 922 923 const bool isMutable = p->readInt32() != 0; 924 const SkColorType colorType = (SkColorType)p->readInt32(); 925 const SkAlphaType alphaType = (SkAlphaType)p->readInt32(); 926 const bool isSRGB = p->readInt32() != 0; 927 const int width = p->readInt32(); 928 const int height = p->readInt32(); 929 const int rowBytes = p->readInt32(); 930 const int density = p->readInt32(); 931 932 if (kN32_SkColorType != colorType && 933 kRGBA_F16_SkColorType != colorType && 934 kRGB_565_SkColorType != colorType && 935 kARGB_4444_SkColorType != colorType && 936 kIndex_8_SkColorType != colorType && 937 kAlpha_8_SkColorType != colorType) { 938 SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType); 939 return NULL; 940 } 941 942 std::unique_ptr<SkBitmap> bitmap(new SkBitmap); 943 944 sk_sp<SkColorSpace> colorSpace; 945 if (kRGBA_F16_SkColorType == colorType) { 946 colorSpace = SkColorSpace::MakeSRGBLinear(); 947 } else { 948 colorSpace = isSRGB ? SkColorSpace::MakeSRGB() : nullptr; 949 } 950 951 if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType, colorSpace), 952 rowBytes)) { 953 return NULL; 954 } 955 956 SkColorTable* ctable = NULL; 957 if (colorType == kIndex_8_SkColorType) { 958 int count = p->readInt32(); 959 if (count < 0 || count > 256) { 960 // The data is corrupt, since SkColorTable enforces a value between 0 and 256, 961 // inclusive. 962 return NULL; 963 } 964 if (count > 0) { 965 size_t size = count * sizeof(SkPMColor); 966 const SkPMColor* src = (const SkPMColor*)p->readInplace(size); 967 if (src == NULL) { 968 return NULL; 969 } 970 ctable = new SkColorTable(src, count); 971 } 972 } 973 974 // Read the bitmap blob. 975 size_t size = bitmap->getSize(); 976 android::Parcel::ReadableBlob blob; 977 android::status_t status = p->readBlob(size, &blob); 978 if (status) { 979 SkSafeUnref(ctable); 980 doThrowRE(env, "Could not read bitmap blob."); 981 return NULL; 982 } 983 984 // Map the bitmap in place from the ashmem region if possible otherwise copy. 985 sk_sp<Bitmap> nativeBitmap; 986 if (blob.fd() >= 0 && (blob.isMutable() || !isMutable) && (size >= ASHMEM_BITMAP_MIN_SIZE)) { 987#if DEBUG_PARCEL 988 ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob " 989 "(fds %s)", 990 isMutable ? "mutable" : "immutable", 991 blob.isMutable() ? "mutable" : "immutable", 992 p->allowFds() ? "allowed" : "forbidden"); 993#endif 994 // Dup the file descriptor so we can keep a reference to it after the Parcel 995 // is disposed. 996 int dupFd = dup(blob.fd()); 997 if (dupFd < 0) { 998 ALOGE("Error allocating dup fd. Error:%d", errno); 999 blob.release(); 1000 SkSafeUnref(ctable); 1001 doThrowRE(env, "Could not allocate dup blob fd."); 1002 return NULL; 1003 } 1004 1005 // Map the pixels in place and take ownership of the ashmem region. 1006 nativeBitmap = sk_sp<Bitmap>(GraphicsJNI::mapAshmemBitmap(env, bitmap.get(), 1007 ctable, dupFd, const_cast<void*>(blob.data()), size, !isMutable)); 1008 SkSafeUnref(ctable); 1009 if (!nativeBitmap) { 1010 close(dupFd); 1011 blob.release(); 1012 doThrowRE(env, "Could not allocate ashmem pixel ref."); 1013 return NULL; 1014 } 1015 1016 // Clear the blob handle, don't release it. 1017 blob.clear(); 1018 } else { 1019#if DEBUG_PARCEL 1020 if (blob.fd() >= 0) { 1021 ALOGD("Bitmap.createFromParcel: copied contents of mutable bitmap " 1022 "from immutable blob (fds %s)", 1023 p->allowFds() ? "allowed" : "forbidden"); 1024 } else { 1025 ALOGD("Bitmap.createFromParcel: copied contents from %s blob " 1026 "(fds %s)", 1027 blob.isMutable() ? "mutable" : "immutable", 1028 p->allowFds() ? "allowed" : "forbidden"); 1029 } 1030#endif 1031 1032 // Copy the pixels into a new buffer. 1033 nativeBitmap = Bitmap::allocateHeapBitmap(bitmap.get(), ctable); 1034 SkSafeUnref(ctable); 1035 if (!nativeBitmap) { 1036 blob.release(); 1037 doThrowRE(env, "Could not allocate java pixel ref."); 1038 return NULL; 1039 } 1040 bitmap->lockPixels(); 1041 memcpy(bitmap->getPixels(), blob.data(), size); 1042 bitmap->unlockPixels(); 1043 1044 // Release the blob handle. 1045 blob.release(); 1046 } 1047 1048 return createBitmap(env, nativeBitmap.release(), 1049 getPremulBitmapCreateFlags(isMutable), NULL, NULL, density); 1050} 1051 1052static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, 1053 jlong bitmapHandle, 1054 jboolean isMutable, jint density, 1055 jobject parcel) { 1056 if (parcel == NULL) { 1057 SkDebugf("------- writeToParcel null parcel\n"); 1058 return JNI_FALSE; 1059 } 1060 1061 android::Parcel* p = android::parcelForJavaObject(env, parcel); 1062 SkBitmap bitmap; 1063 1064 auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle); 1065 bitmapWrapper->getSkBitmap(&bitmap); 1066 1067 sk_sp<SkColorSpace> sRGB = SkColorSpace::MakeSRGB(); 1068 bool isSRGB = bitmap.colorSpace() == sRGB.get(); 1069 1070 p->writeInt32(isMutable); 1071 p->writeInt32(bitmap.colorType()); 1072 p->writeInt32(bitmap.alphaType()); 1073 p->writeInt32(isSRGB); // TODO: We should write the color space (b/32072280) 1074 p->writeInt32(bitmap.width()); 1075 p->writeInt32(bitmap.height()); 1076 p->writeInt32(bitmap.rowBytes()); 1077 p->writeInt32(density); 1078 1079 if (bitmap.colorType() == kIndex_8_SkColorType) { 1080 // The bitmap needs to be locked to access its color table. 1081 SkAutoLockPixels alp(bitmap); 1082 SkColorTable* ctable = bitmap.getColorTable(); 1083 if (ctable != NULL) { 1084 int count = ctable->count(); 1085 p->writeInt32(count); 1086 memcpy(p->writeInplace(count * sizeof(SkPMColor)), 1087 ctable->readColors(), count * sizeof(SkPMColor)); 1088 } else { 1089 p->writeInt32(0); // indicate no ctable 1090 } 1091 } 1092 1093 // Transfer the underlying ashmem region if we have one and it's immutable. 1094 android::status_t status; 1095 int fd = bitmapWrapper->bitmap().getAshmemFd(); 1096 if (fd >= 0 && !isMutable && p->allowFds()) { 1097#if DEBUG_PARCEL 1098 ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as " 1099 "immutable blob (fds %s)", 1100 p->allowFds() ? "allowed" : "forbidden"); 1101#endif 1102 1103 status = p->writeDupImmutableBlobFileDescriptor(fd); 1104 if (status) { 1105 doThrowRE(env, "Could not write bitmap blob file descriptor."); 1106 return JNI_FALSE; 1107 } 1108 return JNI_TRUE; 1109 } 1110 1111 // Copy the bitmap to a new blob. 1112 bool mutableCopy = isMutable; 1113#if DEBUG_PARCEL 1114 ALOGD("Bitmap.writeToParcel: copying %s bitmap into new %s blob (fds %s)", 1115 isMutable ? "mutable" : "immutable", 1116 mutableCopy ? "mutable" : "immutable", 1117 p->allowFds() ? "allowed" : "forbidden"); 1118#endif 1119 1120 size_t size = bitmap.getSize(); 1121 android::Parcel::WritableBlob blob; 1122 status = p->writeBlob(size, mutableCopy, &blob); 1123 if (status) { 1124 doThrowRE(env, "Could not copy bitmap to parcel blob."); 1125 return JNI_FALSE; 1126 } 1127 1128 bitmap.lockPixels(); 1129 const void* pSrc = bitmap.getPixels(); 1130 if (pSrc == NULL) { 1131 memset(blob.data(), 0, size); 1132 } else { 1133 memcpy(blob.data(), pSrc, size); 1134 } 1135 bitmap.unlockPixels(); 1136 1137 blob.release(); 1138 return JNI_TRUE; 1139} 1140 1141static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz, 1142 jlong srcHandle, jlong paintHandle, 1143 jintArray offsetXY) { 1144 SkBitmap src; 1145 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src); 1146 const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle); 1147 SkIPoint offset; 1148 SkBitmap dst; 1149 HeapAllocator allocator; 1150 1151 src.extractAlpha(&dst, paint, &allocator, &offset); 1152 // If Skia can't allocate pixels for destination bitmap, it resets 1153 // it, that is set its pixels buffer to NULL, and zero width and height. 1154 if (dst.getPixels() == NULL && src.getPixels() != NULL) { 1155 doThrowOOME(env, "failed to allocate pixels for alpha"); 1156 return NULL; 1157 } 1158 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) { 1159 int* array = env->GetIntArrayElements(offsetXY, NULL); 1160 array[0] = offset.fX; 1161 array[1] = offset.fY; 1162 env->ReleaseIntArrayElements(offsetXY, array, 0); 1163 } 1164 1165 return createBitmap(env, allocator.getStorageObjAndReset(), 1166 getPremulBitmapCreateFlags(true)); 1167} 1168 1169/////////////////////////////////////////////////////////////////////////////// 1170 1171static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle, 1172 jint x, jint y) { 1173 SkBitmap bitmap; 1174 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1175 SkAutoLockPixels alp(bitmap); 1176 1177 ToColorProc proc = ChooseToColorProc(bitmap); 1178 if (NULL == proc) { 1179 return 0; 1180 } 1181 const void* src = bitmap.getAddr(x, y); 1182 if (NULL == src) { 1183 return 0; 1184 } 1185 1186 SkColor dst[1]; 1187 proc(dst, src, 1, bitmap.getColorTable()); 1188 return static_cast<jint>(dst[0]); 1189} 1190 1191static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle, 1192 jintArray pixelArray, jint offset, jint stride, 1193 jint x, jint y, jint width, jint height) { 1194 SkBitmap bitmap; 1195 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1196 SkAutoLockPixels alp(bitmap); 1197 1198 ToColorProc proc = ChooseToColorProc(bitmap); 1199 if (NULL == proc) { 1200 return; 1201 } 1202 const void* src = bitmap.getAddr(x, y); 1203 if (NULL == src) { 1204 return; 1205 } 1206 1207 SkColorTable* ctable = bitmap.getColorTable(); 1208 jint* dst = env->GetIntArrayElements(pixelArray, NULL); 1209 SkColor* d = (SkColor*)dst + offset; 1210 while (--height >= 0) { 1211 proc(d, src, width, ctable); 1212 d += stride; 1213 src = (void*)((const char*)src + bitmap.rowBytes()); 1214 } 1215 env->ReleaseIntArrayElements(pixelArray, dst, 0); 1216} 1217 1218/////////////////////////////////////////////////////////////////////////////// 1219 1220static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle, 1221 jint x, jint y, jint colorHandle) { 1222 SkBitmap bitmap; 1223 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1224 SkColor color = static_cast<SkColor>(colorHandle); 1225 SkAutoLockPixels alp(bitmap); 1226 if (NULL == bitmap.getPixels()) { 1227 return; 1228 } 1229 1230 FromColorProc proc = ChooseFromColorProc(bitmap); 1231 if (NULL == proc) { 1232 return; 1233 } 1234 1235 proc(bitmap.getAddr(x, y), &color, 1, x, y); 1236 bitmap.notifyPixelsChanged(); 1237} 1238 1239static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle, 1240 jintArray pixelArray, jint offset, jint stride, 1241 jint x, jint y, jint width, jint height) { 1242 SkBitmap bitmap; 1243 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1244 GraphicsJNI::SetPixels(env, pixelArray, offset, stride, 1245 x, y, width, height, bitmap); 1246} 1247 1248static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject, 1249 jlong bitmapHandle, jobject jbuffer) { 1250 SkBitmap bitmap; 1251 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1252 SkAutoLockPixels alp(bitmap); 1253 const void* src = bitmap.getPixels(); 1254 1255 if (NULL != src) { 1256 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE); 1257 1258 // the java side has already checked that buffer is large enough 1259 memcpy(abp.pointer(), src, bitmap.getSize()); 1260 } 1261} 1262 1263static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject, 1264 jlong bitmapHandle, jobject jbuffer) { 1265 SkBitmap bitmap; 1266 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1267 SkAutoLockPixels alp(bitmap); 1268 void* dst = bitmap.getPixels(); 1269 1270 if (NULL != dst) { 1271 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE); 1272 // the java side has already checked that buffer is large enough 1273 memcpy(dst, abp.pointer(), bitmap.getSize()); 1274 bitmap.notifyPixelsChanged(); 1275 } 1276} 1277 1278static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle, jlong bm1Handle) { 1279 SkBitmap bm0; 1280 SkBitmap bm1; 1281 1282 LocalScopedBitmap bitmap0(bm0Handle); 1283 LocalScopedBitmap bitmap1(bm1Handle); 1284 1285 // Paying the price for making Hardware Bitmap as Config: 1286 // later check for colorType will pass successfully, 1287 // because Hardware Config internally may be RGBA8888 or smth like that. 1288 if (bitmap0->isHardware() != bitmap1->isHardware()) { 1289 return JNI_FALSE; 1290 } 1291 1292 bitmap0->bitmap().getSkBitmap(&bm0); 1293 bitmap1->bitmap().getSkBitmap(&bm1); 1294 if (bm0.width() != bm1.width() 1295 || bm0.height() != bm1.height() 1296 || bm0.colorType() != bm1.colorType() 1297 || bm0.alphaType() != bm1.alphaType() 1298 || !SkColorSpace::Equals(bm0.colorSpace(), bm1.colorSpace())) { 1299 return JNI_FALSE; 1300 } 1301 1302 SkAutoLockPixels alp0(bm0); 1303 SkAutoLockPixels alp1(bm1); 1304 1305 // if we can't load the pixels, return false 1306 if (NULL == bm0.getPixels() || NULL == bm1.getPixels()) { 1307 return JNI_FALSE; 1308 } 1309 1310 if (bm0.colorType() == kIndex_8_SkColorType) { 1311 SkColorTable* ct0 = bm0.getColorTable(); 1312 SkColorTable* ct1 = bm1.getColorTable(); 1313 if (NULL == ct0 || NULL == ct1) { 1314 return JNI_FALSE; 1315 } 1316 if (ct0->count() != ct1->count()) { 1317 return JNI_FALSE; 1318 } 1319 1320 const size_t size = ct0->count() * sizeof(SkPMColor); 1321 if (memcmp(ct0->readColors(), ct1->readColors(), size) != 0) { 1322 return JNI_FALSE; 1323 } 1324 } 1325 1326 // now compare each scanline. We can't do the entire buffer at once, 1327 // since we don't care about the pixel values that might extend beyond 1328 // the width (since the scanline might be larger than the logical width) 1329 const int h = bm0.height(); 1330 const size_t size = bm0.width() * bm0.bytesPerPixel(); 1331 for (int y = 0; y < h; y++) { 1332 // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config 1333 // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0 1334 // and bm1 both have pixel data() (have passed NULL == getPixels() check), 1335 // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE 1336 // to warn user those 2 unrecognized config bitmaps may be different. 1337 void *bm0Addr = bm0.getAddr(0, y); 1338 void *bm1Addr = bm1.getAddr(0, y); 1339 1340 if(bm0Addr == NULL || bm1Addr == NULL) { 1341 return JNI_FALSE; 1342 } 1343 1344 if (memcmp(bm0Addr, bm1Addr, size) != 0) { 1345 return JNI_FALSE; 1346 } 1347 } 1348 return JNI_TRUE; 1349} 1350 1351static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapPtr) { 1352 LocalScopedBitmap bitmapHandle(bitmapPtr); 1353 if (!bitmapHandle.valid()) return; 1354 android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmapHandle->bitmap()); 1355} 1356 1357static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr) { 1358 LocalScopedBitmap bitmapHandle(bitmapPtr); 1359 return static_cast<jint>(bitmapHandle->getAllocationByteCount()); 1360} 1361 1362static jobject Bitmap_copyPreserveInternalConfig(JNIEnv* env, jobject, jlong bitmapPtr) { 1363 LocalScopedBitmap bitmapHandle(bitmapPtr); 1364 LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(), 1365 "Hardware config is only supported config in Bitmap_nativeCopyPreserveInternalConfig"); 1366 Bitmap& hwuiBitmap = bitmapHandle->bitmap(); 1367 SkBitmap src; 1368 hwuiBitmap.getSkBitmap(&src); 1369 1370 SkBitmap result; 1371 HeapAllocator allocator; 1372 if (!src.copyTo(&result, hwuiBitmap.info().colorType(), &allocator)) { 1373 doThrowRE(env, "Could not copy a hardware bitmap."); 1374 return NULL; 1375 } 1376 return createBitmap(env, allocator.getStorageObjAndReset(), getPremulBitmapCreateFlags(false)); 1377} 1378 1379static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphicBuffer) { 1380 sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer)); 1381 sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer); 1382 if (!bitmap.get()) { 1383 ALOGW("failed to create hardware bitmap from graphic buffer"); 1384 return NULL; 1385 } 1386 return bitmap::createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false)); 1387} 1388 1389static jobject Bitmap_createGraphicBufferHandle(JNIEnv* env, jobject, jlong bitmapPtr) { 1390 LocalScopedBitmap bitmapHandle(bitmapPtr); 1391 LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(), 1392 "Hardware config is only supported config in Bitmap_getGraphicBuffer"); 1393 1394 Bitmap& hwuiBitmap = bitmapHandle->bitmap(); 1395 sp<GraphicBuffer> buffer(hwuiBitmap.graphicBuffer()); 1396 return createJavaGraphicBuffer(env, buffer); 1397} 1398 1399/////////////////////////////////////////////////////////////////////////////// 1400static jclass make_globalref(JNIEnv* env, const char classname[]) 1401{ 1402 jclass c = env->FindClass(classname); 1403 SkASSERT(c); 1404 return (jclass) env->NewGlobalRef(c); 1405} 1406 1407static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz, 1408 const char fieldname[], const char type[]) 1409{ 1410 jfieldID id = env->GetFieldID(clazz, fieldname, type); 1411 SkASSERT(id); 1412 return id; 1413} 1414 1415static const JNINativeMethod gBitmapMethods[] = { 1416 { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;", 1417 (void*)Bitmap_creator }, 1418 { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;", 1419 (void*)Bitmap_copy }, 1420 { "nativeCopyAshmem", "(J)Landroid/graphics/Bitmap;", 1421 (void*)Bitmap_copyAshmem }, 1422 { "nativeCopyAshmemConfig", "(JI)Landroid/graphics/Bitmap;", 1423 (void*)Bitmap_copyAshmemConfig }, 1424 { "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer }, 1425 { "nativeRecycle", "(J)Z", (void*)Bitmap_recycle }, 1426 { "nativeReconfigure", "(JIIIZ)V", (void*)Bitmap_reconfigure }, 1427 { "nativeCompress", "(JIILjava/io/OutputStream;[B)Z", 1428 (void*)Bitmap_compress }, 1429 { "nativeErase", "(JI)V", (void*)Bitmap_erase }, 1430 { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes }, 1431 { "nativeConfig", "(J)I", (void*)Bitmap_config }, 1432 { "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha }, 1433 { "nativeIsPremultiplied", "(J)Z", (void*)Bitmap_isPremultiplied}, 1434 { "nativeSetHasAlpha", "(JZZ)V", (void*)Bitmap_setHasAlpha}, 1435 { "nativeSetPremultiplied", "(JZ)V", (void*)Bitmap_setPremultiplied}, 1436 { "nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap }, 1437 { "nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap }, 1438 { "nativeCreateFromParcel", 1439 "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;", 1440 (void*)Bitmap_createFromParcel }, 1441 { "nativeWriteToParcel", "(JZILandroid/os/Parcel;)Z", 1442 (void*)Bitmap_writeToParcel }, 1443 { "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;", 1444 (void*)Bitmap_extractAlpha }, 1445 { "nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId }, 1446 { "nativeGetPixel", "(JII)I", (void*)Bitmap_getPixel }, 1447 { "nativeGetPixels", "(J[IIIIIII)V", (void*)Bitmap_getPixels }, 1448 { "nativeSetPixel", "(JIII)V", (void*)Bitmap_setPixel }, 1449 { "nativeSetPixels", "(J[IIIIIII)V", (void*)Bitmap_setPixels }, 1450 { "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V", 1451 (void*)Bitmap_copyPixelsToBuffer }, 1452 { "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V", 1453 (void*)Bitmap_copyPixelsFromBuffer }, 1454 { "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs }, 1455 { "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw }, 1456 { "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount }, 1457 { "nativeCopyPreserveInternalConfig", "(J)Landroid/graphics/Bitmap;", 1458 (void*)Bitmap_copyPreserveInternalConfig }, 1459 { "nativeCreateHardwareBitmap", "(Landroid/graphics/GraphicBuffer;)Landroid/graphics/Bitmap;", 1460 (void*) Bitmap_createHardwareBitmap }, 1461 { "nativeCreateGraphicBufferHandle", "(J)Landroid/graphics/GraphicBuffer;", 1462 (void*) Bitmap_createGraphicBufferHandle } 1463}; 1464 1465int register_android_graphics_Bitmap(JNIEnv* env) 1466{ 1467 gBitmap_class = make_globalref(env, "android/graphics/Bitmap"); 1468 gBitmap_nativePtr = getFieldIDCheck(env, gBitmap_class, "mNativePtr", "J"); 1469 gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V"); 1470 gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "(IIZ)V"); 1471 gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I"); 1472 return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods, 1473 NELEM(gBitmapMethods)); 1474} 1475