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 41static jclass gBitmap_class; 42static jfieldID gBitmap_nativePtr; 43static jmethodID gBitmap_constructorMethodID; 44static jmethodID gBitmap_reinitMethodID; 45static jmethodID gBitmap_getAllocationByteCountMethodID; 46 47namespace android { 48 49class BitmapWrapper { 50public: 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 136private: 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 148class LocalScopedBitmap { 149public: 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 165private: 166 BitmapWrapper* mBitmapWrapper; 167}; 168 169namespace bitmap { 170 171// Assert that bitmap's SkAlphaType is consistent with isPremultiplied. 172static 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 183void 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 194int getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap) 195{ 196 return env->CallIntMethod(javaBitmap, gBitmap_getAllocationByteCountMethodID); 197} 198 199jobject 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 219void toSkBitmap(jlong bitmapHandle, SkBitmap* outBitmap) { 220 LocalScopedBitmap bitmap(bitmapHandle); 221 bitmap->getSkBitmap(outBitmap); 222} 223 224Bitmap& 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 233Bitmap& toBitmap(JNIEnv* env, jlong bitmapHandle) { 234 SkASSERT(env); 235 LocalScopedBitmap localBitmap(bitmapHandle); 236 return localBitmap->bitmap(); 237} 238 239void 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 271void* 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 288bool 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 307using namespace android; 308using namespace android::bitmap; 309 310/////////////////////////////////////////////////////////////////////////////// 311// Conversions to/from SkColor, for get/setPixels, and the create method, which 312// is basically like setPixels 313 314typedef void (*FromColorProc)(void* dst, const SkColor src[], int width, 315 int x, int y); 316 317static 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 326static 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 340static 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 349static 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 369static 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 381static 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 393static 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 409static 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 418static 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 437bool 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 488typedef void (*ToColorProc)(SkColor dst[], const void* src, int width); 489 490static 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 498static 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 506static 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 514static 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 524static 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 534static 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 542static 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 552static 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 562static 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 572static 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 582static 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 627static 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 646static int getPremulBitmapCreateFlags(bool isMutable) { 647 int flags = android::bitmap::kBitmapCreateFlag_Premultiplied; 648 if (isMutable) flags |= android::bitmap::kBitmapCreateFlag_Mutable; 649 return flags; 650} 651 652static 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 ALOGE("OOM allocating Bitmap with dimensions %i x %i", width, height); 686 doThrowOOME(env); 687 return NULL; 688 } 689 690 if (jColors != NULL) { 691 GraphicsJNI::SetPixels(env, jColors, offset, stride, 0, 0, width, height, bitmap); 692 } 693 694 return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable)); 695} 696 697static bool bitmapCopyTo(SkBitmap* dst, SkColorType dstCT, const SkBitmap& src, 698 SkBitmap::Allocator* alloc) { 699 SkPixmap srcPM; 700 if (!src.peekPixels(&srcPM)) { 701 return false; 702 } 703 704 SkImageInfo dstInfo = srcPM.info().makeColorType(dstCT); 705 switch (dstCT) { 706 case kRGB_565_SkColorType: 707 // copyTo() has never been strict on alpha type. Here we set the src to opaque to 708 // allow the call to readPixels() to succeed and preserve this lenient behavior. 709 if (kOpaque_SkAlphaType != srcPM.alphaType()) { 710 srcPM = SkPixmap(srcPM.info().makeAlphaType(kOpaque_SkAlphaType), srcPM.addr(), 711 srcPM.rowBytes()); 712 dstInfo = dstInfo.makeAlphaType(kOpaque_SkAlphaType); 713 } 714 break; 715 case kRGBA_F16_SkColorType: 716 // The caller does not have an opportunity to pass a dst color space. Assume that 717 // they want linear sRGB. 718 dstInfo = dstInfo.makeColorSpace(SkColorSpace::MakeSRGBLinear()); 719 720 if (!srcPM.colorSpace()) { 721 // Skia needs a color space to convert to F16. nullptr should be treated as sRGB. 722 srcPM.setColorSpace(SkColorSpace::MakeSRGB()); 723 } 724 break; 725 default: 726 break; 727 } 728 729 if (!dst->setInfo(dstInfo)) { 730 return false; 731 } 732 if (!dst->tryAllocPixels(alloc)) { 733 return false; 734 } 735 736 // Skia does not support copying from kAlpha8 to types that are not alpha only. 737 // We will handle this case here. 738 if (kAlpha_8_SkColorType == srcPM.colorType() && kAlpha_8_SkColorType != dstCT) { 739 switch (dstCT) { 740 case kRGBA_8888_SkColorType: 741 case kBGRA_8888_SkColorType: { 742 for (int y = 0; y < src.height(); y++) { 743 const uint8_t* srcRow = srcPM.addr8(0, y); 744 uint32_t* dstRow = dst->getAddr32(0, y); 745 ToColor_SA8(dstRow, srcRow, src.width()); 746 } 747 return true; 748 } 749 case kRGB_565_SkColorType: { 750 for (int y = 0; y < src.height(); y++) { 751 uint16_t* dstRow = dst->getAddr16(0, y); 752 memset(dstRow, 0, sizeof(uint16_t) * src.width()); 753 } 754 return true; 755 } 756 case kRGBA_F16_SkColorType: { 757 for (int y = 0; y < src.height(); y++) { 758 const uint8_t* srcRow = srcPM.addr8(0, y); 759 void* dstRow = dst->getAddr(0, y); 760 ToF16_SA8(dstRow, srcRow, src.width()); 761 } 762 return true; 763 } 764 default: 765 return false; 766 } 767 } 768 769 SkPixmap dstPM; 770 if (!dst->peekPixels(&dstPM)) { 771 return false; 772 } 773 774 // Skia needs a color space to convert from F16. nullptr should be treated as sRGB. 775 if (kRGBA_F16_SkColorType == srcPM.colorType() && !dstPM.colorSpace()) { 776 dstPM.setColorSpace(SkColorSpace::MakeSRGB()); 777 } 778 779 // readPixels does not support color spaces with parametric transfer functions. This 780 // works around that restriction when the color spaces are equal. 781 if (kRGBA_F16_SkColorType != dstCT && kRGBA_F16_SkColorType != srcPM.colorType() && 782 dstPM.colorSpace() == srcPM.colorSpace()) { 783 dstPM.setColorSpace(nullptr); 784 srcPM.setColorSpace(nullptr); 785 } 786 787 return srcPM.readPixels(dstPM); 788} 789 790static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle, 791 jint dstConfigHandle, jboolean isMutable) { 792 SkBitmap src; 793 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src); 794 if (dstConfigHandle == GraphicsJNI::hardwareLegacyBitmapConfig()) { 795 sk_sp<Bitmap> bitmap(Bitmap::allocateHardwareBitmap(src)); 796 if (!bitmap.get()) { 797 return NULL; 798 } 799 return createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(isMutable)); 800 } 801 802 SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle); 803 SkBitmap result; 804 HeapAllocator allocator; 805 806 if (!bitmapCopyTo(&result, dstCT, src, &allocator)) { 807 return NULL; 808 } 809 auto bitmap = allocator.getStorageObjAndReset(); 810 return createBitmap(env, bitmap, getPremulBitmapCreateFlags(isMutable)); 811} 812 813static Bitmap* Bitmap_copyAshmemImpl(JNIEnv* env, SkBitmap& src, SkColorType& dstCT) { 814 SkBitmap result; 815 816 AshmemPixelAllocator allocator(env); 817 if (!bitmapCopyTo(&result, dstCT, src, &allocator)) { 818 return NULL; 819 } 820 auto bitmap = allocator.getStorageObjAndReset(); 821 bitmap->setImmutable(); 822 return bitmap; 823} 824 825static jobject Bitmap_copyAshmem(JNIEnv* env, jobject, jlong srcHandle) { 826 SkBitmap src; 827 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src); 828 SkColorType dstCT = src.colorType(); 829 auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT); 830 jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false)); 831 return ret; 832} 833 834static jobject Bitmap_copyAshmemConfig(JNIEnv* env, jobject, jlong srcHandle, jint dstConfigHandle) { 835 SkBitmap src; 836 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src); 837 SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle); 838 auto bitmap = Bitmap_copyAshmemImpl(env, src, dstCT); 839 jobject ret = createBitmap(env, bitmap, getPremulBitmapCreateFlags(false)); 840 return ret; 841} 842 843static void Bitmap_destruct(BitmapWrapper* bitmap) { 844 delete bitmap; 845} 846 847static jlong Bitmap_getNativeFinalizer(JNIEnv*, jobject) { 848 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Bitmap_destruct)); 849} 850 851static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) { 852 LocalScopedBitmap bitmap(bitmapHandle); 853 bitmap->freePixels(); 854 return JNI_TRUE; 855} 856 857static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle, 858 jint width, jint height, jint configHandle, jboolean requestPremul) { 859 LocalScopedBitmap bitmap(bitmapHandle); 860 bitmap->assertValid(); 861 SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle); 862 863 // ARGB_4444 is a deprecated format, convert automatically to 8888 864 if (colorType == kARGB_4444_SkColorType) { 865 colorType = kN32_SkColorType; 866 } 867 size_t requestedSize = width * height * SkColorTypeBytesPerPixel(colorType); 868 if (requestedSize > bitmap->getAllocationByteCount()) { 869 // done in native as there's no way to get BytesPerPixel in Java 870 doThrowIAE(env, "Bitmap not large enough to support new configuration"); 871 return; 872 } 873 SkAlphaType alphaType; 874 if (bitmap->info().colorType() != kRGB_565_SkColorType 875 && bitmap->info().alphaType() == kOpaque_SkAlphaType) { 876 // If the original bitmap was set to opaque, keep that setting, unless it 877 // was 565, which is required to be opaque. 878 alphaType = kOpaque_SkAlphaType; 879 } else { 880 // Otherwise respect the premultiplied request. 881 alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType; 882 } 883 bitmap->bitmap().reconfigure(SkImageInfo::Make(width, height, colorType, alphaType, 884 sk_ref_sp(bitmap->info().colorSpace()))); 885} 886 887// These must match the int values in Bitmap.java 888enum JavaEncodeFormat { 889 kJPEG_JavaEncodeFormat = 0, 890 kPNG_JavaEncodeFormat = 1, 891 kWEBP_JavaEncodeFormat = 2 892}; 893 894static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle, 895 jint format, jint quality, 896 jobject jstream, jbyteArray jstorage) { 897 SkEncodedImageFormat fm; 898 switch (format) { 899 case kJPEG_JavaEncodeFormat: 900 fm = SkEncodedImageFormat::kJPEG; 901 break; 902 case kPNG_JavaEncodeFormat: 903 fm = SkEncodedImageFormat::kPNG; 904 break; 905 case kWEBP_JavaEncodeFormat: 906 fm = SkEncodedImageFormat::kWEBP; 907 break; 908 default: 909 return JNI_FALSE; 910 } 911 912 LocalScopedBitmap bitmap(bitmapHandle); 913 if (!bitmap.valid()) { 914 return JNI_FALSE; 915 } 916 917 std::unique_ptr<SkWStream> strm(CreateJavaOutputStreamAdaptor(env, jstream, jstorage)); 918 if (!strm.get()) { 919 return JNI_FALSE; 920 } 921 922 SkBitmap skbitmap; 923 bitmap->getSkBitmap(&skbitmap); 924 if (skbitmap.colorType() == kRGBA_F16_SkColorType) { 925 // Convert to P3 before encoding. This matches SkAndroidCodec::computeOutputColorSpace 926 // for wide gamuts. 927 auto cs = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, 928 SkColorSpace::kDCIP3_D65_Gamut); 929 auto info = skbitmap.info().makeColorType(kRGBA_8888_SkColorType) 930 .makeColorSpace(std::move(cs)); 931 SkBitmap p3; 932 if (!p3.tryAllocPixels(info)) { 933 return JNI_FALSE; 934 } 935 auto xform = SkColorSpaceXform::New(skbitmap.colorSpace(), info.colorSpace()); 936 if (!xform) { 937 return JNI_FALSE; 938 } 939 if (!xform->apply(SkColorSpaceXform::kRGBA_8888_ColorFormat, p3.getPixels(), 940 SkColorSpaceXform::kRGBA_F16_ColorFormat, skbitmap.getPixels(), 941 info.width() * info.height(), kUnpremul_SkAlphaType)) { 942 return JNI_FALSE; 943 } 944 skbitmap = p3; 945 } 946 return SkEncodeImage(strm.get(), skbitmap, fm, quality) ? JNI_TRUE : JNI_FALSE; 947} 948 949static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) { 950 LocalScopedBitmap bitmap(bitmapHandle); 951 SkBitmap skBitmap; 952 bitmap->getSkBitmap(&skBitmap); 953 skBitmap.eraseColor(color); 954} 955 956static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) { 957 LocalScopedBitmap bitmap(bitmapHandle); 958 return static_cast<jint>(bitmap->rowBytes()); 959} 960 961static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) { 962 LocalScopedBitmap bitmap(bitmapHandle); 963 if (bitmap->isHardware()) { 964 return GraphicsJNI::hardwareLegacyBitmapConfig(); 965 } 966 return GraphicsJNI::colorTypeToLegacyBitmapConfig(bitmap->info().colorType()); 967} 968 969static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) { 970 LocalScopedBitmap bitmap(bitmapHandle); 971 return static_cast<jint>(bitmap->getGenerationID()); 972} 973 974static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) { 975 LocalScopedBitmap bitmap(bitmapHandle); 976 if (bitmap->info().alphaType() == kPremul_SkAlphaType) { 977 return JNI_TRUE; 978 } 979 return JNI_FALSE; 980} 981 982static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) { 983 LocalScopedBitmap bitmap(bitmapHandle); 984 return !bitmap->info().isOpaque() ? JNI_TRUE : JNI_FALSE; 985} 986 987static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle, 988 jboolean hasAlpha, jboolean requestPremul) { 989 LocalScopedBitmap bitmap(bitmapHandle); 990 if (hasAlpha) { 991 bitmap->setAlphaType( 992 requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType); 993 } else { 994 bitmap->setAlphaType(kOpaque_SkAlphaType); 995 } 996} 997 998static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle, 999 jboolean isPremul) { 1000 LocalScopedBitmap bitmap(bitmapHandle); 1001 if (!bitmap->info().isOpaque()) { 1002 if (isPremul) { 1003 bitmap->setAlphaType(kPremul_SkAlphaType); 1004 } else { 1005 bitmap->setAlphaType(kUnpremul_SkAlphaType); 1006 } 1007 } 1008} 1009 1010static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) { 1011 LocalScopedBitmap bitmap(bitmapHandle); 1012 return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE; 1013} 1014 1015static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle, 1016 jboolean hasMipMap) { 1017 LocalScopedBitmap bitmap(bitmapHandle); 1018 bitmap->setHasHardwareMipMap(hasMipMap); 1019} 1020 1021/////////////////////////////////////////////////////////////////////////////// 1022 1023// This is the maximum possible size because the SkColorSpace must be 1024// representable (and therefore serializable) using a matrix and numerical 1025// transfer function. If we allow more color space representations in the 1026// framework, we may need to update this maximum size. 1027static constexpr uint32_t kMaxColorSpaceSerializedBytes = 80; 1028 1029static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { 1030 if (parcel == NULL) { 1031 SkDebugf("-------- unparcel parcel is NULL\n"); 1032 return NULL; 1033 } 1034 1035 android::Parcel* p = android::parcelForJavaObject(env, parcel); 1036 1037 const bool isMutable = p->readInt32() != 0; 1038 const SkColorType colorType = (SkColorType)p->readInt32(); 1039 const SkAlphaType alphaType = (SkAlphaType)p->readInt32(); 1040 const uint32_t colorSpaceSize = p->readUint32(); 1041 sk_sp<SkColorSpace> colorSpace; 1042 if (kRGBA_F16_SkColorType == colorType) { 1043 colorSpace = SkColorSpace::MakeSRGBLinear(); 1044 } else if (colorSpaceSize > 0) { 1045 if (colorSpaceSize > kMaxColorSpaceSerializedBytes) { 1046 ALOGD("Bitmap_createFromParcel: Serialized SkColorSpace is larger than expected: " 1047 "%d bytes\n", colorSpaceSize); 1048 } 1049 1050 const void* data = p->readInplace(colorSpaceSize); 1051 if (data) { 1052 colorSpace = SkColorSpace::Deserialize(data, colorSpaceSize); 1053 } else { 1054 ALOGD("Bitmap_createFromParcel: Unable to read serialized SkColorSpace data\n"); 1055 } 1056 } 1057 const int width = p->readInt32(); 1058 const int height = p->readInt32(); 1059 const int rowBytes = p->readInt32(); 1060 const int density = p->readInt32(); 1061 1062 if (kN32_SkColorType != colorType && 1063 kRGBA_F16_SkColorType != colorType && 1064 kRGB_565_SkColorType != colorType && 1065 kARGB_4444_SkColorType != colorType && 1066 kAlpha_8_SkColorType != colorType) { 1067 SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType); 1068 return NULL; 1069 } 1070 1071 std::unique_ptr<SkBitmap> bitmap(new SkBitmap); 1072 if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType, colorSpace), 1073 rowBytes)) { 1074 return NULL; 1075 } 1076 1077 // Read the bitmap blob. 1078 size_t size = bitmap->computeByteSize(); 1079 android::Parcel::ReadableBlob blob; 1080 android::status_t status = p->readBlob(size, &blob); 1081 if (status) { 1082 doThrowRE(env, "Could not read bitmap blob."); 1083 return NULL; 1084 } 1085 1086 // Map the bitmap in place from the ashmem region if possible otherwise copy. 1087 sk_sp<Bitmap> nativeBitmap; 1088 if (blob.fd() >= 0 && (blob.isMutable() || !isMutable) && (size >= ASHMEM_BITMAP_MIN_SIZE)) { 1089#if DEBUG_PARCEL 1090 ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob " 1091 "(fds %s)", 1092 isMutable ? "mutable" : "immutable", 1093 blob.isMutable() ? "mutable" : "immutable", 1094 p->allowFds() ? "allowed" : "forbidden"); 1095#endif 1096 // Dup the file descriptor so we can keep a reference to it after the Parcel 1097 // is disposed. 1098 int dupFd = dup(blob.fd()); 1099 if (dupFd < 0) { 1100 ALOGE("Error allocating dup fd. Error:%d", errno); 1101 blob.release(); 1102 doThrowRE(env, "Could not allocate dup blob fd."); 1103 return NULL; 1104 } 1105 1106 // Map the pixels in place and take ownership of the ashmem region. 1107 nativeBitmap = sk_sp<Bitmap>(GraphicsJNI::mapAshmemBitmap(env, bitmap.get(), 1108 dupFd, const_cast<void*>(blob.data()), size, !isMutable)); 1109 if (!nativeBitmap) { 1110 close(dupFd); 1111 blob.release(); 1112 doThrowRE(env, "Could not allocate ashmem pixel ref."); 1113 return NULL; 1114 } 1115 1116 // Clear the blob handle, don't release it. 1117 blob.clear(); 1118 } else { 1119#if DEBUG_PARCEL 1120 if (blob.fd() >= 0) { 1121 ALOGD("Bitmap.createFromParcel: copied contents of mutable bitmap " 1122 "from immutable blob (fds %s)", 1123 p->allowFds() ? "allowed" : "forbidden"); 1124 } else { 1125 ALOGD("Bitmap.createFromParcel: copied contents from %s blob " 1126 "(fds %s)", 1127 blob.isMutable() ? "mutable" : "immutable", 1128 p->allowFds() ? "allowed" : "forbidden"); 1129 } 1130#endif 1131 1132 // Copy the pixels into a new buffer. 1133 nativeBitmap = Bitmap::allocateHeapBitmap(bitmap.get()); 1134 if (!nativeBitmap) { 1135 blob.release(); 1136 doThrowRE(env, "Could not allocate java pixel ref."); 1137 return NULL; 1138 } 1139 memcpy(bitmap->getPixels(), blob.data(), size); 1140 1141 // Release the blob handle. 1142 blob.release(); 1143 } 1144 1145 return createBitmap(env, nativeBitmap.release(), 1146 getPremulBitmapCreateFlags(isMutable), NULL, NULL, density); 1147} 1148 1149static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, 1150 jlong bitmapHandle, 1151 jboolean isMutable, jint density, 1152 jobject parcel) { 1153 if (parcel == NULL) { 1154 SkDebugf("------- writeToParcel null parcel\n"); 1155 return JNI_FALSE; 1156 } 1157 1158 android::Parcel* p = android::parcelForJavaObject(env, parcel); 1159 SkBitmap bitmap; 1160 1161 auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle); 1162 bitmapWrapper->getSkBitmap(&bitmap); 1163 1164 p->writeInt32(isMutable); 1165 p->writeInt32(bitmap.colorType()); 1166 p->writeInt32(bitmap.alphaType()); 1167 SkColorSpace* colorSpace = bitmap.colorSpace(); 1168 if (colorSpace != nullptr && bitmap.colorType() != kRGBA_F16_SkColorType) { 1169 sk_sp<SkData> data = colorSpace->serialize(); 1170 size_t size = data->size(); 1171 p->writeUint32(size); 1172 if (size > 0) { 1173 if (size > kMaxColorSpaceSerializedBytes) { 1174 ALOGD("Bitmap_writeToParcel: Serialized SkColorSpace is larger than expected: " 1175 "%zu bytes\n", size); 1176 } 1177 1178 p->write(data->data(), size); 1179 } 1180 } else { 1181 p->writeUint32(0); 1182 } 1183 p->writeInt32(bitmap.width()); 1184 p->writeInt32(bitmap.height()); 1185 p->writeInt32(bitmap.rowBytes()); 1186 p->writeInt32(density); 1187 1188 // Transfer the underlying ashmem region if we have one and it's immutable. 1189 android::status_t status; 1190 int fd = bitmapWrapper->bitmap().getAshmemFd(); 1191 if (fd >= 0 && !isMutable && p->allowFds()) { 1192#if DEBUG_PARCEL 1193 ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as " 1194 "immutable blob (fds %s)", 1195 p->allowFds() ? "allowed" : "forbidden"); 1196#endif 1197 1198 status = p->writeDupImmutableBlobFileDescriptor(fd); 1199 if (status) { 1200 doThrowRE(env, "Could not write bitmap blob file descriptor."); 1201 return JNI_FALSE; 1202 } 1203 return JNI_TRUE; 1204 } 1205 1206 // Copy the bitmap to a new blob. 1207 bool mutableCopy = isMutable; 1208#if DEBUG_PARCEL 1209 ALOGD("Bitmap.writeToParcel: copying %s bitmap into new %s blob (fds %s)", 1210 isMutable ? "mutable" : "immutable", 1211 mutableCopy ? "mutable" : "immutable", 1212 p->allowFds() ? "allowed" : "forbidden"); 1213#endif 1214 1215 size_t size = bitmap.computeByteSize(); 1216 android::Parcel::WritableBlob blob; 1217 status = p->writeBlob(size, mutableCopy, &blob); 1218 if (status) { 1219 doThrowRE(env, "Could not copy bitmap to parcel blob."); 1220 return JNI_FALSE; 1221 } 1222 1223 const void* pSrc = bitmap.getPixels(); 1224 if (pSrc == NULL) { 1225 memset(blob.data(), 0, size); 1226 } else { 1227 memcpy(blob.data(), pSrc, size); 1228 } 1229 1230 blob.release(); 1231 return JNI_TRUE; 1232} 1233 1234static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz, 1235 jlong srcHandle, jlong paintHandle, 1236 jintArray offsetXY) { 1237 SkBitmap src; 1238 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src); 1239 const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle); 1240 SkIPoint offset; 1241 SkBitmap dst; 1242 HeapAllocator allocator; 1243 1244 src.extractAlpha(&dst, paint, &allocator, &offset); 1245 // If Skia can't allocate pixels for destination bitmap, it resets 1246 // it, that is set its pixels buffer to NULL, and zero width and height. 1247 if (dst.getPixels() == NULL && src.getPixels() != NULL) { 1248 doThrowOOME(env, "failed to allocate pixels for alpha"); 1249 return NULL; 1250 } 1251 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) { 1252 int* array = env->GetIntArrayElements(offsetXY, NULL); 1253 array[0] = offset.fX; 1254 array[1] = offset.fY; 1255 env->ReleaseIntArrayElements(offsetXY, array, 0); 1256 } 1257 1258 return createBitmap(env, allocator.getStorageObjAndReset(), 1259 getPremulBitmapCreateFlags(true)); 1260} 1261 1262/////////////////////////////////////////////////////////////////////////////// 1263 1264static jboolean Bitmap_isSRGB(JNIEnv* env, jobject, jlong bitmapHandle) { 1265 LocalScopedBitmap bitmapHolder(bitmapHandle); 1266 if (!bitmapHolder.valid()) return JNI_TRUE; 1267 1268 SkColorSpace* colorSpace = bitmapHolder->info().colorSpace(); 1269 return GraphicsJNI::isColorSpaceSRGB(colorSpace); 1270} 1271 1272static jboolean Bitmap_isSRGBLinear(JNIEnv* env, jobject, jlong bitmapHandle) { 1273 LocalScopedBitmap bitmapHolder(bitmapHandle); 1274 if (!bitmapHolder.valid()) return JNI_FALSE; 1275 1276 SkColorSpace* colorSpace = bitmapHolder->info().colorSpace(); 1277 sk_sp<SkColorSpace> srgbLinear = SkColorSpace::MakeSRGBLinear(); 1278 return colorSpace == srgbLinear.get() ? JNI_TRUE : JNI_FALSE; 1279} 1280 1281static jboolean Bitmap_getColorSpace(JNIEnv* env, jobject, jlong bitmapHandle, 1282 jfloatArray xyzArray, jfloatArray paramsArray) { 1283 1284 LocalScopedBitmap bitmapHolder(bitmapHandle); 1285 if (!bitmapHolder.valid()) return JNI_FALSE; 1286 1287 SkColorSpace* colorSpace = bitmapHolder->info().colorSpace(); 1288 if (colorSpace == nullptr) return JNI_FALSE; 1289 1290 SkMatrix44 xyzMatrix(SkMatrix44::kUninitialized_Constructor); 1291 if (!colorSpace->toXYZD50(&xyzMatrix)) return JNI_FALSE; 1292 1293 jfloat* xyz = env->GetFloatArrayElements(xyzArray, NULL); 1294 xyz[0] = xyzMatrix.getFloat(0, 0); 1295 xyz[1] = xyzMatrix.getFloat(1, 0); 1296 xyz[2] = xyzMatrix.getFloat(2, 0); 1297 xyz[3] = xyzMatrix.getFloat(0, 1); 1298 xyz[4] = xyzMatrix.getFloat(1, 1); 1299 xyz[5] = xyzMatrix.getFloat(2, 1); 1300 xyz[6] = xyzMatrix.getFloat(0, 2); 1301 xyz[7] = xyzMatrix.getFloat(1, 2); 1302 xyz[8] = xyzMatrix.getFloat(2, 2); 1303 env->ReleaseFloatArrayElements(xyzArray, xyz, 0); 1304 1305 SkColorSpaceTransferFn transferParams; 1306 if (!colorSpace->isNumericalTransferFn(&transferParams)) return JNI_FALSE; 1307 1308 jfloat* params = env->GetFloatArrayElements(paramsArray, NULL); 1309 params[0] = transferParams.fA; 1310 params[1] = transferParams.fB; 1311 params[2] = transferParams.fC; 1312 params[3] = transferParams.fD; 1313 params[4] = transferParams.fE; 1314 params[5] = transferParams.fF; 1315 params[6] = transferParams.fG; 1316 env->ReleaseFloatArrayElements(paramsArray, params, 0); 1317 1318 return JNI_TRUE; 1319} 1320 1321/////////////////////////////////////////////////////////////////////////////// 1322 1323static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle, 1324 jint x, jint y) { 1325 SkBitmap bitmap; 1326 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1327 1328 ToColorProc proc = ChooseToColorProc(bitmap); 1329 if (NULL == proc) { 1330 return 0; 1331 } 1332 const void* src = bitmap.getAddr(x, y); 1333 if (NULL == src) { 1334 return 0; 1335 } 1336 1337 SkColor dst[1]; 1338 proc(dst, src, 1); 1339 1340 SkColorSpace* colorSpace = bitmap.colorSpace(); 1341 if (bitmap.colorType() != kRGBA_F16_SkColorType && 1342 !GraphicsJNI::isColorSpaceSRGB(colorSpace)) { 1343 auto sRGB = SkColorSpace::MakeSRGB(); 1344 auto xform = SkColorSpaceXform::New(colorSpace, sRGB.get()); 1345 xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, &dst[0], 1346 SkColorSpaceXform::kBGRA_8888_ColorFormat, &dst[0], 1, 1347 SkAlphaType::kUnpremul_SkAlphaType); 1348 } 1349 1350 return static_cast<jint>(dst[0]); 1351} 1352 1353static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle, 1354 jintArray pixelArray, jint offset, jint stride, 1355 jint x, jint y, jint width, jint height) { 1356 SkBitmap bitmap; 1357 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1358 1359 ToColorProc proc = ChooseToColorProc(bitmap); 1360 if (NULL == proc) { 1361 return; 1362 } 1363 const void* src = bitmap.getAddr(x, y); 1364 if (NULL == src) { 1365 return; 1366 } 1367 1368 jint* dst = env->GetIntArrayElements(pixelArray, NULL); 1369 SkColor* d = (SkColor*)dst + offset; 1370 1371 SkColorSpace* colorSpace = bitmap.colorSpace(); 1372 if (bitmap.colorType() == kRGBA_F16_SkColorType || 1373 GraphicsJNI::isColorSpaceSRGB(colorSpace)) { 1374 while (--height >= 0) { 1375 proc(d, src, width); 1376 d += stride; 1377 src = (void*)((const char*)src + bitmap.rowBytes()); 1378 } 1379 } else { 1380 auto sRGB = SkColorSpace::MakeSRGB(); 1381 auto xform = SkColorSpaceXform::New(colorSpace, sRGB.get()); 1382 1383 while (--height >= 0) { 1384 proc(d, src, width); 1385 1386 xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, d, 1387 SkColorSpaceXform::kBGRA_8888_ColorFormat, d, width, 1388 SkAlphaType::kUnpremul_SkAlphaType); 1389 1390 d += stride; 1391 src = (void*)((const char*)src + bitmap.rowBytes()); 1392 } 1393 } 1394 1395 env->ReleaseIntArrayElements(pixelArray, dst, 0); 1396} 1397 1398/////////////////////////////////////////////////////////////////////////////// 1399 1400static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle, 1401 jint x, jint y, jint colorHandle) { 1402 SkBitmap bitmap; 1403 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1404 SkColor color = static_cast<SkColor>(colorHandle); 1405 if (NULL == bitmap.getPixels()) { 1406 return; 1407 } 1408 1409 FromColorProc proc = ChooseFromColorProc(bitmap); 1410 if (NULL == proc) { 1411 return; 1412 } 1413 1414 SkColorSpace* colorSpace = bitmap.colorSpace(); 1415 if (bitmap.colorType() != kRGBA_F16_SkColorType && 1416 !GraphicsJNI::isColorSpaceSRGB(colorSpace)) { 1417 auto sRGB = SkColorSpace::MakeSRGB(); 1418 auto xform = SkColorSpaceXform::New(sRGB.get(), colorSpace); 1419 xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, &color, 1420 SkColorSpaceXform::kBGRA_8888_ColorFormat, &color, 1, 1421 SkAlphaType::kUnpremul_SkAlphaType); 1422 } 1423 1424 proc(bitmap.getAddr(x, y), &color, 1, x, y); 1425 bitmap.notifyPixelsChanged(); 1426} 1427 1428static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle, 1429 jintArray pixelArray, jint offset, jint stride, 1430 jint x, jint y, jint width, jint height) { 1431 SkBitmap bitmap; 1432 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1433 GraphicsJNI::SetPixels(env, pixelArray, offset, stride, 1434 x, y, width, height, bitmap); 1435} 1436 1437static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject, 1438 jlong bitmapHandle, jobject jbuffer) { 1439 SkBitmap bitmap; 1440 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1441 const void* src = bitmap.getPixels(); 1442 1443 if (NULL != src) { 1444 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE); 1445 1446 // the java side has already checked that buffer is large enough 1447 memcpy(abp.pointer(), src, bitmap.computeByteSize()); 1448 } 1449} 1450 1451static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject, 1452 jlong bitmapHandle, jobject jbuffer) { 1453 SkBitmap bitmap; 1454 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1455 void* dst = bitmap.getPixels(); 1456 1457 if (NULL != dst) { 1458 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE); 1459 // the java side has already checked that buffer is large enough 1460 memcpy(dst, abp.pointer(), bitmap.computeByteSize()); 1461 bitmap.notifyPixelsChanged(); 1462 } 1463} 1464 1465static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle, jlong bm1Handle) { 1466 SkBitmap bm0; 1467 SkBitmap bm1; 1468 1469 LocalScopedBitmap bitmap0(bm0Handle); 1470 LocalScopedBitmap bitmap1(bm1Handle); 1471 1472 // Paying the price for making Hardware Bitmap as Config: 1473 // later check for colorType will pass successfully, 1474 // because Hardware Config internally may be RGBA8888 or smth like that. 1475 if (bitmap0->isHardware() != bitmap1->isHardware()) { 1476 return JNI_FALSE; 1477 } 1478 1479 bitmap0->bitmap().getSkBitmap(&bm0); 1480 bitmap1->bitmap().getSkBitmap(&bm1); 1481 if (bm0.width() != bm1.width() 1482 || bm0.height() != bm1.height() 1483 || bm0.colorType() != bm1.colorType() 1484 || bm0.alphaType() != bm1.alphaType() 1485 || !SkColorSpace::Equals(bm0.colorSpace(), bm1.colorSpace())) { 1486 return JNI_FALSE; 1487 } 1488 1489 // if we can't load the pixels, return false 1490 if (NULL == bm0.getPixels() || NULL == bm1.getPixels()) { 1491 return JNI_FALSE; 1492 } 1493 1494 // now compare each scanline. We can't do the entire buffer at once, 1495 // since we don't care about the pixel values that might extend beyond 1496 // the width (since the scanline might be larger than the logical width) 1497 const int h = bm0.height(); 1498 const size_t size = bm0.width() * bm0.bytesPerPixel(); 1499 for (int y = 0; y < h; y++) { 1500 // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config 1501 // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0 1502 // and bm1 both have pixel data() (have passed NULL == getPixels() check), 1503 // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE 1504 // to warn user those 2 unrecognized config bitmaps may be different. 1505 void *bm0Addr = bm0.getAddr(0, y); 1506 void *bm1Addr = bm1.getAddr(0, y); 1507 1508 if(bm0Addr == NULL || bm1Addr == NULL) { 1509 return JNI_FALSE; 1510 } 1511 1512 if (memcmp(bm0Addr, bm1Addr, size) != 0) { 1513 return JNI_FALSE; 1514 } 1515 } 1516 return JNI_TRUE; 1517} 1518 1519static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapPtr) { 1520 LocalScopedBitmap bitmapHandle(bitmapPtr); 1521 if (!bitmapHandle.valid()) return; 1522 android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmapHandle->bitmap()); 1523} 1524 1525static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr) { 1526 LocalScopedBitmap bitmapHandle(bitmapPtr); 1527 return static_cast<jint>(bitmapHandle->getAllocationByteCount()); 1528} 1529 1530static jobject Bitmap_copyPreserveInternalConfig(JNIEnv* env, jobject, jlong bitmapPtr) { 1531 LocalScopedBitmap bitmapHandle(bitmapPtr); 1532 LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(), 1533 "Hardware config is only supported config in Bitmap_nativeCopyPreserveInternalConfig"); 1534 Bitmap& hwuiBitmap = bitmapHandle->bitmap(); 1535 SkBitmap src; 1536 hwuiBitmap.getSkBitmap(&src); 1537 1538 SkBitmap result; 1539 HeapAllocator allocator; 1540 if (!bitmapCopyTo(&result, hwuiBitmap.info().colorType(), src, &allocator)) { 1541 doThrowRE(env, "Could not copy a hardware bitmap."); 1542 return NULL; 1543 } 1544 return createBitmap(env, allocator.getStorageObjAndReset(), getPremulBitmapCreateFlags(false)); 1545} 1546 1547static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphicBuffer) { 1548 sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer)); 1549 sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer); 1550 if (!bitmap.get()) { 1551 ALOGW("failed to create hardware bitmap from graphic buffer"); 1552 return NULL; 1553 } 1554 return bitmap::createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false)); 1555} 1556 1557static jobject Bitmap_createGraphicBufferHandle(JNIEnv* env, jobject, jlong bitmapPtr) { 1558 LocalScopedBitmap bitmapHandle(bitmapPtr); 1559 LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(), 1560 "Hardware config is only supported config in Bitmap_getGraphicBuffer"); 1561 1562 Bitmap& hwuiBitmap = bitmapHandle->bitmap(); 1563 sp<GraphicBuffer> buffer(hwuiBitmap.graphicBuffer()); 1564 return createJavaGraphicBuffer(env, buffer); 1565} 1566 1567static void Bitmap_copyColorSpace(JNIEnv* env, jobject, jlong srcBitmapPtr, jlong dstBitmapPtr) { 1568 LocalScopedBitmap srcBitmapHandle(srcBitmapPtr); 1569 LocalScopedBitmap dstBitmapHandle(dstBitmapPtr); 1570 1571 dstBitmapHandle->bitmap().setColorSpace(srcBitmapHandle->bitmap().info().refColorSpace()); 1572} 1573 1574/////////////////////////////////////////////////////////////////////////////// 1575 1576static const JNINativeMethod gBitmapMethods[] = { 1577 { "nativeCreate", "([IIIIIIZ[FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)Landroid/graphics/Bitmap;", 1578 (void*)Bitmap_creator }, 1579 { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;", 1580 (void*)Bitmap_copy }, 1581 { "nativeCopyAshmem", "(J)Landroid/graphics/Bitmap;", 1582 (void*)Bitmap_copyAshmem }, 1583 { "nativeCopyAshmemConfig", "(JI)Landroid/graphics/Bitmap;", 1584 (void*)Bitmap_copyAshmemConfig }, 1585 { "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer }, 1586 { "nativeRecycle", "(J)Z", (void*)Bitmap_recycle }, 1587 { "nativeReconfigure", "(JIIIZ)V", (void*)Bitmap_reconfigure }, 1588 { "nativeCompress", "(JIILjava/io/OutputStream;[B)Z", 1589 (void*)Bitmap_compress }, 1590 { "nativeErase", "(JI)V", (void*)Bitmap_erase }, 1591 { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes }, 1592 { "nativeConfig", "(J)I", (void*)Bitmap_config }, 1593 { "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha }, 1594 { "nativeIsPremultiplied", "(J)Z", (void*)Bitmap_isPremultiplied}, 1595 { "nativeSetHasAlpha", "(JZZ)V", (void*)Bitmap_setHasAlpha}, 1596 { "nativeSetPremultiplied", "(JZ)V", (void*)Bitmap_setPremultiplied}, 1597 { "nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap }, 1598 { "nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap }, 1599 { "nativeCreateFromParcel", 1600 "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;", 1601 (void*)Bitmap_createFromParcel }, 1602 { "nativeWriteToParcel", "(JZILandroid/os/Parcel;)Z", 1603 (void*)Bitmap_writeToParcel }, 1604 { "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;", 1605 (void*)Bitmap_extractAlpha }, 1606 { "nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId }, 1607 { "nativeGetPixel", "(JII)I", (void*)Bitmap_getPixel }, 1608 { "nativeGetPixels", "(J[IIIIIII)V", (void*)Bitmap_getPixels }, 1609 { "nativeSetPixel", "(JIII)V", (void*)Bitmap_setPixel }, 1610 { "nativeSetPixels", "(J[IIIIIII)V", (void*)Bitmap_setPixels }, 1611 { "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V", 1612 (void*)Bitmap_copyPixelsToBuffer }, 1613 { "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V", 1614 (void*)Bitmap_copyPixelsFromBuffer }, 1615 { "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs }, 1616 { "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw }, 1617 { "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount }, 1618 { "nativeCopyPreserveInternalConfig", "(J)Landroid/graphics/Bitmap;", 1619 (void*)Bitmap_copyPreserveInternalConfig }, 1620 { "nativeCreateHardwareBitmap", "(Landroid/graphics/GraphicBuffer;)Landroid/graphics/Bitmap;", 1621 (void*) Bitmap_createHardwareBitmap }, 1622 { "nativeCreateGraphicBufferHandle", "(J)Landroid/graphics/GraphicBuffer;", 1623 (void*) Bitmap_createGraphicBufferHandle }, 1624 { "nativeGetColorSpace", "(J[F[F)Z", (void*)Bitmap_getColorSpace }, 1625 { "nativeIsSRGB", "(J)Z", (void*)Bitmap_isSRGB }, 1626 { "nativeIsSRGBLinear", "(J)Z", (void*)Bitmap_isSRGBLinear}, 1627 { "nativeCopyColorSpace", "(JJ)V", 1628 (void*)Bitmap_copyColorSpace }, 1629}; 1630 1631int register_android_graphics_Bitmap(JNIEnv* env) 1632{ 1633 gBitmap_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Bitmap")); 1634 gBitmap_nativePtr = GetFieldIDOrDie(env, gBitmap_class, "mNativePtr", "J"); 1635 gBitmap_constructorMethodID = GetMethodIDOrDie(env, gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V"); 1636 gBitmap_reinitMethodID = GetMethodIDOrDie(env, gBitmap_class, "reinit", "(IIZ)V"); 1637 gBitmap_getAllocationByteCountMethodID = GetMethodIDOrDie(env, gBitmap_class, "getAllocationByteCount", "()I"); 1638 return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods, 1639 NELEM(gBitmapMethods)); 1640} 1641