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