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