1 #include "Paint.h" 2 #include "SkBitmap.h" 3 #include "SkPixelRef.h" 4 #include "SkImageEncoder.h" 5 #include "SkImageInfo.h" 6 #include "SkColorPriv.h" 7 #include "GraphicsJNI.h" 8 #include "SkDither.h" 9 #include "SkUnPreMultiply.h" 10 #include "SkStream.h" 11 12 #include <binder/Parcel.h> 13 #include "android_os_Parcel.h" 14 #include "android_util_Binder.h" 15 #include "android_nio_utils.h" 16 #include "CreateJavaOutputStreamAdaptor.h" 17 18 #include <jni.h> 19 20 #include <Caches.h> 21 22 #if 0 23 #define TRACE_BITMAP(code) code 24 #else 25 #define TRACE_BITMAP(code) 26 #endif 27 28 /////////////////////////////////////////////////////////////////////////////// 29 // Conversions to/from SkColor, for get/setPixels, and the create method, which 30 // is basically like setPixels 31 32 typedef void (*FromColorProc)(void* dst, const SkColor src[], int width, 33 int x, int y); 34 35 static void FromColor_D32(void* dst, const SkColor src[], int width, 36 int, int) { 37 SkPMColor* d = (SkPMColor*)dst; 38 39 for (int i = 0; i < width; i++) { 40 *d++ = SkPreMultiplyColor(*src++); 41 } 42 } 43 44 static void FromColor_D32_Raw(void* dst, const SkColor src[], int width, 45 int, int) { 46 // SkColor's ordering may be different from SkPMColor 47 if (SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER) { 48 memcpy(dst, src, width * sizeof(SkColor)); 49 return; 50 } 51 52 // order isn't same, repack each pixel manually 53 SkPMColor* d = (SkPMColor*)dst; 54 for (int i = 0; i < width; i++) { 55 SkColor c = *src++; 56 *d++ = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c), 57 SkColorGetG(c), SkColorGetB(c)); 58 } 59 } 60 61 static void FromColor_D565(void* dst, const SkColor src[], int width, 62 int x, int y) { 63 uint16_t* d = (uint16_t*)dst; 64 65 DITHER_565_SCAN(y); 66 for (int stop = x + width; x < stop; x++) { 67 SkColor c = *src++; 68 *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c), 69 DITHER_VALUE(x)); 70 } 71 } 72 73 static void FromColor_D4444(void* dst, const SkColor src[], int width, 74 int x, int y) { 75 SkPMColor16* d = (SkPMColor16*)dst; 76 77 DITHER_4444_SCAN(y); 78 for (int stop = x + width; x < stop; x++) { 79 SkPMColor pmc = SkPreMultiplyColor(*src++); 80 *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x)); 81 // *d++ = SkPixel32ToPixel4444(pmc); 82 } 83 } 84 85 static void FromColor_D4444_Raw(void* dst, const SkColor src[], int width, 86 int x, int y) { 87 SkPMColor16* d = (SkPMColor16*)dst; 88 89 DITHER_4444_SCAN(y); 90 for (int stop = x + width; x < stop; x++) { 91 SkColor c = *src++; 92 93 // SkPMColor is used because the ordering is ARGB32, even though the target actually premultiplied 94 SkPMColor pmc = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c), 95 SkColorGetG(c), SkColorGetB(c)); 96 *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x)); 97 // *d++ = SkPixel32ToPixel4444(pmc); 98 } 99 } 100 101 // can return NULL 102 static FromColorProc ChooseFromColorProc(const SkBitmap& bitmap) { 103 switch (bitmap.colorType()) { 104 case kN32_SkColorType: 105 return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D32 : FromColor_D32_Raw; 106 case kARGB_4444_SkColorType: 107 return bitmap.alphaType() == kPremul_SkAlphaType ? FromColor_D4444 : 108 FromColor_D4444_Raw; 109 case kRGB_565_SkColorType: 110 return FromColor_D565; 111 default: 112 break; 113 } 114 return NULL; 115 } 116 117 bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride, 118 int x, int y, int width, int height, const SkBitmap& dstBitmap) { 119 SkAutoLockPixels alp(dstBitmap); 120 void* dst = dstBitmap.getPixels(); 121 FromColorProc proc = ChooseFromColorProc(dstBitmap); 122 123 if (NULL == dst || NULL == proc) { 124 return false; 125 } 126 127 const jint* array = env->GetIntArrayElements(srcColors, NULL); 128 const SkColor* src = (const SkColor*)array + srcOffset; 129 130 // reset to to actual choice from caller 131 dst = dstBitmap.getAddr(x, y); 132 // now copy/convert each scanline 133 for (int y = 0; y < height; y++) { 134 proc(dst, src, width, x, y); 135 src += srcStride; 136 dst = (char*)dst + dstBitmap.rowBytes(); 137 } 138 139 dstBitmap.notifyPixelsChanged(); 140 141 env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array), 142 JNI_ABORT); 143 return true; 144 } 145 146 //////////////////// ToColor procs 147 148 typedef void (*ToColorProc)(SkColor dst[], const void* src, int width, 149 SkColorTable*); 150 151 static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width, 152 SkColorTable*) { 153 SkASSERT(width > 0); 154 const SkPMColor* s = (const SkPMColor*)src; 155 do { 156 *dst++ = SkUnPreMultiply::PMColorToColor(*s++); 157 } while (--width != 0); 158 } 159 160 static void ToColor_S32_Raw(SkColor dst[], const void* src, int width, 161 SkColorTable*) { 162 SkASSERT(width > 0); 163 const SkPMColor* s = (const SkPMColor*)src; 164 do { 165 SkPMColor c = *s++; 166 *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c), 167 SkGetPackedG32(c), SkGetPackedB32(c)); 168 } while (--width != 0); 169 } 170 171 static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width, 172 SkColorTable*) { 173 SkASSERT(width > 0); 174 const SkPMColor* s = (const SkPMColor*)src; 175 do { 176 SkPMColor c = *s++; 177 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c), 178 SkGetPackedB32(c)); 179 } while (--width != 0); 180 } 181 182 static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width, 183 SkColorTable*) { 184 SkASSERT(width > 0); 185 const SkPMColor16* s = (const SkPMColor16*)src; 186 do { 187 *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++)); 188 } while (--width != 0); 189 } 190 191 static void ToColor_S4444_Raw(SkColor dst[], const void* src, int width, 192 SkColorTable*) { 193 SkASSERT(width > 0); 194 const SkPMColor16* s = (const SkPMColor16*)src; 195 do { 196 SkPMColor c = SkPixel4444ToPixel32(*s++); 197 *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c), 198 SkGetPackedG32(c), SkGetPackedB32(c)); 199 } while (--width != 0); 200 } 201 202 static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width, 203 SkColorTable*) { 204 SkASSERT(width > 0); 205 const SkPMColor16* s = (const SkPMColor16*)src; 206 do { 207 SkPMColor c = SkPixel4444ToPixel32(*s++); 208 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c), 209 SkGetPackedB32(c)); 210 } while (--width != 0); 211 } 212 213 static void ToColor_S565(SkColor dst[], const void* src, int width, 214 SkColorTable*) { 215 SkASSERT(width > 0); 216 const uint16_t* s = (const uint16_t*)src; 217 do { 218 uint16_t c = *s++; 219 *dst++ = SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c), 220 SkPacked16ToB32(c)); 221 } while (--width != 0); 222 } 223 224 static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width, 225 SkColorTable* ctable) { 226 SkASSERT(width > 0); 227 const uint8_t* s = (const uint8_t*)src; 228 const SkPMColor* colors = ctable->lockColors(); 229 do { 230 *dst++ = SkUnPreMultiply::PMColorToColor(colors[*s++]); 231 } while (--width != 0); 232 ctable->unlockColors(); 233 } 234 235 static void ToColor_SI8_Raw(SkColor dst[], const void* src, int width, 236 SkColorTable* ctable) { 237 SkASSERT(width > 0); 238 const uint8_t* s = (const uint8_t*)src; 239 const SkPMColor* colors = ctable->lockColors(); 240 do { 241 SkPMColor c = colors[*s++]; 242 *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c), 243 SkGetPackedG32(c), SkGetPackedB32(c)); 244 } while (--width != 0); 245 ctable->unlockColors(); 246 } 247 248 static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width, 249 SkColorTable* ctable) { 250 SkASSERT(width > 0); 251 const uint8_t* s = (const uint8_t*)src; 252 const SkPMColor* colors = ctable->lockColors(); 253 do { 254 SkPMColor c = colors[*s++]; 255 *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c), 256 SkGetPackedB32(c)); 257 } while (--width != 0); 258 ctable->unlockColors(); 259 } 260 261 // can return NULL 262 static ToColorProc ChooseToColorProc(const SkBitmap& src) { 263 switch (src.colorType()) { 264 case kN32_SkColorType: 265 switch (src.alphaType()) { 266 case kOpaque_SkAlphaType: 267 return ToColor_S32_Opaque; 268 case kPremul_SkAlphaType: 269 return ToColor_S32_Alpha; 270 case kUnpremul_SkAlphaType: 271 return ToColor_S32_Raw; 272 default: 273 return NULL; 274 } 275 case kARGB_4444_SkColorType: 276 switch (src.alphaType()) { 277 case kOpaque_SkAlphaType: 278 return ToColor_S4444_Opaque; 279 case kPremul_SkAlphaType: 280 return ToColor_S4444_Alpha; 281 case kUnpremul_SkAlphaType: 282 return ToColor_S4444_Raw; 283 default: 284 return NULL; 285 } 286 case kRGB_565_SkColorType: 287 return ToColor_S565; 288 case kIndex_8_SkColorType: 289 if (src.getColorTable() == NULL) { 290 return NULL; 291 } 292 switch (src.alphaType()) { 293 case kOpaque_SkAlphaType: 294 return ToColor_SI8_Opaque; 295 case kPremul_SkAlphaType: 296 return ToColor_SI8_Alpha; 297 case kUnpremul_SkAlphaType: 298 return ToColor_SI8_Raw; 299 default: 300 return NULL; 301 } 302 default: 303 break; 304 } 305 return NULL; 306 } 307 308 /////////////////////////////////////////////////////////////////////////////// 309 /////////////////////////////////////////////////////////////////////////////// 310 311 static int getPremulBitmapCreateFlags(bool isMutable) { 312 int flags = GraphicsJNI::kBitmapCreateFlag_Premultiplied; 313 if (isMutable) flags |= GraphicsJNI::kBitmapCreateFlag_Mutable; 314 return flags; 315 } 316 317 static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors, 318 jint offset, jint stride, jint width, jint height, 319 jint configHandle, jboolean isMutable) { 320 SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle); 321 if (NULL != jColors) { 322 size_t n = env->GetArrayLength(jColors); 323 if (n < SkAbs32(stride) * (size_t)height) { 324 doThrowAIOOBE(env); 325 return NULL; 326 } 327 } 328 329 // ARGB_4444 is a deprecated format, convert automatically to 8888 330 if (colorType == kARGB_4444_SkColorType) { 331 colorType = kN32_SkColorType; 332 } 333 334 SkBitmap bitmap; 335 bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType)); 336 337 jbyteArray buff = GraphicsJNI::allocateJavaPixelRef(env, &bitmap, NULL); 338 if (NULL == buff) { 339 return NULL; 340 } 341 342 if (jColors != NULL) { 343 GraphicsJNI::SetPixels(env, jColors, offset, stride, 344 0, 0, width, height, bitmap); 345 } 346 347 return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), buff, 348 getPremulBitmapCreateFlags(isMutable), NULL, NULL); 349 } 350 351 static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle, 352 jint dstConfigHandle, jboolean isMutable) { 353 const SkBitmap* src = reinterpret_cast<SkBitmap*>(srcHandle); 354 SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle); 355 SkBitmap result; 356 JavaPixelAllocator allocator(env); 357 358 if (!src->copyTo(&result, dstCT, &allocator)) { 359 return NULL; 360 } 361 return GraphicsJNI::createBitmap(env, new SkBitmap(result), allocator.getStorageObj(), 362 getPremulBitmapCreateFlags(isMutable), NULL, NULL); 363 } 364 365 static void Bitmap_destructor(JNIEnv* env, jobject, jlong bitmapHandle) { 366 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 367 #ifdef USE_OPENGL_RENDERER 368 if (android::uirenderer::Caches::hasInstance()) { 369 android::uirenderer::Caches::getInstance().resourceCache.destructor(bitmap); 370 return; 371 } 372 #endif // USE_OPENGL_RENDERER 373 delete bitmap; 374 } 375 376 static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) { 377 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 378 #ifdef USE_OPENGL_RENDERER 379 if (android::uirenderer::Caches::hasInstance()) { 380 bool result; 381 result = android::uirenderer::Caches::getInstance().resourceCache.recycle(bitmap); 382 return result ? JNI_TRUE : JNI_FALSE; 383 } 384 #endif // USE_OPENGL_RENDERER 385 bitmap->setPixels(NULL, NULL); 386 return JNI_TRUE; 387 } 388 389 static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle, 390 jint width, jint height, jint configHandle, jint allocSize, 391 jboolean requestPremul) { 392 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 393 SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle); 394 395 // ARGB_4444 is a deprecated format, convert automatically to 8888 396 if (colorType == kARGB_4444_SkColorType) { 397 colorType = kN32_SkColorType; 398 } 399 400 if (width * height * SkColorTypeBytesPerPixel(colorType) > allocSize) { 401 // done in native as there's no way to get BytesPerPixel in Java 402 doThrowIAE(env, "Bitmap not large enough to support new configuration"); 403 return; 404 } 405 SkPixelRef* ref = bitmap->pixelRef(); 406 ref->ref(); 407 SkAlphaType alphaType; 408 if (bitmap->colorType() != kRGB_565_SkColorType 409 && bitmap->alphaType() == kOpaque_SkAlphaType) { 410 // If the original bitmap was set to opaque, keep that setting, unless it 411 // was 565, which is required to be opaque. 412 alphaType = kOpaque_SkAlphaType; 413 } else { 414 // Otherwise respect the premultiplied request. 415 alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType; 416 } 417 bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType)); 418 // FIXME: Skia thinks of an SkPixelRef as having a constant SkImageInfo (except for 419 // its alphatype), so it would make more sense from Skia's perspective to create a 420 // new SkPixelRef. That said, libhwui uses the pointer to the SkPixelRef as a key 421 // for its cache, so it won't realize this is the same Java Bitmap. 422 SkImageInfo& info = const_cast<SkImageInfo&>(ref->info()); 423 // Use the updated from the SkBitmap, which may have corrected an invalid alphatype. 424 // (e.g. 565 non-opaque) 425 info = bitmap->info(); 426 bitmap->setPixelRef(ref); 427 428 // notifyPixelsChanged will increment the generation ID even though the actual pixel data 429 // hasn't been touched. This signals the renderer that the bitmap (including width, height, 430 // colortype and alphatype) has changed. 431 ref->notifyPixelsChanged(); 432 ref->unref(); 433 } 434 435 // These must match the int values in Bitmap.java 436 enum JavaEncodeFormat { 437 kJPEG_JavaEncodeFormat = 0, 438 kPNG_JavaEncodeFormat = 1, 439 kWEBP_JavaEncodeFormat = 2 440 }; 441 442 static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle, 443 jint format, jint quality, 444 jobject jstream, jbyteArray jstorage) { 445 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 446 SkImageEncoder::Type fm; 447 448 switch (format) { 449 case kJPEG_JavaEncodeFormat: 450 fm = SkImageEncoder::kJPEG_Type; 451 break; 452 case kPNG_JavaEncodeFormat: 453 fm = SkImageEncoder::kPNG_Type; 454 break; 455 case kWEBP_JavaEncodeFormat: 456 fm = SkImageEncoder::kWEBP_Type; 457 break; 458 default: 459 return JNI_FALSE; 460 } 461 462 bool success = false; 463 if (NULL != bitmap) { 464 SkAutoLockPixels alp(*bitmap); 465 466 if (NULL == bitmap->getPixels()) { 467 return JNI_FALSE; 468 } 469 470 SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage); 471 if (NULL == strm) { 472 return JNI_FALSE; 473 } 474 475 SkImageEncoder* encoder = SkImageEncoder::Create(fm); 476 if (NULL != encoder) { 477 success = encoder->encodeStream(strm, *bitmap, quality); 478 delete encoder; 479 } 480 delete strm; 481 } 482 return success ? JNI_TRUE : JNI_FALSE; 483 } 484 485 static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) { 486 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 487 bitmap->eraseColor(color); 488 } 489 490 static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) { 491 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 492 return static_cast<jint>(bitmap->rowBytes()); 493 } 494 495 static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) { 496 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 497 return GraphicsJNI::colorTypeToLegacyBitmapConfig(bitmap->colorType()); 498 } 499 500 static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) { 501 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 502 return static_cast<jint>(bitmap->getGenerationID()); 503 } 504 505 static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) { 506 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 507 if (bitmap->alphaType() == kPremul_SkAlphaType) { 508 return JNI_TRUE; 509 } 510 return JNI_FALSE; 511 } 512 513 static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) { 514 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 515 return !bitmap->isOpaque() ? JNI_TRUE : JNI_FALSE; 516 } 517 518 static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle, 519 jboolean hasAlpha, jboolean requestPremul) { 520 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 521 if (hasAlpha) { 522 bitmap->setAlphaType(requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType); 523 } else { 524 bitmap->setAlphaType(kOpaque_SkAlphaType); 525 } 526 } 527 528 static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle, 529 jboolean isPremul) { 530 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 531 if (!bitmap->isOpaque()) { 532 if (isPremul) { 533 bitmap->setAlphaType(kPremul_SkAlphaType); 534 } else { 535 bitmap->setAlphaType(kUnpremul_SkAlphaType); 536 } 537 } 538 } 539 540 static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) { 541 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 542 return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE; 543 } 544 545 static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle, 546 jboolean hasMipMap) { 547 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 548 bitmap->setHasHardwareMipMap(hasMipMap); 549 } 550 551 /////////////////////////////////////////////////////////////////////////////// 552 553 static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { 554 if (parcel == NULL) { 555 SkDebugf("-------- unparcel parcel is NULL\n"); 556 return NULL; 557 } 558 559 android::Parcel* p = android::parcelForJavaObject(env, parcel); 560 561 const bool isMutable = p->readInt32() != 0; 562 const SkColorType colorType = (SkColorType)p->readInt32(); 563 const SkAlphaType alphaType = (SkAlphaType)p->readInt32(); 564 const int width = p->readInt32(); 565 const int height = p->readInt32(); 566 const int rowBytes = p->readInt32(); 567 const int density = p->readInt32(); 568 569 if (kN32_SkColorType != colorType && 570 kRGB_565_SkColorType != colorType && 571 kARGB_4444_SkColorType != colorType && 572 kIndex_8_SkColorType != colorType && 573 kAlpha_8_SkColorType != colorType) { 574 SkDebugf("Bitmap_createFromParcel unknown colortype: %d\n", colorType); 575 return NULL; 576 } 577 578 SkBitmap* bitmap = new SkBitmap; 579 580 bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType), rowBytes); 581 582 SkColorTable* ctable = NULL; 583 if (colorType == kIndex_8_SkColorType) { 584 int count = p->readInt32(); 585 if (count > 0) { 586 size_t size = count * sizeof(SkPMColor); 587 const SkPMColor* src = (const SkPMColor*)p->readInplace(size); 588 ctable = new SkColorTable(src, count); 589 } 590 } 591 592 jbyteArray buffer = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable); 593 if (NULL == buffer) { 594 SkSafeUnref(ctable); 595 delete bitmap; 596 return NULL; 597 } 598 599 SkSafeUnref(ctable); 600 601 size_t size = bitmap->getSize(); 602 603 android::Parcel::ReadableBlob blob; 604 android::status_t status = p->readBlob(size, &blob); 605 if (status) { 606 doThrowRE(env, "Could not read bitmap from parcel blob."); 607 delete bitmap; 608 return NULL; 609 } 610 611 bitmap->lockPixels(); 612 memcpy(bitmap->getPixels(), blob.data(), size); 613 bitmap->unlockPixels(); 614 615 blob.release(); 616 617 return GraphicsJNI::createBitmap(env, bitmap, buffer, getPremulBitmapCreateFlags(isMutable), 618 NULL, NULL, density); 619 } 620 621 static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, 622 jlong bitmapHandle, 623 jboolean isMutable, jint density, 624 jobject parcel) { 625 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 626 if (parcel == NULL) { 627 SkDebugf("------- writeToParcel null parcel\n"); 628 return JNI_FALSE; 629 } 630 631 android::Parcel* p = android::parcelForJavaObject(env, parcel); 632 633 p->writeInt32(isMutable); 634 p->writeInt32(bitmap->colorType()); 635 p->writeInt32(bitmap->alphaType()); 636 p->writeInt32(bitmap->width()); 637 p->writeInt32(bitmap->height()); 638 p->writeInt32(bitmap->rowBytes()); 639 p->writeInt32(density); 640 641 if (bitmap->colorType() == kIndex_8_SkColorType) { 642 SkColorTable* ctable = bitmap->getColorTable(); 643 if (ctable != NULL) { 644 int count = ctable->count(); 645 p->writeInt32(count); 646 memcpy(p->writeInplace(count * sizeof(SkPMColor)), 647 ctable->lockColors(), count * sizeof(SkPMColor)); 648 ctable->unlockColors(); 649 } else { 650 p->writeInt32(0); // indicate no ctable 651 } 652 } 653 654 size_t size = bitmap->getSize(); 655 656 android::Parcel::WritableBlob blob; 657 android::status_t status = p->writeBlob(size, &blob); 658 if (status) { 659 doThrowRE(env, "Could not write bitmap to parcel blob."); 660 return JNI_FALSE; 661 } 662 663 bitmap->lockPixels(); 664 const void* pSrc = bitmap->getPixels(); 665 if (pSrc == NULL) { 666 memset(blob.data(), 0, size); 667 } else { 668 memcpy(blob.data(), pSrc, size); 669 } 670 bitmap->unlockPixels(); 671 672 blob.release(); 673 return JNI_TRUE; 674 } 675 676 static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz, 677 jlong srcHandle, jlong paintHandle, 678 jintArray offsetXY) { 679 const SkBitmap* src = reinterpret_cast<SkBitmap*>(srcHandle); 680 const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle); 681 SkIPoint offset; 682 SkBitmap* dst = new SkBitmap; 683 JavaPixelAllocator allocator(env); 684 685 src->extractAlpha(dst, paint, &allocator, &offset); 686 // If Skia can't allocate pixels for destination bitmap, it resets 687 // it, that is set its pixels buffer to NULL, and zero width and height. 688 if (dst->getPixels() == NULL && src->getPixels() != NULL) { 689 delete dst; 690 doThrowOOME(env, "failed to allocate pixels for alpha"); 691 return NULL; 692 } 693 if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) { 694 int* array = env->GetIntArrayElements(offsetXY, NULL); 695 array[0] = offset.fX; 696 array[1] = offset.fY; 697 env->ReleaseIntArrayElements(offsetXY, array, 0); 698 } 699 700 return GraphicsJNI::createBitmap(env, dst, allocator.getStorageObj(), 701 getPremulBitmapCreateFlags(true), NULL, NULL); 702 } 703 704 /////////////////////////////////////////////////////////////////////////////// 705 706 static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle, 707 jint x, jint y) { 708 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 709 SkAutoLockPixels alp(*bitmap); 710 711 ToColorProc proc = ChooseToColorProc(*bitmap); 712 if (NULL == proc) { 713 return 0; 714 } 715 const void* src = bitmap->getAddr(x, y); 716 if (NULL == src) { 717 return 0; 718 } 719 720 SkColor dst[1]; 721 proc(dst, src, 1, bitmap->getColorTable()); 722 return static_cast<jint>(dst[0]); 723 } 724 725 static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle, 726 jintArray pixelArray, jint offset, jint stride, 727 jint x, jint y, jint width, jint height) { 728 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 729 SkAutoLockPixels alp(*bitmap); 730 731 ToColorProc proc = ChooseToColorProc(*bitmap); 732 if (NULL == proc) { 733 return; 734 } 735 const void* src = bitmap->getAddr(x, y); 736 if (NULL == src) { 737 return; 738 } 739 740 SkColorTable* ctable = bitmap->getColorTable(); 741 jint* dst = env->GetIntArrayElements(pixelArray, NULL); 742 SkColor* d = (SkColor*)dst + offset; 743 while (--height >= 0) { 744 proc(d, src, width, ctable); 745 d += stride; 746 src = (void*)((const char*)src + bitmap->rowBytes()); 747 } 748 env->ReleaseIntArrayElements(pixelArray, dst, 0); 749 } 750 751 /////////////////////////////////////////////////////////////////////////////// 752 753 static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle, 754 jint x, jint y, jint colorHandle) { 755 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 756 SkColor color = static_cast<SkColor>(colorHandle); 757 SkAutoLockPixels alp(*bitmap); 758 if (NULL == bitmap->getPixels()) { 759 return; 760 } 761 762 FromColorProc proc = ChooseFromColorProc(*bitmap); 763 if (NULL == proc) { 764 return; 765 } 766 767 proc(bitmap->getAddr(x, y), &color, 1, x, y); 768 bitmap->notifyPixelsChanged(); 769 } 770 771 static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle, 772 jintArray pixelArray, jint offset, jint stride, 773 jint x, jint y, jint width, jint height) { 774 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 775 GraphicsJNI::SetPixels(env, pixelArray, offset, stride, 776 x, y, width, height, *bitmap); 777 } 778 779 static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject, 780 jlong bitmapHandle, jobject jbuffer) { 781 const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 782 SkAutoLockPixels alp(*bitmap); 783 const void* src = bitmap->getPixels(); 784 785 if (NULL != src) { 786 android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE); 787 788 // the java side has already checked that buffer is large enough 789 memcpy(abp.pointer(), src, bitmap->getSize()); 790 } 791 } 792 793 static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject, 794 jlong bitmapHandle, jobject jbuffer) { 795 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 796 SkAutoLockPixels alp(*bitmap); 797 void* dst = bitmap->getPixels(); 798 799 if (NULL != dst) { 800 android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE); 801 // the java side has already checked that buffer is large enough 802 memcpy(dst, abp.pointer(), bitmap->getSize()); 803 bitmap->notifyPixelsChanged(); 804 } 805 } 806 807 static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle, 808 jlong bm1Handle) { 809 const SkBitmap* bm0 = reinterpret_cast<SkBitmap*>(bm0Handle); 810 const SkBitmap* bm1 = reinterpret_cast<SkBitmap*>(bm1Handle); 811 if (bm0->width() != bm1->width() || 812 bm0->height() != bm1->height() || 813 bm0->colorType() != bm1->colorType()) { 814 return JNI_FALSE; 815 } 816 817 SkAutoLockPixels alp0(*bm0); 818 SkAutoLockPixels alp1(*bm1); 819 820 // if we can't load the pixels, return false 821 if (NULL == bm0->getPixels() || NULL == bm1->getPixels()) { 822 return JNI_FALSE; 823 } 824 825 if (bm0->colorType() == kIndex_8_SkColorType) { 826 SkColorTable* ct0 = bm0->getColorTable(); 827 SkColorTable* ct1 = bm1->getColorTable(); 828 if (NULL == ct0 || NULL == ct1) { 829 return JNI_FALSE; 830 } 831 if (ct0->count() != ct1->count()) { 832 return JNI_FALSE; 833 } 834 835 SkAutoLockColors alc0(ct0); 836 SkAutoLockColors alc1(ct1); 837 const size_t size = ct0->count() * sizeof(SkPMColor); 838 if (memcmp(alc0.colors(), alc1.colors(), size) != 0) { 839 return JNI_FALSE; 840 } 841 } 842 843 // now compare each scanline. We can't do the entire buffer at once, 844 // since we don't care about the pixel values that might extend beyond 845 // the width (since the scanline might be larger than the logical width) 846 const int h = bm0->height(); 847 const size_t size = bm0->width() * bm0->bytesPerPixel(); 848 for (int y = 0; y < h; y++) { 849 // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config 850 // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0 851 // and bm1 both have pixel data() (have passed NULL == getPixels() check), 852 // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE 853 // to warn user those 2 unrecognized config bitmaps may be different. 854 void *bm0Addr = bm0->getAddr(0, y); 855 void *bm1Addr = bm1->getAddr(0, y); 856 857 if(bm0Addr == NULL || bm1Addr == NULL) { 858 return JNI_FALSE; 859 } 860 861 if (memcmp(bm0Addr, bm1Addr, size) != 0) { 862 return JNI_FALSE; 863 } 864 } 865 return JNI_TRUE; 866 } 867 868 static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapHandle) { 869 SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); 870 bitmap->lockPixels(); 871 bitmap->unlockPixels(); 872 } 873 874 /////////////////////////////////////////////////////////////////////////////// 875 876 #include <android_runtime/AndroidRuntime.h> 877 878 static JNINativeMethod gBitmapMethods[] = { 879 { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;", 880 (void*)Bitmap_creator }, 881 { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;", 882 (void*)Bitmap_copy }, 883 { "nativeDestructor", "(J)V", (void*)Bitmap_destructor }, 884 { "nativeRecycle", "(J)Z", (void*)Bitmap_recycle }, 885 { "nativeReconfigure", "(JIIIIZ)V", (void*)Bitmap_reconfigure }, 886 { "nativeCompress", "(JIILjava/io/OutputStream;[B)Z", 887 (void*)Bitmap_compress }, 888 { "nativeErase", "(JI)V", (void*)Bitmap_erase }, 889 { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes }, 890 { "nativeConfig", "(J)I", (void*)Bitmap_config }, 891 { "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha }, 892 { "nativeIsPremultiplied", "(J)Z", (void*)Bitmap_isPremultiplied}, 893 { "nativeSetHasAlpha", "(JZZ)V", (void*)Bitmap_setHasAlpha}, 894 { "nativeSetPremultiplied", "(JZ)V", (void*)Bitmap_setPremultiplied}, 895 { "nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap }, 896 { "nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap }, 897 { "nativeCreateFromParcel", 898 "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;", 899 (void*)Bitmap_createFromParcel }, 900 { "nativeWriteToParcel", "(JZILandroid/os/Parcel;)Z", 901 (void*)Bitmap_writeToParcel }, 902 { "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;", 903 (void*)Bitmap_extractAlpha }, 904 { "nativeGenerationId", "(J)I", (void*)Bitmap_getGenerationId }, 905 { "nativeGetPixel", "(JII)I", (void*)Bitmap_getPixel }, 906 { "nativeGetPixels", "(J[IIIIIII)V", (void*)Bitmap_getPixels }, 907 { "nativeSetPixel", "(JIII)V", (void*)Bitmap_setPixel }, 908 { "nativeSetPixels", "(J[IIIIIII)V", (void*)Bitmap_setPixels }, 909 { "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V", 910 (void*)Bitmap_copyPixelsToBuffer }, 911 { "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V", 912 (void*)Bitmap_copyPixelsFromBuffer }, 913 { "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs }, 914 { "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw }, 915 }; 916 917 #define kClassPathName "android/graphics/Bitmap" 918 919 int register_android_graphics_Bitmap(JNIEnv* env) 920 { 921 return android::AndroidRuntime::registerNativeMethods(env, kClassPathName, 922 gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods)); 923 } 924