Bitmap.cpp revision f3a0299753dffe3cd79d62b99001754fe6dbf524
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 return SkEncodeImage(strm.get(), skbitmap, fm, quality) ? JNI_TRUE : JNI_FALSE; 925} 926 927static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) { 928 LocalScopedBitmap bitmap(bitmapHandle); 929 SkBitmap skBitmap; 930 bitmap->getSkBitmap(&skBitmap); 931 skBitmap.eraseColor(color); 932} 933 934static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) { 935 LocalScopedBitmap bitmap(bitmapHandle); 936 return static_cast<jint>(bitmap->rowBytes()); 937} 938 939static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) { 940 LocalScopedBitmap bitmap(bitmapHandle); 941 if (bitmap->isHardware()) { 942 return GraphicsJNI::hardwareLegacyBitmapConfig(); 943 } 944 return GraphicsJNI::colorTypeToLegacyBitmapConfig(bitmap->info().colorType()); 945} 946 947static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) { 948 LocalScopedBitmap bitmap(bitmapHandle); 949 return static_cast<jint>(bitmap->getGenerationID()); 950} 951 952static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) { 953 LocalScopedBitmap bitmap(bitmapHandle); 954 if (bitmap->info().alphaType() == kPremul_SkAlphaType) { 955 return JNI_TRUE; 956 } 957 return JNI_FALSE; 958} 959 960static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) { 961 LocalScopedBitmap bitmap(bitmapHandle); 962 return !bitmap->info().isOpaque() ? JNI_TRUE : JNI_FALSE; 963} 964 965static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle, 966 jboolean hasAlpha, jboolean requestPremul) { 967 LocalScopedBitmap bitmap(bitmapHandle); 968 if (hasAlpha) { 969 bitmap->setAlphaType( 970 requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType); 971 } else { 972 bitmap->setAlphaType(kOpaque_SkAlphaType); 973 } 974} 975 976static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle, 977 jboolean isPremul) { 978 LocalScopedBitmap bitmap(bitmapHandle); 979 if (!bitmap->info().isOpaque()) { 980 if (isPremul) { 981 bitmap->setAlphaType(kPremul_SkAlphaType); 982 } else { 983 bitmap->setAlphaType(kUnpremul_SkAlphaType); 984 } 985 } 986} 987 988static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) { 989 LocalScopedBitmap bitmap(bitmapHandle); 990 return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE; 991} 992 993static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle, 994 jboolean hasMipMap) { 995 LocalScopedBitmap bitmap(bitmapHandle); 996 bitmap->setHasHardwareMipMap(hasMipMap); 997} 998 999/////////////////////////////////////////////////////////////////////////////// 1000 1001// This is the maximum possible size because the SkColorSpace must be 1002// representable (and therefore serializable) using a matrix and numerical 1003// transfer function. If we allow more color space representations in the 1004// framework, we may need to update this maximum size. 1005static constexpr uint32_t kMaxColorSpaceSerializedBytes = 80; 1006 1007static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { 1008 if (parcel == NULL) { 1009 SkDebugf("-------- unparcel parcel is NULL\n"); 1010 return NULL; 1011 } 1012 1013 android::Parcel* p = android::parcelForJavaObject(env, parcel); 1014 1015 const bool isMutable = p->readInt32() != 0; 1016 const SkColorType colorType = (SkColorType)p->readInt32(); 1017 const SkAlphaType alphaType = (SkAlphaType)p->readInt32(); 1018 const uint32_t colorSpaceSize = p->readUint32(); 1019 sk_sp<SkColorSpace> colorSpace; 1020 if (kRGBA_F16_SkColorType == colorType) { 1021 colorSpace = SkColorSpace::MakeSRGBLinear(); 1022 } else if (colorSpaceSize > 0) { 1023 if (colorSpaceSize > kMaxColorSpaceSerializedBytes) { 1024 ALOGD("Bitmap_createFromParcel: Serialized SkColorSpace is larger than expected: " 1025 "%d bytes\n", colorSpaceSize); 1026 } 1027 1028 const void* data = p->readInplace(colorSpaceSize); 1029 if (data) { 1030 colorSpace = SkColorSpace::Deserialize(data, colorSpaceSize); 1031 } else { 1032 ALOGD("Bitmap_createFromParcel: Unable to read serialized SkColorSpace data\n"); 1033 } 1034 } 1035 const int width = p->readInt32(); 1036 const int height = p->readInt32(); 1037 const int rowBytes = p->readInt32(); 1038 const int density = p->readInt32(); 1039 1040 if (kN32_SkColorType != colorType && 1041 kRGBA_F16_SkColorType != colorType && 1042 kRGB_565_SkColorType != colorType && 1043 kARGB_4444_SkColorType != colorType && 1044 kAlpha_8_SkColorType != colorType) { 1045 SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType); 1046 return NULL; 1047 } 1048 1049 std::unique_ptr<SkBitmap> bitmap(new SkBitmap); 1050 if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType, colorSpace), 1051 rowBytes)) { 1052 return NULL; 1053 } 1054 1055 // Read the bitmap blob. 1056 size_t size = bitmap->getSize(); 1057 android::Parcel::ReadableBlob blob; 1058 android::status_t status = p->readBlob(size, &blob); 1059 if (status) { 1060 doThrowRE(env, "Could not read bitmap blob."); 1061 return NULL; 1062 } 1063 1064 // Map the bitmap in place from the ashmem region if possible otherwise copy. 1065 sk_sp<Bitmap> nativeBitmap; 1066 if (blob.fd() >= 0 && (blob.isMutable() || !isMutable) && (size >= ASHMEM_BITMAP_MIN_SIZE)) { 1067#if DEBUG_PARCEL 1068 ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob " 1069 "(fds %s)", 1070 isMutable ? "mutable" : "immutable", 1071 blob.isMutable() ? "mutable" : "immutable", 1072 p->allowFds() ? "allowed" : "forbidden"); 1073#endif 1074 // Dup the file descriptor so we can keep a reference to it after the Parcel 1075 // is disposed. 1076 int dupFd = dup(blob.fd()); 1077 if (dupFd < 0) { 1078 ALOGE("Error allocating dup fd. Error:%d", errno); 1079 blob.release(); 1080 doThrowRE(env, "Could not allocate dup blob fd."); 1081 return NULL; 1082 } 1083 1084 // Map the pixels in place and take ownership of the ashmem region. 1085 nativeBitmap = sk_sp<Bitmap>(GraphicsJNI::mapAshmemBitmap(env, bitmap.get(), 1086 dupFd, const_cast<void*>(blob.data()), size, !isMutable)); 1087 if (!nativeBitmap) { 1088 close(dupFd); 1089 blob.release(); 1090 doThrowRE(env, "Could not allocate ashmem pixel ref."); 1091 return NULL; 1092 } 1093 1094 // Clear the blob handle, don't release it. 1095 blob.clear(); 1096 } else { 1097#if DEBUG_PARCEL 1098 if (blob.fd() >= 0) { 1099 ALOGD("Bitmap.createFromParcel: copied contents of mutable bitmap " 1100 "from immutable blob (fds %s)", 1101 p->allowFds() ? "allowed" : "forbidden"); 1102 } else { 1103 ALOGD("Bitmap.createFromParcel: copied contents from %s blob " 1104 "(fds %s)", 1105 blob.isMutable() ? "mutable" : "immutable", 1106 p->allowFds() ? "allowed" : "forbidden"); 1107 } 1108#endif 1109 1110 // Copy the pixels into a new buffer. 1111 nativeBitmap = Bitmap::allocateHeapBitmap(bitmap.get()); 1112 if (!nativeBitmap) { 1113 blob.release(); 1114 doThrowRE(env, "Could not allocate java pixel ref."); 1115 return NULL; 1116 } 1117 memcpy(bitmap->getPixels(), blob.data(), size); 1118 1119 // Release the blob handle. 1120 blob.release(); 1121 } 1122 1123 return createBitmap(env, nativeBitmap.release(), 1124 getPremulBitmapCreateFlags(isMutable), NULL, NULL, density); 1125} 1126 1127static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, 1128 jlong bitmapHandle, 1129 jboolean isMutable, jint density, 1130 jobject parcel) { 1131 if (parcel == NULL) { 1132 SkDebugf("------- writeToParcel null parcel\n"); 1133 return JNI_FALSE; 1134 } 1135 1136 android::Parcel* p = android::parcelForJavaObject(env, parcel); 1137 SkBitmap bitmap; 1138 1139 auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle); 1140 bitmapWrapper->getSkBitmap(&bitmap); 1141 1142 p->writeInt32(isMutable); 1143 p->writeInt32(bitmap.colorType()); 1144 p->writeInt32(bitmap.alphaType()); 1145 SkColorSpace* colorSpace = bitmap.colorSpace(); 1146 if (colorSpace != nullptr && bitmap.colorType() != kRGBA_F16_SkColorType) { 1147 sk_sp<SkData> data = colorSpace->serialize(); 1148 size_t size = data->size(); 1149 p->writeUint32(size); 1150 if (size > 0) { 1151 if (size > kMaxColorSpaceSerializedBytes) { 1152 ALOGD("Bitmap_writeToParcel: Serialized SkColorSpace is larger than expected: " 1153 "%zu bytes\n", size); 1154 } 1155 1156 p->write(data->data(), size); 1157 } 1158 } else { 1159 p->writeUint32(0); 1160 } 1161 p->writeInt32(bitmap.width()); 1162 p->writeInt32(bitmap.height()); 1163 p->writeInt32(bitmap.rowBytes()); 1164 p->writeInt32(density); 1165 1166 // Transfer the underlying ashmem region if we have one and it's immutable. 1167 android::status_t status; 1168 int fd = bitmapWrapper->bitmap().getAshmemFd(); 1169 if (fd >= 0 && !isMutable && p->allowFds()) { 1170#if DEBUG_PARCEL 1171 ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as " 1172 "immutable blob (fds %s)", 1173 p->allowFds() ? "allowed" : "forbidden"); 1174#endif 1175 1176 status = p->writeDupImmutableBlobFileDescriptor(fd); 1177 if (status) { 1178 doThrowRE(env, "Could not write bitmap blob file descriptor."); 1179 return JNI_FALSE; 1180 } 1181 return JNI_TRUE; 1182 } 1183 1184 // Copy the bitmap to a new blob. 1185 bool mutableCopy = isMutable; 1186#if DEBUG_PARCEL 1187 ALOGD("Bitmap.writeToParcel: copying %s bitmap into new %s blob (fds %s)", 1188 isMutable ? "mutable" : "immutable", 1189 mutableCopy ? "mutable" : "immutable", 1190 p->allowFds() ? "allowed" : "forbidden"); 1191#endif 1192 1193 size_t size = bitmap.getSize(); 1194 android::Parcel::WritableBlob blob; 1195 status = p->writeBlob(size, mutableCopy, &blob); 1196 if (status) { 1197 doThrowRE(env, "Could not copy bitmap to parcel blob."); 1198 return JNI_FALSE; 1199 } 1200 1201 const void* pSrc = bitmap.getPixels(); 1202 if (pSrc == NULL) { 1203 memset(blob.data(), 0, size); 1204 } else { 1205 memcpy(blob.data(), pSrc, size); 1206 } 1207 1208 blob.release(); 1209 return JNI_TRUE; 1210} 1211 1212static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz, 1213 jlong srcHandle, jlong paintHandle, 1214 jintArray offsetXY) { 1215 SkBitmap src; 1216 reinterpret_cast<BitmapWrapper*>(srcHandle)->getSkBitmap(&src); 1217 const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle); 1218 SkIPoint offset; 1219 SkBitmap dst; 1220 HeapAllocator allocator; 1221 1222 src.extractAlpha(&dst, paint, &allocator, &offset); 1223 // If Skia can't allocate pixels for destination bitmap, it resets 1224 // it, that is set its pixels buffer to NULL, and zero width and height. 1225 if (dst.getPixels() == NULL && src.getPixels() != NULL) { 1226 doThrowOOME(env, "failed to allocate pixels for alpha"); 1227 return NULL; 1228 } 1229 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) { 1230 int* array = env->GetIntArrayElements(offsetXY, NULL); 1231 array[0] = offset.fX; 1232 array[1] = offset.fY; 1233 env->ReleaseIntArrayElements(offsetXY, array, 0); 1234 } 1235 1236 return createBitmap(env, allocator.getStorageObjAndReset(), 1237 getPremulBitmapCreateFlags(true)); 1238} 1239 1240/////////////////////////////////////////////////////////////////////////////// 1241 1242static jboolean Bitmap_isSRGB(JNIEnv* env, jobject, jlong bitmapHandle) { 1243 LocalScopedBitmap bitmapHolder(bitmapHandle); 1244 if (!bitmapHolder.valid()) return JNI_TRUE; 1245 1246 SkColorSpace* colorSpace = bitmapHolder->info().colorSpace(); 1247 return GraphicsJNI::isColorSpaceSRGB(colorSpace); 1248} 1249 1250static jboolean Bitmap_getColorSpace(JNIEnv* env, jobject, jlong bitmapHandle, 1251 jfloatArray xyzArray, jfloatArray paramsArray) { 1252 1253 LocalScopedBitmap bitmapHolder(bitmapHandle); 1254 if (!bitmapHolder.valid()) return JNI_FALSE; 1255 1256 SkColorSpace* colorSpace = bitmapHolder->info().colorSpace(); 1257 if (colorSpace == nullptr) return JNI_FALSE; 1258 1259 SkMatrix44 xyzMatrix(SkMatrix44::kUninitialized_Constructor); 1260 if (!colorSpace->toXYZD50(&xyzMatrix)) return JNI_FALSE; 1261 1262 jfloat* xyz = env->GetFloatArrayElements(xyzArray, NULL); 1263 xyz[0] = xyzMatrix.getFloat(0, 0); 1264 xyz[1] = xyzMatrix.getFloat(1, 0); 1265 xyz[2] = xyzMatrix.getFloat(2, 0); 1266 xyz[3] = xyzMatrix.getFloat(0, 1); 1267 xyz[4] = xyzMatrix.getFloat(1, 1); 1268 xyz[5] = xyzMatrix.getFloat(2, 1); 1269 xyz[6] = xyzMatrix.getFloat(0, 2); 1270 xyz[7] = xyzMatrix.getFloat(1, 2); 1271 xyz[8] = xyzMatrix.getFloat(2, 2); 1272 env->ReleaseFloatArrayElements(xyzArray, xyz, 0); 1273 1274 SkColorSpaceTransferFn transferParams; 1275 if (!colorSpace->isNumericalTransferFn(&transferParams)) return JNI_FALSE; 1276 1277 jfloat* params = env->GetFloatArrayElements(paramsArray, NULL); 1278 params[0] = transferParams.fA; 1279 params[1] = transferParams.fB; 1280 params[2] = transferParams.fC; 1281 params[3] = transferParams.fD; 1282 params[4] = transferParams.fE; 1283 params[5] = transferParams.fF; 1284 params[6] = transferParams.fG; 1285 env->ReleaseFloatArrayElements(paramsArray, params, 0); 1286 1287 return JNI_TRUE; 1288} 1289 1290/////////////////////////////////////////////////////////////////////////////// 1291 1292static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle, 1293 jint x, jint y) { 1294 SkBitmap bitmap; 1295 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1296 1297 ToColorProc proc = ChooseToColorProc(bitmap); 1298 if (NULL == proc) { 1299 return 0; 1300 } 1301 const void* src = bitmap.getAddr(x, y); 1302 if (NULL == src) { 1303 return 0; 1304 } 1305 1306 SkColor dst[1]; 1307 proc(dst, src, 1); 1308 1309 SkColorSpace* colorSpace = bitmap.colorSpace(); 1310 if (bitmap.colorType() != kRGBA_F16_SkColorType && 1311 !GraphicsJNI::isColorSpaceSRGB(colorSpace)) { 1312 auto sRGB = SkColorSpace::MakeSRGB(); 1313 auto xform = SkColorSpaceXform::New(colorSpace, sRGB.get()); 1314 xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, &dst[0], 1315 SkColorSpaceXform::kBGRA_8888_ColorFormat, &dst[0], 1, 1316 SkAlphaType::kUnpremul_SkAlphaType); 1317 } 1318 1319 return static_cast<jint>(dst[0]); 1320} 1321 1322static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle, 1323 jintArray pixelArray, jint offset, jint stride, 1324 jint x, jint y, jint width, jint height) { 1325 SkBitmap bitmap; 1326 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1327 1328 ToColorProc proc = ChooseToColorProc(bitmap); 1329 if (NULL == proc) { 1330 return; 1331 } 1332 const void* src = bitmap.getAddr(x, y); 1333 if (NULL == src) { 1334 return; 1335 } 1336 1337 jint* dst = env->GetIntArrayElements(pixelArray, NULL); 1338 SkColor* d = (SkColor*)dst + offset; 1339 1340 SkColorSpace* colorSpace = bitmap.colorSpace(); 1341 if (bitmap.colorType() == kRGBA_F16_SkColorType || 1342 GraphicsJNI::isColorSpaceSRGB(colorSpace)) { 1343 while (--height >= 0) { 1344 proc(d, src, width); 1345 d += stride; 1346 src = (void*)((const char*)src + bitmap.rowBytes()); 1347 } 1348 } else { 1349 auto sRGB = SkColorSpace::MakeSRGB(); 1350 auto xform = SkColorSpaceXform::New(colorSpace, sRGB.get()); 1351 1352 while (--height >= 0) { 1353 proc(d, src, width); 1354 1355 xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, d, 1356 SkColorSpaceXform::kBGRA_8888_ColorFormat, d, width, 1357 SkAlphaType::kUnpremul_SkAlphaType); 1358 1359 d += stride; 1360 src = (void*)((const char*)src + bitmap.rowBytes()); 1361 } 1362 } 1363 1364 env->ReleaseIntArrayElements(pixelArray, dst, 0); 1365} 1366 1367/////////////////////////////////////////////////////////////////////////////// 1368 1369static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle, 1370 jint x, jint y, jint colorHandle) { 1371 SkBitmap bitmap; 1372 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1373 SkColor color = static_cast<SkColor>(colorHandle); 1374 if (NULL == bitmap.getPixels()) { 1375 return; 1376 } 1377 1378 FromColorProc proc = ChooseFromColorProc(bitmap); 1379 if (NULL == proc) { 1380 return; 1381 } 1382 1383 SkColorSpace* colorSpace = bitmap.colorSpace(); 1384 if (bitmap.colorType() != kRGBA_F16_SkColorType && 1385 !GraphicsJNI::isColorSpaceSRGB(colorSpace)) { 1386 auto sRGB = SkColorSpace::MakeSRGB(); 1387 auto xform = SkColorSpaceXform::New(sRGB.get(), colorSpace); 1388 xform->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, &color, 1389 SkColorSpaceXform::kBGRA_8888_ColorFormat, &color, 1, 1390 SkAlphaType::kUnpremul_SkAlphaType); 1391 } 1392 1393 proc(bitmap.getAddr(x, y), &color, 1, x, y); 1394 bitmap.notifyPixelsChanged(); 1395} 1396 1397static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle, 1398 jintArray pixelArray, jint offset, jint stride, 1399 jint x, jint y, jint width, jint height) { 1400 SkBitmap bitmap; 1401 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1402 GraphicsJNI::SetPixels(env, pixelArray, offset, stride, 1403 x, y, width, height, bitmap); 1404} 1405 1406static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject, 1407 jlong bitmapHandle, jobject jbuffer) { 1408 SkBitmap bitmap; 1409 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1410 const void* src = bitmap.getPixels(); 1411 1412 if (NULL != src) { 1413 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE); 1414 1415 // the java side has already checked that buffer is large enough 1416 memcpy(abp.pointer(), src, bitmap.getSize()); 1417 } 1418} 1419 1420static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject, 1421 jlong bitmapHandle, jobject jbuffer) { 1422 SkBitmap bitmap; 1423 reinterpret_cast<BitmapWrapper*>(bitmapHandle)->getSkBitmap(&bitmap); 1424 void* dst = bitmap.getPixels(); 1425 1426 if (NULL != dst) { 1427 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE); 1428 // the java side has already checked that buffer is large enough 1429 memcpy(dst, abp.pointer(), bitmap.getSize()); 1430 bitmap.notifyPixelsChanged(); 1431 } 1432} 1433 1434static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle, jlong bm1Handle) { 1435 SkBitmap bm0; 1436 SkBitmap bm1; 1437 1438 LocalScopedBitmap bitmap0(bm0Handle); 1439 LocalScopedBitmap bitmap1(bm1Handle); 1440 1441 // Paying the price for making Hardware Bitmap as Config: 1442 // later check for colorType will pass successfully, 1443 // because Hardware Config internally may be RGBA8888 or smth like that. 1444 if (bitmap0->isHardware() != bitmap1->isHardware()) { 1445 return JNI_FALSE; 1446 } 1447 1448 bitmap0->bitmap().getSkBitmap(&bm0); 1449 bitmap1->bitmap().getSkBitmap(&bm1); 1450 if (bm0.width() != bm1.width() 1451 || bm0.height() != bm1.height() 1452 || bm0.colorType() != bm1.colorType() 1453 || bm0.alphaType() != bm1.alphaType() 1454 || !SkColorSpace::Equals(bm0.colorSpace(), bm1.colorSpace())) { 1455 return JNI_FALSE; 1456 } 1457 1458 // if we can't load the pixels, return false 1459 if (NULL == bm0.getPixels() || NULL == bm1.getPixels()) { 1460 return JNI_FALSE; 1461 } 1462 1463 // now compare each scanline. We can't do the entire buffer at once, 1464 // since we don't care about the pixel values that might extend beyond 1465 // the width (since the scanline might be larger than the logical width) 1466 const int h = bm0.height(); 1467 const size_t size = bm0.width() * bm0.bytesPerPixel(); 1468 for (int y = 0; y < h; y++) { 1469 // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config 1470 // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0 1471 // and bm1 both have pixel data() (have passed NULL == getPixels() check), 1472 // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE 1473 // to warn user those 2 unrecognized config bitmaps may be different. 1474 void *bm0Addr = bm0.getAddr(0, y); 1475 void *bm1Addr = bm1.getAddr(0, y); 1476 1477 if(bm0Addr == NULL || bm1Addr == NULL) { 1478 return JNI_FALSE; 1479 } 1480 1481 if (memcmp(bm0Addr, bm1Addr, size) != 0) { 1482 return JNI_FALSE; 1483 } 1484 } 1485 return JNI_TRUE; 1486} 1487 1488static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapPtr) { 1489 LocalScopedBitmap bitmapHandle(bitmapPtr); 1490 if (!bitmapHandle.valid()) return; 1491 android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmapHandle->bitmap()); 1492} 1493 1494static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr) { 1495 LocalScopedBitmap bitmapHandle(bitmapPtr); 1496 return static_cast<jint>(bitmapHandle->getAllocationByteCount()); 1497} 1498 1499static jobject Bitmap_copyPreserveInternalConfig(JNIEnv* env, jobject, jlong bitmapPtr) { 1500 LocalScopedBitmap bitmapHandle(bitmapPtr); 1501 LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(), 1502 "Hardware config is only supported config in Bitmap_nativeCopyPreserveInternalConfig"); 1503 Bitmap& hwuiBitmap = bitmapHandle->bitmap(); 1504 SkBitmap src; 1505 hwuiBitmap.getSkBitmap(&src); 1506 1507 SkBitmap result; 1508 HeapAllocator allocator; 1509 if (!bitmapCopyTo(&result, hwuiBitmap.info().colorType(), src, &allocator)) { 1510 doThrowRE(env, "Could not copy a hardware bitmap."); 1511 return NULL; 1512 } 1513 return createBitmap(env, allocator.getStorageObjAndReset(), getPremulBitmapCreateFlags(false)); 1514} 1515 1516static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphicBuffer) { 1517 sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer)); 1518 sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer); 1519 if (!bitmap.get()) { 1520 ALOGW("failed to create hardware bitmap from graphic buffer"); 1521 return NULL; 1522 } 1523 return bitmap::createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false)); 1524} 1525 1526static jobject Bitmap_createGraphicBufferHandle(JNIEnv* env, jobject, jlong bitmapPtr) { 1527 LocalScopedBitmap bitmapHandle(bitmapPtr); 1528 LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(), 1529 "Hardware config is only supported config in Bitmap_getGraphicBuffer"); 1530 1531 Bitmap& hwuiBitmap = bitmapHandle->bitmap(); 1532 sp<GraphicBuffer> buffer(hwuiBitmap.graphicBuffer()); 1533 return createJavaGraphicBuffer(env, buffer); 1534} 1535 1536static void Bitmap_copyColorSpace(JNIEnv* env, jobject, jlong srcBitmapPtr, jlong dstBitmapPtr) { 1537 LocalScopedBitmap srcBitmapHandle(srcBitmapPtr); 1538 LocalScopedBitmap dstBitmapHandle(dstBitmapPtr); 1539 1540 dstBitmapHandle->bitmap().setColorSpace(srcBitmapHandle->bitmap().info().refColorSpace()); 1541} 1542 1543/////////////////////////////////////////////////////////////////////////////// 1544 1545static const JNINativeMethod gBitmapMethods[] = { 1546 { "nativeCreate", "([IIIIIIZ[FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)Landroid/graphics/Bitmap;", 1547 (void*)Bitmap_creator }, 1548 { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;", 1549 (void*)Bitmap_copy }, 1550 { "nativeCopyAshmem", "(J)Landroid/graphics/Bitmap;", 1551 (void*)Bitmap_copyAshmem }, 1552 { "nativeCopyAshmemConfig", "(JI)Landroid/graphics/Bitmap;", 1553 (void*)Bitmap_copyAshmemConfig }, 1554 { "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer }, 1555 { "nativeRecycle", "(J)Z", (void*)Bitmap_recycle }, 1556 { "nativeReconfigure", "(JIIIZ)V", (void*)Bitmap_reconfigure }, 1557 { "nativeCompress", "(JIILjava/io/OutputStream;[B)Z", 1558 (void*)Bitmap_compress }, 1559 { "nativeErase", "(JI)V", (void*)Bitmap_erase }, 1560 { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes }, 1561 { "nativeConfig", "(J)I", (void*)Bitmap_config }, 1562 { "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha }, 1563 { "nativeIsPremultiplied", "(J)Z", (void*)Bitmap_isPremultiplied}, 1564 { "nativeSetHasAlpha", "(JZZ)V", (void*)Bitmap_setHasAlpha}, 1565 { "nativeSetPremultiplied", "(JZ)V", (void*)Bitmap_setPremultiplied}, 1566 { "nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap }, 1567 { "nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap }, 1568 { "nativeCreateFromParcel", 1569 "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;", 1570 (void*)Bitmap_createFromParcel }, 1571 { "nativeWriteToParcel", "(JZILandroid/os/Parcel;)Z", 1572 (void*)Bitmap_writeToParcel }, 1573 { "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;", 1574 (void*)Bitmap_extractAlpha }, 1575 { "nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId }, 1576 { "nativeGetPixel", "(JII)I", (void*)Bitmap_getPixel }, 1577 { "nativeGetPixels", "(J[IIIIIII)V", (void*)Bitmap_getPixels }, 1578 { "nativeSetPixel", "(JIII)V", (void*)Bitmap_setPixel }, 1579 { "nativeSetPixels", "(J[IIIIIII)V", (void*)Bitmap_setPixels }, 1580 { "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V", 1581 (void*)Bitmap_copyPixelsToBuffer }, 1582 { "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V", 1583 (void*)Bitmap_copyPixelsFromBuffer }, 1584 { "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs }, 1585 { "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw }, 1586 { "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount }, 1587 { "nativeCopyPreserveInternalConfig", "(J)Landroid/graphics/Bitmap;", 1588 (void*)Bitmap_copyPreserveInternalConfig }, 1589 { "nativeCreateHardwareBitmap", "(Landroid/graphics/GraphicBuffer;)Landroid/graphics/Bitmap;", 1590 (void*) Bitmap_createHardwareBitmap }, 1591 { "nativeCreateGraphicBufferHandle", "(J)Landroid/graphics/GraphicBuffer;", 1592 (void*) Bitmap_createGraphicBufferHandle }, 1593 { "nativeGetColorSpace", "(J[F[F)Z", (void*)Bitmap_getColorSpace }, 1594 { "nativeIsSRGB", "(J)Z", (void*)Bitmap_isSRGB }, 1595 { "nativeCopyColorSpace", "(JJ)V", 1596 (void*)Bitmap_copyColorSpace }, 1597}; 1598 1599int register_android_graphics_Bitmap(JNIEnv* env) 1600{ 1601 gBitmap_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Bitmap")); 1602 gBitmap_nativePtr = GetFieldIDOrDie(env, gBitmap_class, "mNativePtr", "J"); 1603 gBitmap_constructorMethodID = GetMethodIDOrDie(env, gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V"); 1604 gBitmap_reinitMethodID = GetMethodIDOrDie(env, gBitmap_class, "reinit", "(IIZ)V"); 1605 gBitmap_getAllocationByteCountMethodID = GetMethodIDOrDie(env, gBitmap_class, "getAllocationByteCount", "()I"); 1606 return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods, 1607 NELEM(gBitmapMethods)); 1608} 1609