Bitmap.cpp revision c69853c8b72540e5031d28e03cbce5a390c6959f
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 698 PixelRef* nativeBitmap = GraphicsJNI::allocateHeapPixelRef(&bitmap, NULL); 699 if (!nativeBitmap) { 700 return NULL; 701 } 702 703 if (jColors != NULL) { 704 GraphicsJNI::SetPixels(env, jColors, offset, stride, 705 0, 0, width, height, bitmap); 706 } 707 708 return createBitmap(env, nativeBitmap, 709 getPremulBitmapCreateFlags(isMutable)); 710} 711 712static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle, 713 jint dstConfigHandle, jboolean isMutable) { 714 SkBitmap src; 715 reinterpret_cast<Bitmap*>(srcHandle)->getSkBitmap(&src); 716 SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle); 717 SkBitmap result; 718 HeapAllocator allocator; 719 720 if (!src.copyTo(&result, dstCT, &allocator)) { 721 return NULL; 722 } 723 auto pixelRef = allocator.getStorageObjAndReset(); 724 return createBitmap(env, pixelRef, getPremulBitmapCreateFlags(isMutable)); 725} 726 727static PixelRef* Bitmap_copyAshmemImpl(JNIEnv* env, SkBitmap& src, SkColorType& dstCT) { 728 SkBitmap result; 729 730 AshmemPixelAllocator allocator(env); 731 if (!src.copyTo(&result, dstCT, &allocator)) { 732 return NULL; 733 } 734 auto pixelRef = allocator.getStorageObjAndReset(); 735 pixelRef->setImmutable(); 736 return pixelRef; 737} 738 739static jobject Bitmap_copyAshmem(JNIEnv* env, jobject, jlong srcHandle) { 740 SkBitmap src; 741 reinterpret_cast<Bitmap*>(srcHandle)->getSkBitmap(&src); 742 SkColorType dstCT = src.colorType(); 743 auto pixelRef = Bitmap_copyAshmemImpl(env, src, dstCT); 744 jobject ret = createBitmap(env, pixelRef, getPremulBitmapCreateFlags(false)); 745 return ret; 746} 747 748static jobject Bitmap_copyAshmemConfig(JNIEnv* env, jobject, jlong srcHandle, jint dstConfigHandle) { 749 SkBitmap src; 750 reinterpret_cast<Bitmap*>(srcHandle)->getSkBitmap(&src); 751 SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle); 752 auto pixelRef = Bitmap_copyAshmemImpl(env, src, dstCT); 753 jobject ret = createBitmap(env, pixelRef, getPremulBitmapCreateFlags(false)); 754 return ret; 755} 756 757static void Bitmap_destruct(Bitmap* bitmap) { 758 delete bitmap; 759} 760 761static jlong Bitmap_getNativeFinalizer(JNIEnv*, jobject) { 762 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Bitmap_destruct)); 763} 764 765static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) { 766 LocalScopedBitmap bitmap(bitmapHandle); 767 bitmap->freePixels(); 768 return JNI_TRUE; 769} 770 771static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle, 772 jint width, jint height, jint configHandle, jboolean requestPremul) { 773 LocalScopedBitmap bitmap(bitmapHandle); 774 bitmap->assertValid(); 775 SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle); 776 777 // ARGB_4444 is a deprecated format, convert automatically to 8888 778 if (colorType == kARGB_4444_SkColorType) { 779 colorType = kN32_SkColorType; 780 } 781 size_t requestedSize = width * height * SkColorTypeBytesPerPixel(colorType); 782 if (requestedSize > bitmap->getAllocationByteCount()) { 783 // done in native as there's no way to get BytesPerPixel in Java 784 doThrowIAE(env, "Bitmap not large enough to support new configuration"); 785 return; 786 } 787 SkAlphaType alphaType; 788 if (bitmap->info().colorType() != kRGB_565_SkColorType 789 && bitmap->info().alphaType() == kOpaque_SkAlphaType) { 790 // If the original bitmap was set to opaque, keep that setting, unless it 791 // was 565, which is required to be opaque. 792 alphaType = kOpaque_SkAlphaType; 793 } else { 794 // Otherwise respect the premultiplied request. 795 alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType; 796 } 797 bitmap->pixelRef()->reconfigure(SkImageInfo::Make(width, height, colorType, alphaType)); 798} 799 800// These must match the int values in Bitmap.java 801enum JavaEncodeFormat { 802 kJPEG_JavaEncodeFormat = 0, 803 kPNG_JavaEncodeFormat = 1, 804 kWEBP_JavaEncodeFormat = 2 805}; 806 807static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle, 808 jint format, jint quality, 809 jobject jstream, jbyteArray jstorage) { 810 811 LocalScopedBitmap bitmap(bitmapHandle); 812 SkImageEncoder::Type fm; 813 814 switch (format) { 815 case kJPEG_JavaEncodeFormat: 816 fm = SkImageEncoder::kJPEG_Type; 817 break; 818 case kPNG_JavaEncodeFormat: 819 fm = SkImageEncoder::kPNG_Type; 820 break; 821 case kWEBP_JavaEncodeFormat: 822 fm = SkImageEncoder::kWEBP_Type; 823 break; 824 default: 825 return JNI_FALSE; 826 } 827 828 if (!bitmap.valid()) { 829 return JNI_FALSE; 830 } 831 832 bool success = false; 833 834 std::unique_ptr<SkWStream> strm(CreateJavaOutputStreamAdaptor(env, jstream, jstorage)); 835 if (!strm.get()) { 836 return JNI_FALSE; 837 } 838 839 std::unique_ptr<SkImageEncoder> encoder(SkImageEncoder::Create(fm)); 840 if (encoder.get()) { 841 SkBitmap skbitmap; 842 bitmap->getSkBitmap(&skbitmap); 843 success = encoder->encodeStream(strm.get(), skbitmap, quality); 844 } 845 return success ? JNI_TRUE : JNI_FALSE; 846} 847 848static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) { 849 LocalScopedBitmap bitmap(bitmapHandle); 850 SkBitmap skBitmap; 851 bitmap->getSkBitmap(&skBitmap); 852 skBitmap.eraseColor(color); 853} 854 855static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) { 856 LocalScopedBitmap bitmap(bitmapHandle); 857 return static_cast<jint>(bitmap->rowBytes()); 858} 859 860static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) { 861 LocalScopedBitmap bitmap(bitmapHandle); 862 return GraphicsJNI::colorTypeToLegacyBitmapConfig(bitmap->info().colorType()); 863} 864 865static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) { 866 LocalScopedBitmap bitmap(bitmapHandle); 867 return static_cast<jint>(bitmap->getGenerationID()); 868} 869 870static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) { 871 LocalScopedBitmap bitmap(bitmapHandle); 872 if (bitmap->info().alphaType() == kPremul_SkAlphaType) { 873 return JNI_TRUE; 874 } 875 return JNI_FALSE; 876} 877 878static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) { 879 LocalScopedBitmap bitmap(bitmapHandle); 880 return !bitmap->info().isOpaque() ? JNI_TRUE : JNI_FALSE; 881} 882 883static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle, 884 jboolean hasAlpha, jboolean requestPremul) { 885 LocalScopedBitmap bitmap(bitmapHandle); 886 if (hasAlpha) { 887 bitmap->setAlphaType( 888 requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType); 889 } else { 890 bitmap->setAlphaType(kOpaque_SkAlphaType); 891 } 892} 893 894static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle, 895 jboolean isPremul) { 896 LocalScopedBitmap bitmap(bitmapHandle); 897 if (!bitmap->info().isOpaque()) { 898 if (isPremul) { 899 bitmap->setAlphaType(kPremul_SkAlphaType); 900 } else { 901 bitmap->setAlphaType(kUnpremul_SkAlphaType); 902 } 903 } 904} 905 906static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) { 907 LocalScopedBitmap bitmap(bitmapHandle); 908 return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE; 909} 910 911static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle, 912 jboolean hasMipMap) { 913 LocalScopedBitmap bitmap(bitmapHandle); 914 bitmap->setHasHardwareMipMap(hasMipMap); 915} 916 917/////////////////////////////////////////////////////////////////////////////// 918 919static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { 920 if (parcel == NULL) { 921 SkDebugf("-------- unparcel parcel is NULL\n"); 922 return NULL; 923 } 924 925 android::Parcel* p = android::parcelForJavaObject(env, parcel); 926 927 const bool isMutable = p->readInt32() != 0; 928 const SkColorType colorType = (SkColorType)p->readInt32(); 929 const SkAlphaType alphaType = (SkAlphaType)p->readInt32(); 930 const int width = p->readInt32(); 931 const int height = p->readInt32(); 932 const int rowBytes = p->readInt32(); 933 const int density = p->readInt32(); 934 935 if (kN32_SkColorType != colorType && 936 kRGB_565_SkColorType != colorType && 937 kARGB_4444_SkColorType != colorType && 938 kIndex_8_SkColorType != colorType && 939 kAlpha_8_SkColorType != colorType) { 940 SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType); 941 return NULL; 942 } 943 944 std::unique_ptr<SkBitmap> bitmap(new SkBitmap); 945 946 if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType), rowBytes)) { 947 return NULL; 948 } 949 950 SkColorTable* ctable = NULL; 951 if (colorType == kIndex_8_SkColorType) { 952 int count = p->readInt32(); 953 if (count < 0 || count > 256) { 954 // The data is corrupt, since SkColorTable enforces a value between 0 and 256, 955 // inclusive. 956 return NULL; 957 } 958 if (count > 0) { 959 size_t size = count * sizeof(SkPMColor); 960 const SkPMColor* src = (const SkPMColor*)p->readInplace(size); 961 if (src == NULL) { 962 return NULL; 963 } 964 ctable = new SkColorTable(src, count); 965 } 966 } 967 968 // Read the bitmap blob. 969 size_t size = bitmap->getSize(); 970 android::Parcel::ReadableBlob blob; 971 android::status_t status = p->readBlob(size, &blob); 972 if (status) { 973 SkSafeUnref(ctable); 974 doThrowRE(env, "Could not read bitmap blob."); 975 return NULL; 976 } 977 978 // Map the bitmap in place from the ashmem region if possible otherwise copy. 979 PixelRef* nativeBitmap; 980 if (blob.fd() >= 0 && (blob.isMutable() || !isMutable) && (size >= ASHMEM_BITMAP_MIN_SIZE)) { 981#if DEBUG_PARCEL 982 ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob " 983 "(fds %s)", 984 isMutable ? "mutable" : "immutable", 985 blob.isMutable() ? "mutable" : "immutable", 986 p->allowFds() ? "allowed" : "forbidden"); 987#endif 988 // Dup the file descriptor so we can keep a reference to it after the Parcel 989 // is disposed. 990 int dupFd = dup(blob.fd()); 991 if (dupFd < 0) { 992 ALOGE("Error allocating dup fd. Error:%d", errno); 993 blob.release(); 994 SkSafeUnref(ctable); 995 doThrowRE(env, "Could not allocate dup blob fd."); 996 return NULL; 997 } 998 999 // Map the pixels in place and take ownership of the ashmem region. 1000 nativeBitmap = GraphicsJNI::mapAshmemPixelRef(env, bitmap.get(), 1001 ctable, dupFd, const_cast<void*>(blob.data()), size, !isMutable); 1002 SkSafeUnref(ctable); 1003 if (!nativeBitmap) { 1004 close(dupFd); 1005 blob.release(); 1006 doThrowRE(env, "Could not allocate ashmem pixel ref."); 1007 return NULL; 1008 } 1009 1010 // Clear the blob handle, don't release it. 1011 blob.clear(); 1012 } else { 1013#if DEBUG_PARCEL 1014 if (blob.fd() >= 0) { 1015 ALOGD("Bitmap.createFromParcel: copied contents of mutable bitmap " 1016 "from immutable blob (fds %s)", 1017 p->allowFds() ? "allowed" : "forbidden"); 1018 } else { 1019 ALOGD("Bitmap.createFromParcel: copied contents from %s blob " 1020 "(fds %s)", 1021 blob.isMutable() ? "mutable" : "immutable", 1022 p->allowFds() ? "allowed" : "forbidden"); 1023 } 1024#endif 1025 1026 // Copy the pixels into a new buffer. 1027 nativeBitmap = GraphicsJNI::allocateHeapPixelRef(bitmap.get(), ctable); 1028 SkSafeUnref(ctable); 1029 if (!nativeBitmap) { 1030 blob.release(); 1031 doThrowRE(env, "Could not allocate java pixel ref."); 1032 return NULL; 1033 } 1034 bitmap->lockPixels(); 1035 memcpy(bitmap->getPixels(), blob.data(), size); 1036 bitmap->unlockPixels(); 1037 1038 // Release the blob handle. 1039 blob.release(); 1040 } 1041 1042 return createBitmap(env, nativeBitmap, 1043 getPremulBitmapCreateFlags(isMutable), NULL, NULL, density); 1044} 1045 1046static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, 1047 jlong bitmapHandle, 1048 jboolean isMutable, jint density, 1049 jobject parcel) { 1050 if (parcel == NULL) { 1051 SkDebugf("------- writeToParcel null parcel\n"); 1052 return JNI_FALSE; 1053 } 1054 1055 android::Parcel* p = android::parcelForJavaObject(env, parcel); 1056 SkBitmap bitmap; 1057 1058 auto androidBitmap = reinterpret_cast<Bitmap*>(bitmapHandle); 1059 androidBitmap->getSkBitmap(&bitmap); 1060 1061 p->writeInt32(isMutable); 1062 p->writeInt32(bitmap.colorType()); 1063 p->writeInt32(bitmap.alphaType()); 1064 p->writeInt32(bitmap.width()); 1065 p->writeInt32(bitmap.height()); 1066 p->writeInt32(bitmap.rowBytes()); 1067 p->writeInt32(density); 1068 1069 if (bitmap.colorType() == kIndex_8_SkColorType) { 1070 // The bitmap needs to be locked to access its color table. 1071 SkAutoLockPixels alp(bitmap); 1072 SkColorTable* ctable = bitmap.getColorTable(); 1073 if (ctable != NULL) { 1074 int count = ctable->count(); 1075 p->writeInt32(count); 1076 memcpy(p->writeInplace(count * sizeof(SkPMColor)), 1077 ctable->readColors(), count * sizeof(SkPMColor)); 1078 } else { 1079 p->writeInt32(0); // indicate no ctable 1080 } 1081 } 1082 1083 // Transfer the underlying ashmem region if we have one and it's immutable. 1084 android::status_t status; 1085 int fd = androidBitmap->pixelRef()->getAshmemFd(); 1086 if (fd >= 0 && !isMutable && p->allowFds()) { 1087#if DEBUG_PARCEL 1088 ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as " 1089 "immutable blob (fds %s)", 1090 p->allowFds() ? "allowed" : "forbidden"); 1091#endif 1092 1093 status = p->writeDupImmutableBlobFileDescriptor(fd); 1094 if (status) { 1095 doThrowRE(env, "Could not write bitmap blob file descriptor."); 1096 return JNI_FALSE; 1097 } 1098 return JNI_TRUE; 1099 } 1100 1101 // Copy the bitmap to a new blob. 1102 bool mutableCopy = isMutable; 1103#if DEBUG_PARCEL 1104 ALOGD("Bitmap.writeToParcel: copying %s bitmap into new %s blob (fds %s)", 1105 isMutable ? "mutable" : "immutable", 1106 mutableCopy ? "mutable" : "immutable", 1107 p->allowFds() ? "allowed" : "forbidden"); 1108#endif 1109 1110 size_t size = bitmap.getSize(); 1111 android::Parcel::WritableBlob blob; 1112 status = p->writeBlob(size, mutableCopy, &blob); 1113 if (status) { 1114 doThrowRE(env, "Could not copy bitmap to parcel blob."); 1115 return JNI_FALSE; 1116 } 1117 1118 bitmap.lockPixels(); 1119 const void* pSrc = bitmap.getPixels(); 1120 if (pSrc == NULL) { 1121 memset(blob.data(), 0, size); 1122 } else { 1123 memcpy(blob.data(), pSrc, size); 1124 } 1125 bitmap.unlockPixels(); 1126 1127 blob.release(); 1128 return JNI_TRUE; 1129} 1130 1131static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz, 1132 jlong srcHandle, jlong paintHandle, 1133 jintArray offsetXY) { 1134 SkBitmap src; 1135 reinterpret_cast<Bitmap*>(srcHandle)->getSkBitmap(&src); 1136 const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle); 1137 SkIPoint offset; 1138 SkBitmap dst; 1139 HeapAllocator allocator; 1140 1141 src.extractAlpha(&dst, paint, &allocator, &offset); 1142 // If Skia can't allocate pixels for destination bitmap, it resets 1143 // it, that is set its pixels buffer to NULL, and zero width and height. 1144 if (dst.getPixels() == NULL && src.getPixels() != NULL) { 1145 doThrowOOME(env, "failed to allocate pixels for alpha"); 1146 return NULL; 1147 } 1148 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) { 1149 int* array = env->GetIntArrayElements(offsetXY, NULL); 1150 array[0] = offset.fX; 1151 array[1] = offset.fY; 1152 env->ReleaseIntArrayElements(offsetXY, array, 0); 1153 } 1154 1155 return createBitmap(env, allocator.getStorageObjAndReset(), 1156 getPremulBitmapCreateFlags(true)); 1157} 1158 1159/////////////////////////////////////////////////////////////////////////////// 1160 1161static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle, 1162 jint x, jint y) { 1163 SkBitmap bitmap; 1164 reinterpret_cast<Bitmap*>(bitmapHandle)->getSkBitmap(&bitmap); 1165 SkAutoLockPixels alp(bitmap); 1166 1167 ToColorProc proc = ChooseToColorProc(bitmap); 1168 if (NULL == proc) { 1169 return 0; 1170 } 1171 const void* src = bitmap.getAddr(x, y); 1172 if (NULL == src) { 1173 return 0; 1174 } 1175 1176 SkColor dst[1]; 1177 proc(dst, src, 1, bitmap.getColorTable()); 1178 return static_cast<jint>(dst[0]); 1179} 1180 1181static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle, 1182 jintArray pixelArray, jint offset, jint stride, 1183 jint x, jint y, jint width, jint height) { 1184 SkBitmap bitmap; 1185 reinterpret_cast<Bitmap*>(bitmapHandle)->getSkBitmap(&bitmap); 1186 SkAutoLockPixels alp(bitmap); 1187 1188 ToColorProc proc = ChooseToColorProc(bitmap); 1189 if (NULL == proc) { 1190 return; 1191 } 1192 const void* src = bitmap.getAddr(x, y); 1193 if (NULL == src) { 1194 return; 1195 } 1196 1197 SkColorTable* ctable = bitmap.getColorTable(); 1198 jint* dst = env->GetIntArrayElements(pixelArray, NULL); 1199 SkColor* d = (SkColor*)dst + offset; 1200 while (--height >= 0) { 1201 proc(d, src, width, ctable); 1202 d += stride; 1203 src = (void*)((const char*)src + bitmap.rowBytes()); 1204 } 1205 env->ReleaseIntArrayElements(pixelArray, dst, 0); 1206} 1207 1208/////////////////////////////////////////////////////////////////////////////// 1209 1210static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle, 1211 jint x, jint y, jint colorHandle) { 1212 SkBitmap bitmap; 1213 reinterpret_cast<Bitmap*>(bitmapHandle)->getSkBitmap(&bitmap); 1214 SkColor color = static_cast<SkColor>(colorHandle); 1215 SkAutoLockPixels alp(bitmap); 1216 if (NULL == bitmap.getPixels()) { 1217 return; 1218 } 1219 1220 FromColorProc proc = ChooseFromColorProc(bitmap); 1221 if (NULL == proc) { 1222 return; 1223 } 1224 1225 proc(bitmap.getAddr(x, y), &color, 1, x, y); 1226 bitmap.notifyPixelsChanged(); 1227} 1228 1229static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle, 1230 jintArray pixelArray, jint offset, jint stride, 1231 jint x, jint y, jint width, jint height) { 1232 SkBitmap bitmap; 1233 reinterpret_cast<Bitmap*>(bitmapHandle)->getSkBitmap(&bitmap); 1234 GraphicsJNI::SetPixels(env, pixelArray, offset, stride, 1235 x, y, width, height, bitmap); 1236} 1237 1238static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject, 1239 jlong bitmapHandle, jobject jbuffer) { 1240 SkBitmap bitmap; 1241 reinterpret_cast<Bitmap*>(bitmapHandle)->getSkBitmap(&bitmap); 1242 SkAutoLockPixels alp(bitmap); 1243 const void* src = bitmap.getPixels(); 1244 1245 if (NULL != src) { 1246 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE); 1247 1248 // the java side has already checked that buffer is large enough 1249 memcpy(abp.pointer(), src, bitmap.getSize()); 1250 } 1251} 1252 1253static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject, 1254 jlong bitmapHandle, jobject jbuffer) { 1255 SkBitmap bitmap; 1256 reinterpret_cast<Bitmap*>(bitmapHandle)->getSkBitmap(&bitmap); 1257 SkAutoLockPixels alp(bitmap); 1258 void* dst = bitmap.getPixels(); 1259 1260 if (NULL != dst) { 1261 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE); 1262 // the java side has already checked that buffer is large enough 1263 memcpy(dst, abp.pointer(), bitmap.getSize()); 1264 bitmap.notifyPixelsChanged(); 1265 } 1266} 1267 1268static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle, 1269 jlong bm1Handle) { 1270 SkBitmap bm0; 1271 SkBitmap bm1; 1272 reinterpret_cast<Bitmap*>(bm0Handle)->getSkBitmap(&bm0); 1273 reinterpret_cast<Bitmap*>(bm1Handle)->getSkBitmap(&bm1); 1274 if (bm0.width() != bm1.width() || 1275 bm0.height() != bm1.height() || 1276 bm0.colorType() != bm1.colorType()) { 1277 return JNI_FALSE; 1278 } 1279 1280 SkAutoLockPixels alp0(bm0); 1281 SkAutoLockPixels alp1(bm1); 1282 1283 // if we can't load the pixels, return false 1284 if (NULL == bm0.getPixels() || NULL == bm1.getPixels()) { 1285 return JNI_FALSE; 1286 } 1287 1288 if (bm0.colorType() == kIndex_8_SkColorType) { 1289 SkColorTable* ct0 = bm0.getColorTable(); 1290 SkColorTable* ct1 = bm1.getColorTable(); 1291 if (NULL == ct0 || NULL == ct1) { 1292 return JNI_FALSE; 1293 } 1294 if (ct0->count() != ct1->count()) { 1295 return JNI_FALSE; 1296 } 1297 1298 const size_t size = ct0->count() * sizeof(SkPMColor); 1299 if (memcmp(ct0->readColors(), ct1->readColors(), size) != 0) { 1300 return JNI_FALSE; 1301 } 1302 } 1303 1304 // now compare each scanline. We can't do the entire buffer at once, 1305 // since we don't care about the pixel values that might extend beyond 1306 // the width (since the scanline might be larger than the logical width) 1307 const int h = bm0.height(); 1308 const size_t size = bm0.width() * bm0.bytesPerPixel(); 1309 for (int y = 0; y < h; y++) { 1310 // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config 1311 // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0 1312 // and bm1 both have pixel data() (have passed NULL == getPixels() check), 1313 // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE 1314 // to warn user those 2 unrecognized config bitmaps may be different. 1315 void *bm0Addr = bm0.getAddr(0, y); 1316 void *bm1Addr = bm1.getAddr(0, y); 1317 1318 if(bm0Addr == NULL || bm1Addr == NULL) { 1319 return JNI_FALSE; 1320 } 1321 1322 if (memcmp(bm0Addr, bm1Addr, size) != 0) { 1323 return JNI_FALSE; 1324 } 1325 } 1326 return JNI_TRUE; 1327} 1328 1329static jlong Bitmap_refPixelRef(JNIEnv* env, jobject, jlong bitmapHandle) { 1330 LocalScopedBitmap bitmap(bitmapHandle); 1331 SkPixelRef* pixelRef = bitmap->pixelRef(); 1332 SkSafeRef(pixelRef); 1333 return reinterpret_cast<jlong>(pixelRef); 1334} 1335 1336static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapPtr) { 1337 LocalScopedBitmap bitmapHandle(bitmapPtr); 1338 if (!bitmapHandle.valid()) return; 1339 SkBitmap bitmap; 1340 bitmapHandle->getSkBitmap(&bitmap); 1341 android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmap); 1342} 1343 1344static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr) { 1345 LocalScopedBitmap bitmapHandle(bitmapPtr); 1346 return static_cast<jint>(bitmapHandle->getAllocationByteCount()); 1347} 1348 1349/////////////////////////////////////////////////////////////////////////////// 1350static jclass make_globalref(JNIEnv* env, const char classname[]) 1351{ 1352 jclass c = env->FindClass(classname); 1353 SkASSERT(c); 1354 return (jclass) env->NewGlobalRef(c); 1355} 1356 1357static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz, 1358 const char fieldname[], const char type[]) 1359{ 1360 jfieldID id = env->GetFieldID(clazz, fieldname, type); 1361 SkASSERT(id); 1362 return id; 1363} 1364 1365static const JNINativeMethod gBitmapMethods[] = { 1366 { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;", 1367 (void*)Bitmap_creator }, 1368 { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;", 1369 (void*)Bitmap_copy }, 1370 { "nativeCopyAshmem", "(J)Landroid/graphics/Bitmap;", 1371 (void*)Bitmap_copyAshmem }, 1372 { "nativeCopyAshmemConfig", "(JI)Landroid/graphics/Bitmap;", 1373 (void*)Bitmap_copyAshmemConfig }, 1374 { "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer }, 1375 { "nativeRecycle", "(J)Z", (void*)Bitmap_recycle }, 1376 { "nativeReconfigure", "(JIIIZ)V", (void*)Bitmap_reconfigure }, 1377 { "nativeCompress", "(JIILjava/io/OutputStream;[B)Z", 1378 (void*)Bitmap_compress }, 1379 { "nativeErase", "(JI)V", (void*)Bitmap_erase }, 1380 { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes }, 1381 { "nativeConfig", "(J)I", (void*)Bitmap_config }, 1382 { "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha }, 1383 { "nativeIsPremultiplied", "(J)Z", (void*)Bitmap_isPremultiplied}, 1384 { "nativeSetHasAlpha", "(JZZ)V", (void*)Bitmap_setHasAlpha}, 1385 { "nativeSetPremultiplied", "(JZ)V", (void*)Bitmap_setPremultiplied}, 1386 { "nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap }, 1387 { "nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap }, 1388 { "nativeCreateFromParcel", 1389 "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;", 1390 (void*)Bitmap_createFromParcel }, 1391 { "nativeWriteToParcel", "(JZILandroid/os/Parcel;)Z", 1392 (void*)Bitmap_writeToParcel }, 1393 { "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;", 1394 (void*)Bitmap_extractAlpha }, 1395 { "nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId }, 1396 { "nativeGetPixel", "(JII)I", (void*)Bitmap_getPixel }, 1397 { "nativeGetPixels", "(J[IIIIIII)V", (void*)Bitmap_getPixels }, 1398 { "nativeSetPixel", "(JIII)V", (void*)Bitmap_setPixel }, 1399 { "nativeSetPixels", "(J[IIIIIII)V", (void*)Bitmap_setPixels }, 1400 { "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V", 1401 (void*)Bitmap_copyPixelsToBuffer }, 1402 { "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V", 1403 (void*)Bitmap_copyPixelsFromBuffer }, 1404 { "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs }, 1405 { "nativeRefPixelRef", "(J)J", (void*)Bitmap_refPixelRef }, 1406 { "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw }, 1407 { "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount }, 1408}; 1409 1410int register_android_graphics_Bitmap(JNIEnv* env) 1411{ 1412 gBitmap_class = make_globalref(env, "android/graphics/Bitmap"); 1413 gBitmap_nativePtr = getFieldIDCheck(env, gBitmap_class, "mNativePtr", "J"); 1414 gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V"); 1415 gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "(IIZ)V"); 1416 gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I"); 1417 return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods, 1418 NELEM(gBitmapMethods)); 1419}