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