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