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