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