1 #define LOG_TAG "BitmapFactory" 2 3 #include "BitmapFactory.h" 4 #include "SkImageDecoder.h" 5 #include "SkImageRef_ashmem.h" 6 #include "SkImageRef_GlobalPool.h" 7 #include "SkPixelRef.h" 8 #include "SkStream.h" 9 #include "SkTemplates.h" 10 #include "SkUtils.h" 11 #include "CreateJavaOutputStreamAdaptor.h" 12 #include "AutoDecodeCancel.h" 13 #include "Utils.h" 14 15 #include <android_runtime/AndroidRuntime.h> 16 #include <utils/Asset.h> 17 #include <utils/ResourceTypes.h> 18 #include <netinet/in.h> 19 #include <sys/mman.h> 20 #include <sys/stat.h> 21 22 jclass gOptions_class; 23 jfieldID gOptions_justBoundsFieldID; 24 jfieldID gOptions_sampleSizeFieldID; 25 jfieldID gOptions_configFieldID; 26 jfieldID gOptions_ditherFieldID; 27 jfieldID gOptions_purgeableFieldID; 28 jfieldID gOptions_shareableFieldID; 29 jfieldID gOptions_nativeAllocFieldID; 30 jfieldID gOptions_preferQualityOverSpeedFieldID; 31 jfieldID gOptions_widthFieldID; 32 jfieldID gOptions_heightFieldID; 33 jfieldID gOptions_mimeFieldID; 34 jfieldID gOptions_mCancelID; 35 36 static jclass gFileDescriptor_class; 37 static jfieldID gFileDescriptor_descriptor; 38 39 #if 0 40 #define TRACE_BITMAP(code) code 41 #else 42 #define TRACE_BITMAP(code) 43 #endif 44 45 using namespace android; 46 47 class NinePatchPeeker : public SkImageDecoder::Peeker { 48 SkImageDecoder* fHost; 49 public: 50 NinePatchPeeker(SkImageDecoder* host) { 51 // the host lives longer than we do, so a raw ptr is safe 52 fHost = host; 53 fPatchIsValid = false; 54 } 55 56 ~NinePatchPeeker() { 57 if (fPatchIsValid) { 58 free(fPatch); 59 } 60 } 61 62 bool fPatchIsValid; 63 Res_png_9patch* fPatch; 64 65 virtual bool peek(const char tag[], const void* data, size_t length) { 66 if (strcmp("npTc", tag) == 0 && length >= sizeof(Res_png_9patch)) { 67 Res_png_9patch* patch = (Res_png_9patch*) data; 68 size_t patchSize = patch->serializedSize(); 69 assert(length == patchSize); 70 // You have to copy the data because it is owned by the png reader 71 Res_png_9patch* patchNew = (Res_png_9patch*) malloc(patchSize); 72 memcpy(patchNew, patch, patchSize); 73 // this relies on deserialization being done in place 74 Res_png_9patch::deserialize(patchNew); 75 patchNew->fileToDevice(); 76 if (fPatchIsValid) { 77 free(fPatch); 78 } 79 fPatch = patchNew; 80 //printf("9patch: (%d,%d)-(%d,%d)\n", 81 // fPatch.sizeLeft, fPatch.sizeTop, 82 // fPatch.sizeRight, fPatch.sizeBottom); 83 fPatchIsValid = true; 84 85 // now update our host to force index or 32bit config 86 // 'cause we don't want 565 predithered, since as a 9patch, we know 87 // we will be stretched, and therefore we want to dither afterwards. 88 static const SkBitmap::Config gNo565Pref[] = { 89 SkBitmap::kIndex8_Config, 90 SkBitmap::kIndex8_Config, 91 SkBitmap::kARGB_8888_Config, 92 SkBitmap::kARGB_8888_Config, 93 SkBitmap::kARGB_8888_Config, 94 SkBitmap::kARGB_8888_Config, 95 }; 96 fHost->setPrefConfigTable(gNo565Pref); 97 } else { 98 fPatch = NULL; 99 } 100 return true; // keep on decoding 101 } 102 }; 103 104 /////////////////////////////////////////////////////////////////////////////// 105 106 static inline int32_t validOrNeg1(bool isValid, int32_t value) { 107 // return isValid ? value : -1; 108 SkASSERT((int)isValid == 0 || (int)isValid == 1); 109 return ((int32_t)isValid - 1) | value; 110 } 111 112 jstring getMimeTypeString(JNIEnv* env, SkImageDecoder::Format format) { 113 static const struct { 114 SkImageDecoder::Format fFormat; 115 const char* fMimeType; 116 } gMimeTypes[] = { 117 { SkImageDecoder::kBMP_Format, "image/bmp" }, 118 { SkImageDecoder::kGIF_Format, "image/gif" }, 119 { SkImageDecoder::kICO_Format, "image/x-ico" }, 120 { SkImageDecoder::kJPEG_Format, "image/jpeg" }, 121 { SkImageDecoder::kPNG_Format, "image/png" }, 122 { SkImageDecoder::kWBMP_Format, "image/vnd.wap.wbmp" } 123 }; 124 125 const char* cstr = NULL; 126 for (size_t i = 0; i < SK_ARRAY_COUNT(gMimeTypes); i++) { 127 if (gMimeTypes[i].fFormat == format) { 128 cstr = gMimeTypes[i].fMimeType; 129 break; 130 } 131 } 132 133 jstring jstr = 0; 134 if (NULL != cstr) { 135 jstr = env->NewStringUTF(cstr); 136 } 137 return jstr; 138 } 139 140 static bool optionsPurgeable(JNIEnv* env, jobject options) { 141 return options != NULL && 142 env->GetBooleanField(options, gOptions_purgeableFieldID); 143 } 144 145 static bool optionsShareable(JNIEnv* env, jobject options) { 146 return options != NULL && 147 env->GetBooleanField(options, gOptions_shareableFieldID); 148 } 149 150 static bool optionsReportSizeToVM(JNIEnv* env, jobject options) { 151 return NULL == options || 152 !env->GetBooleanField(options, gOptions_nativeAllocFieldID); 153 } 154 155 156 static SkPixelRef* installPixelRef(SkBitmap* bitmap, SkStream* stream, 157 int sampleSize, bool ditherImage) { 158 SkImageRef* pr; 159 // only use ashmem for large images, since mmaps come at a price 160 if (bitmap->getSize() >= 32 * 1024) { 161 pr = new SkImageRef_ashmem(stream, bitmap->config(), sampleSize); 162 } else { 163 pr = new SkImageRef_GlobalPool(stream, bitmap->config(), sampleSize); 164 } 165 pr->setDitherImage(ditherImage); 166 bitmap->setPixelRef(pr)->unref(); 167 pr->isOpaque(bitmap); 168 return pr; 169 } 170 171 // since we "may" create a purgeable imageref, we require the stream be ref'able 172 // i.e. dynamically allocated, since its lifetime may exceed the current stack 173 // frame. 174 static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding, 175 jobject options, bool allowPurgeable, 176 bool forcePurgeable = false) { 177 int sampleSize = 1; 178 SkImageDecoder::Mode mode = SkImageDecoder::kDecodePixels_Mode; 179 SkBitmap::Config prefConfig = SkBitmap::kNo_Config; 180 bool doDither = true; 181 bool isPurgeable = forcePurgeable || 182 (allowPurgeable && optionsPurgeable(env, options)); 183 bool reportSizeToVM = optionsReportSizeToVM(env, options); 184 bool preferQualityOverSpeed = false; 185 186 if (NULL != options) { 187 sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID); 188 if (env->GetBooleanField(options, gOptions_justBoundsFieldID)) { 189 mode = SkImageDecoder::kDecodeBounds_Mode; 190 } 191 // initialize these, in case we fail later on 192 env->SetIntField(options, gOptions_widthFieldID, -1); 193 env->SetIntField(options, gOptions_heightFieldID, -1); 194 env->SetObjectField(options, gOptions_mimeFieldID, 0); 195 196 jobject jconfig = env->GetObjectField(options, gOptions_configFieldID); 197 prefConfig = GraphicsJNI::getNativeBitmapConfig(env, jconfig); 198 doDither = env->GetBooleanField(options, gOptions_ditherFieldID); 199 preferQualityOverSpeed = env->GetBooleanField(options, 200 gOptions_preferQualityOverSpeedFieldID); 201 } 202 203 SkImageDecoder* decoder = SkImageDecoder::Factory(stream); 204 if (NULL == decoder) { 205 return nullObjectReturn("SkImageDecoder::Factory returned null"); 206 } 207 208 decoder->setSampleSize(sampleSize); 209 decoder->setDitherImage(doDither); 210 decoder->setPreferQualityOverSpeed(preferQualityOverSpeed); 211 212 NinePatchPeeker peeker(decoder); 213 JavaPixelAllocator javaAllocator(env, reportSizeToVM); 214 SkBitmap* bitmap = new SkBitmap; 215 Res_png_9patch dummy9Patch; 216 217 SkAutoTDelete<SkImageDecoder> add(decoder); 218 SkAutoTDelete<SkBitmap> adb(bitmap); 219 220 decoder->setPeeker(&peeker); 221 if (!isPurgeable) { 222 decoder->setAllocator(&javaAllocator); 223 } 224 225 AutoDecoderCancel adc(options, decoder); 226 227 // To fix the race condition in case "requestCancelDecode" 228 // happens earlier than AutoDecoderCancel object is added 229 // to the gAutoDecoderCancelMutex linked list. 230 if (NULL != options && env->GetBooleanField(options, gOptions_mCancelID)) { 231 return nullObjectReturn("gOptions_mCancelID");; 232 } 233 234 SkImageDecoder::Mode decodeMode = mode; 235 if (isPurgeable) { 236 decodeMode = SkImageDecoder::kDecodeBounds_Mode; 237 } 238 if (!decoder->decode(stream, bitmap, prefConfig, decodeMode)) { 239 return nullObjectReturn("decoder->decode returned false"); 240 } 241 242 // update options (if any) 243 if (NULL != options) { 244 env->SetIntField(options, gOptions_widthFieldID, bitmap->width()); 245 env->SetIntField(options, gOptions_heightFieldID, bitmap->height()); 246 // TODO: set the mimeType field with the data from the codec. 247 // but how to reuse a set of strings, rather than allocating new one 248 // each time? 249 env->SetObjectField(options, gOptions_mimeFieldID, 250 getMimeTypeString(env, decoder->getFormat())); 251 } 252 253 // if we're in justBounds mode, return now (skip the java bitmap) 254 if (SkImageDecoder::kDecodeBounds_Mode == mode) { 255 return NULL; 256 } 257 258 jbyteArray ninePatchChunk = NULL; 259 if (peeker.fPatchIsValid) { 260 size_t ninePatchArraySize = peeker.fPatch->serializedSize(); 261 ninePatchChunk = env->NewByteArray(ninePatchArraySize); 262 if (NULL == ninePatchChunk) { 263 return nullObjectReturn("ninePatchChunk == null"); 264 } 265 jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(ninePatchChunk, 266 NULL); 267 if (NULL == array) { 268 return nullObjectReturn("primitive array == null"); 269 } 270 peeker.fPatch->serialize(array); 271 env->ReleasePrimitiveArrayCritical(ninePatchChunk, array, 0); 272 } 273 274 // detach bitmap from its autotdeleter, since we want to own it now 275 adb.detach(); 276 277 if (padding) { 278 if (peeker.fPatchIsValid) { 279 GraphicsJNI::set_jrect(env, padding, 280 peeker.fPatch->paddingLeft, 281 peeker.fPatch->paddingTop, 282 peeker.fPatch->paddingRight, 283 peeker.fPatch->paddingBottom); 284 } else { 285 GraphicsJNI::set_jrect(env, padding, -1, -1, -1, -1); 286 } 287 } 288 289 SkPixelRef* pr; 290 if (isPurgeable) { 291 pr = installPixelRef(bitmap, stream, sampleSize, doDither); 292 } else { 293 // if we get here, we're in kDecodePixels_Mode and will therefore 294 // already have a pixelref installed. 295 pr = bitmap->pixelRef(); 296 } 297 // promise we will never change our pixels (great for sharing and pictures) 298 pr->setImmutable(); 299 // now create the java bitmap 300 return GraphicsJNI::createBitmap(env, bitmap, false, ninePatchChunk); 301 } 302 303 static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, 304 jobject is, // InputStream 305 jbyteArray storage, // byte[] 306 jobject padding, 307 jobject options) { // BitmapFactory$Options 308 jobject bitmap = NULL; 309 SkStream* stream = CreateJavaInputStreamAdaptor(env, is, storage, 0); 310 311 if (stream) { 312 // for now we don't allow purgeable with java inputstreams 313 bitmap = doDecode(env, stream, padding, options, false); 314 stream->unref(); 315 } 316 return bitmap; 317 } 318 319 static ssize_t getFDSize(int fd) { 320 off_t curr = ::lseek(fd, 0, SEEK_CUR); 321 if (curr < 0) { 322 return 0; 323 } 324 size_t size = ::lseek(fd, 0, SEEK_END); 325 ::lseek(fd, curr, SEEK_SET); 326 return size; 327 } 328 329 static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, 330 jobject fileDescriptor, 331 jobject padding, 332 jobject bitmapFactoryOptions) { 333 NPE_CHECK_RETURN_ZERO(env, fileDescriptor); 334 335 jint descriptor = env->GetIntField(fileDescriptor, 336 gFileDescriptor_descriptor); 337 338 bool isPurgeable = optionsPurgeable(env, bitmapFactoryOptions); 339 bool isShareable = optionsShareable(env, bitmapFactoryOptions); 340 bool weOwnTheFD = false; 341 if (isPurgeable && isShareable) { 342 int newFD = ::dup(descriptor); 343 if (-1 != newFD) { 344 weOwnTheFD = true; 345 descriptor = newFD; 346 } 347 } 348 349 SkFDStream* stream = new SkFDStream(descriptor, weOwnTheFD); 350 SkAutoUnref aur(stream); 351 if (!stream->isValid()) { 352 return NULL; 353 } 354 355 /* Restore our offset when we leave, so we can be called more than once 356 with the same descriptor. This is only required if we didn't dup the 357 file descriptor, but it is OK to do it all the time. 358 */ 359 AutoFDSeek as(descriptor); 360 361 /* Allow purgeable iff we own the FD, i.e., in the puregeable and 362 shareable case. 363 */ 364 return doDecode(env, stream, padding, bitmapFactoryOptions, weOwnTheFD); 365 } 366 367 /* make a deep copy of the asset, and return it as a stream, or NULL if there 368 was an error. 369 */ 370 static SkStream* copyAssetToStream(Asset* asset) { 371 // if we could "ref/reopen" the asset, we may not need to copy it here 372 off_t size = asset->seek(0, SEEK_SET); 373 if ((off_t)-1 == size) { 374 SkDebugf("---- copyAsset: asset rewind failed\n"); 375 return NULL; 376 } 377 378 size = asset->getLength(); 379 if (size <= 0) { 380 SkDebugf("---- copyAsset: asset->getLength() returned %d\n", size); 381 return NULL; 382 } 383 384 SkStream* stream = new SkMemoryStream(size); 385 void* data = const_cast<void*>(stream->getMemoryBase()); 386 off_t len = asset->read(data, size); 387 if (len != size) { 388 SkDebugf("---- copyAsset: asset->read(%d) returned %d\n", size, len); 389 delete stream; 390 stream = NULL; 391 } 392 return stream; 393 } 394 395 static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, 396 jint native_asset, // Asset 397 jobject padding, // Rect 398 jobject options) { // BitmapFactory$Options 399 SkStream* stream; 400 Asset* asset = reinterpret_cast<Asset*>(native_asset); 401 bool forcePurgeable = optionsPurgeable(env, options); 402 if (forcePurgeable) { 403 // if we could "ref/reopen" the asset, we may not need to copy it here 404 // and we could assume optionsShareable, since assets are always RO 405 stream = copyAssetToStream(asset); 406 if (NULL == stream) { 407 return NULL; 408 } 409 } else { 410 // since we know we'll be done with the asset when we return, we can 411 // just use a simple wrapper 412 stream = new AssetStreamAdaptor(asset); 413 } 414 SkAutoUnref aur(stream); 415 return doDecode(env, stream, padding, options, true, forcePurgeable); 416 } 417 418 static jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray, 419 int offset, int length, jobject options) { 420 /* If optionsShareable() we could decide to just wrap the java array and 421 share it, but that means adding a globalref to the java array object 422 and managing its lifetime. For now we just always copy the array's data 423 if optionsPurgeable(). 424 */ 425 AutoJavaByteArray ar(env, byteArray); 426 SkStream* stream = new SkMemoryStream(ar.ptr() + offset, length, 427 optionsPurgeable(env, options)); 428 SkAutoUnref aur(stream); 429 return doDecode(env, stream, NULL, options, true); 430 } 431 432 static void nativeRequestCancel(JNIEnv*, jobject joptions) { 433 (void)AutoDecoderCancel::RequestCancel(joptions); 434 } 435 436 static jbyteArray nativeScaleNinePatch(JNIEnv* env, jobject, jbyteArray chunkObject, jfloat scale, 437 jobject padding) { 438 439 jbyte* array = env->GetByteArrayElements(chunkObject, 0); 440 if (array != NULL) { 441 size_t chunkSize = env->GetArrayLength(chunkObject); 442 void* storage = alloca(chunkSize); 443 android::Res_png_9patch* chunk = static_cast<android::Res_png_9patch*>(storage); 444 memcpy(chunk, array, chunkSize); 445 android::Res_png_9patch::deserialize(chunk); 446 447 chunk->paddingLeft = int(chunk->paddingLeft * scale + 0.5f); 448 chunk->paddingTop = int(chunk->paddingTop * scale + 0.5f); 449 chunk->paddingRight = int(chunk->paddingRight * scale + 0.5f); 450 chunk->paddingBottom = int(chunk->paddingBottom * scale + 0.5f); 451 452 for (int i = 0; i < chunk->numXDivs; i++) { 453 chunk->xDivs[i] = int(chunk->xDivs[i] * scale + 0.5f); 454 if (i > 0 && chunk->xDivs[i] == chunk->xDivs[i - 1]) { 455 chunk->xDivs[i]++; 456 } 457 } 458 459 for (int i = 0; i < chunk->numYDivs; i++) { 460 chunk->yDivs[i] = int(chunk->yDivs[i] * scale + 0.5f); 461 if (i > 0 && chunk->yDivs[i] == chunk->yDivs[i - 1]) { 462 chunk->yDivs[i]++; 463 } 464 } 465 466 memcpy(array, chunk, chunkSize); 467 468 if (padding) { 469 GraphicsJNI::set_jrect(env, padding, chunk->paddingLeft, chunk->paddingTop, 470 chunk->paddingRight, chunk->paddingBottom); 471 } 472 473 env->ReleaseByteArrayElements(chunkObject, array, 0); 474 } 475 return chunkObject; 476 } 477 478 static void nativeSetDefaultConfig(JNIEnv* env, jobject, int nativeConfig) { 479 SkBitmap::Config config = static_cast<SkBitmap::Config>(nativeConfig); 480 481 // these are the only default configs that make sense for codecs right now 482 static const SkBitmap::Config gValidDefConfig[] = { 483 SkBitmap::kRGB_565_Config, 484 SkBitmap::kARGB_8888_Config, 485 }; 486 487 for (size_t i = 0; i < SK_ARRAY_COUNT(gValidDefConfig); i++) { 488 if (config == gValidDefConfig[i]) { 489 SkImageDecoder::SetDeviceConfig(config); 490 break; 491 } 492 } 493 } 494 495 /////////////////////////////////////////////////////////////////////////////// 496 497 static JNINativeMethod gMethods[] = { 498 { "nativeDecodeStream", 499 "(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", 500 (void*)nativeDecodeStream 501 }, 502 503 { "nativeDecodeFileDescriptor", 504 "(Ljava/io/FileDescriptor;Landroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", 505 (void*)nativeDecodeFileDescriptor 506 }, 507 508 { "nativeDecodeAsset", 509 "(ILandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", 510 (void*)nativeDecodeAsset 511 }, 512 513 { "nativeDecodeByteArray", 514 "([BIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", 515 (void*)nativeDecodeByteArray 516 }, 517 518 { "nativeScaleNinePatch", 519 "([BFLandroid/graphics/Rect;)[B", 520 (void*)nativeScaleNinePatch 521 }, 522 523 { "nativeSetDefaultConfig", "(I)V", (void*)nativeSetDefaultConfig }, 524 }; 525 526 static JNINativeMethod gOptionsMethods[] = { 527 { "requestCancel", "()V", (void*)nativeRequestCancel } 528 }; 529 530 static jclass make_globalref(JNIEnv* env, const char classname[]) { 531 jclass c = env->FindClass(classname); 532 SkASSERT(c); 533 return (jclass)env->NewGlobalRef(c); 534 } 535 536 static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz, 537 const char fieldname[], const char type[]) { 538 jfieldID id = env->GetFieldID(clazz, fieldname, type); 539 SkASSERT(id); 540 return id; 541 } 542 543 #define kClassPathName "android/graphics/BitmapFactory" 544 545 #define RETURN_ERR_IF_NULL(value) \ 546 do { if (!(value)) { assert(0); return -1; } } while (false) 547 548 int register_android_graphics_BitmapFactory(JNIEnv* env); 549 int register_android_graphics_BitmapFactory(JNIEnv* env) { 550 gOptions_class = make_globalref(env, "android/graphics/BitmapFactory$Options"); 551 gOptions_justBoundsFieldID = getFieldIDCheck(env, gOptions_class, "inJustDecodeBounds", "Z"); 552 gOptions_sampleSizeFieldID = getFieldIDCheck(env, gOptions_class, "inSampleSize", "I"); 553 gOptions_configFieldID = getFieldIDCheck(env, gOptions_class, "inPreferredConfig", 554 "Landroid/graphics/Bitmap$Config;"); 555 gOptions_ditherFieldID = getFieldIDCheck(env, gOptions_class, "inDither", "Z"); 556 gOptions_purgeableFieldID = getFieldIDCheck(env, gOptions_class, "inPurgeable", "Z"); 557 gOptions_shareableFieldID = getFieldIDCheck(env, gOptions_class, "inInputShareable", "Z"); 558 gOptions_nativeAllocFieldID = getFieldIDCheck(env, gOptions_class, "inNativeAlloc", "Z"); 559 gOptions_preferQualityOverSpeedFieldID = getFieldIDCheck(env, gOptions_class, 560 "inPreferQualityOverSpeed", "Z"); 561 gOptions_widthFieldID = getFieldIDCheck(env, gOptions_class, "outWidth", "I"); 562 gOptions_heightFieldID = getFieldIDCheck(env, gOptions_class, "outHeight", "I"); 563 gOptions_mimeFieldID = getFieldIDCheck(env, gOptions_class, "outMimeType", "Ljava/lang/String;"); 564 gOptions_mCancelID = getFieldIDCheck(env, gOptions_class, "mCancel", "Z"); 565 566 gFileDescriptor_class = make_globalref(env, "java/io/FileDescriptor"); 567 gFileDescriptor_descriptor = getFieldIDCheck(env, gFileDescriptor_class, "descriptor", "I"); 568 569 int ret = AndroidRuntime::registerNativeMethods(env, 570 "android/graphics/BitmapFactory$Options", 571 gOptionsMethods, 572 SK_ARRAY_COUNT(gOptionsMethods)); 573 if (ret) { 574 return ret; 575 } 576 return android::AndroidRuntime::registerNativeMethods(env, kClassPathName, 577 gMethods, SK_ARRAY_COUNT(gMethods)); 578 } 579