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