1 #define LOG_TAG "BitmapFactory" 2 3 #include "BitmapFactory.h" 4 #include "CreateJavaOutputStreamAdaptor.h" 5 #include "GraphicsJNI.h" 6 #include "NinePatchPeeker.h" 7 #include "SkAndroidCodec.h" 8 #include "SkBRDAllocator.h" 9 #include "SkFrontBufferedStream.h" 10 #include "SkImageDecoder.h" 11 #include "SkMath.h" 12 #include "SkPixelRef.h" 13 #include "SkStream.h" 14 #include "SkUtils.h" 15 #include "Utils.h" 16 #include "core_jni_helpers.h" 17 18 #include <JNIHelp.h> 19 #include <androidfw/Asset.h> 20 #include <androidfw/ResourceTypes.h> 21 #include <cutils/compiler.h> 22 #include <memory> 23 #include <netinet/in.h> 24 #include <stdio.h> 25 #include <sys/mman.h> 26 #include <sys/stat.h> 27 28 jfieldID gOptions_justBoundsFieldID; 29 jfieldID gOptions_sampleSizeFieldID; 30 jfieldID gOptions_configFieldID; 31 jfieldID gOptions_premultipliedFieldID; 32 jfieldID gOptions_mutableFieldID; 33 jfieldID gOptions_ditherFieldID; 34 jfieldID gOptions_preferQualityOverSpeedFieldID; 35 jfieldID gOptions_scaledFieldID; 36 jfieldID gOptions_densityFieldID; 37 jfieldID gOptions_screenDensityFieldID; 38 jfieldID gOptions_targetDensityFieldID; 39 jfieldID gOptions_widthFieldID; 40 jfieldID gOptions_heightFieldID; 41 jfieldID gOptions_mimeFieldID; 42 jfieldID gOptions_mCancelID; 43 jfieldID gOptions_bitmapFieldID; 44 45 jfieldID gBitmap_ninePatchInsetsFieldID; 46 47 jclass gInsetStruct_class; 48 jmethodID gInsetStruct_constructorMethodID; 49 50 using namespace android; 51 52 jstring encodedFormatToString(JNIEnv* env, SkEncodedFormat format) { 53 const char* mimeType; 54 switch (format) { 55 case SkEncodedFormat::kBMP_SkEncodedFormat: 56 mimeType = "image/bmp"; 57 break; 58 case SkEncodedFormat::kGIF_SkEncodedFormat: 59 mimeType = "image/gif"; 60 break; 61 case SkEncodedFormat::kICO_SkEncodedFormat: 62 mimeType = "image/x-ico"; 63 break; 64 case SkEncodedFormat::kJPEG_SkEncodedFormat: 65 mimeType = "image/jpeg"; 66 break; 67 case SkEncodedFormat::kPNG_SkEncodedFormat: 68 mimeType = "image/png"; 69 break; 70 case SkEncodedFormat::kWEBP_SkEncodedFormat: 71 mimeType = "image/webp"; 72 break; 73 case SkEncodedFormat::kWBMP_SkEncodedFormat: 74 mimeType = "image/vnd.wap.wbmp"; 75 break; 76 case SkEncodedFormat::kRAW_SkEncodedFormat: 77 mimeType = "image/x-adobe-dng"; 78 break; 79 default: 80 mimeType = nullptr; 81 break; 82 } 83 84 jstring jstr = nullptr; 85 if (mimeType) { 86 // NOTE: Caller should env->ExceptionCheck() for OOM 87 // (can't check for nullptr as it's a valid return value) 88 jstr = env->NewStringUTF(mimeType); 89 } 90 return jstr; 91 } 92 93 static void scaleDivRange(int32_t* divs, int count, float scale, int maxValue) { 94 for (int i = 0; i < count; i++) { 95 divs[i] = int32_t(divs[i] * scale + 0.5f); 96 if (i > 0 && divs[i] == divs[i - 1]) { 97 divs[i]++; // avoid collisions 98 } 99 } 100 101 if (CC_UNLIKELY(divs[count - 1] > maxValue)) { 102 // if the collision avoidance above put some divs outside the bounds of the bitmap, 103 // slide outer stretchable divs inward to stay within bounds 104 int highestAvailable = maxValue; 105 for (int i = count - 1; i >= 0; i--) { 106 divs[i] = highestAvailable; 107 if (i > 0 && divs[i] <= divs[i-1]){ 108 // keep shifting 109 highestAvailable = divs[i] - 1; 110 } else { 111 break; 112 } 113 } 114 } 115 } 116 117 static void scaleNinePatchChunk(android::Res_png_9patch* chunk, float scale, 118 int scaledWidth, int scaledHeight) { 119 chunk->paddingLeft = int(chunk->paddingLeft * scale + 0.5f); 120 chunk->paddingTop = int(chunk->paddingTop * scale + 0.5f); 121 chunk->paddingRight = int(chunk->paddingRight * scale + 0.5f); 122 chunk->paddingBottom = int(chunk->paddingBottom * scale + 0.5f); 123 124 scaleDivRange(chunk->getXDivs(), chunk->numXDivs, scale, scaledWidth); 125 scaleDivRange(chunk->getYDivs(), chunk->numYDivs, scale, scaledHeight); 126 } 127 128 static SkColorType colorTypeForScaledOutput(SkColorType colorType) { 129 switch (colorType) { 130 case kUnknown_SkColorType: 131 case kIndex_8_SkColorType: 132 return kN32_SkColorType; 133 default: 134 break; 135 } 136 return colorType; 137 } 138 139 class ScaleCheckingAllocator : public SkBitmap::HeapAllocator { 140 public: 141 ScaleCheckingAllocator(float scale, int size) 142 : mScale(scale), mSize(size) { 143 } 144 145 virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) { 146 // accounts for scale in final allocation, using eventual size and config 147 const int bytesPerPixel = SkColorTypeBytesPerPixel( 148 colorTypeForScaledOutput(bitmap->colorType())); 149 const int requestedSize = bytesPerPixel * 150 int(bitmap->width() * mScale + 0.5f) * 151 int(bitmap->height() * mScale + 0.5f); 152 if (requestedSize > mSize) { 153 ALOGW("bitmap for alloc reuse (%d bytes) can't fit scaled bitmap (%d bytes)", 154 mSize, requestedSize); 155 return false; 156 } 157 return SkBitmap::HeapAllocator::allocPixelRef(bitmap, ctable); 158 } 159 private: 160 const float mScale; 161 const int mSize; 162 }; 163 164 class RecyclingPixelAllocator : public SkBitmap::Allocator { 165 public: 166 RecyclingPixelAllocator(android::Bitmap* bitmap, unsigned int size) 167 : mBitmap(bitmap), mSize(size) { 168 } 169 170 ~RecyclingPixelAllocator() { 171 } 172 173 virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) { 174 const SkImageInfo& info = bitmap->info(); 175 if (info.colorType() == kUnknown_SkColorType) { 176 ALOGW("unable to reuse a bitmap as the target has an unknown bitmap configuration"); 177 return false; 178 } 179 180 const int64_t size64 = info.getSafeSize64(bitmap->rowBytes()); 181 if (!sk_64_isS32(size64)) { 182 ALOGW("bitmap is too large"); 183 return false; 184 } 185 186 const size_t size = sk_64_asS32(size64); 187 if (size > mSize) { 188 ALOGW("bitmap marked for reuse (%u bytes) can't fit new bitmap " 189 "(%zu bytes)", mSize, size); 190 return false; 191 } 192 193 mBitmap->reconfigure(info, bitmap->rowBytes(), ctable); 194 bitmap->setPixelRef(mBitmap->refPixelRef())->unref(); 195 196 // since we're already allocated, we lockPixels right away 197 // HeapAllocator/JavaPixelAllocator behaves this way too 198 bitmap->lockPixels(); 199 return true; 200 } 201 202 private: 203 android::Bitmap* const mBitmap; 204 const unsigned int mSize; 205 }; 206 207 // Necessary for decodes when the native decoder cannot scale to appropriately match the sampleSize 208 // (for example, RAW). If the sampleSize divides evenly into the dimension, we require that the 209 // scale matches exactly. If sampleSize does not divide evenly, we allow the decoder to choose how 210 // best to round. 211 static bool needsFineScale(const int fullSize, const int decodedSize, const int sampleSize) { 212 if (fullSize % sampleSize == 0 && fullSize / sampleSize != decodedSize) { 213 return true; 214 } else if ((fullSize / sampleSize + 1) != decodedSize && 215 (fullSize / sampleSize) != decodedSize) { 216 return true; 217 } 218 return false; 219 } 220 221 static bool needsFineScale(const SkISize fullSize, const SkISize decodedSize, 222 const int sampleSize) { 223 return needsFineScale(fullSize.width(), decodedSize.width(), sampleSize) || 224 needsFineScale(fullSize.height(), decodedSize.height(), sampleSize); 225 } 226 227 static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding, jobject options) { 228 // This function takes ownership of the input stream. Since the SkAndroidCodec 229 // will take ownership of the stream, we don't necessarily need to take ownership 230 // here. This is a precaution - if we were to return before creating the codec, 231 // we need to make sure that we delete the stream. 232 std::unique_ptr<SkStreamRewindable> streamDeleter(stream); 233 234 // Set default values for the options parameters. 235 int sampleSize = 1; 236 bool onlyDecodeSize = false; 237 SkColorType prefColorType = kN32_SkColorType; 238 bool isMutable = false; 239 float scale = 1.0f; 240 bool requireUnpremultiplied = false; 241 jobject javaBitmap = NULL; 242 243 // Update with options supplied by the client. 244 if (options != NULL) { 245 sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID); 246 // Correct a non-positive sampleSize. sampleSize defaults to zero within the 247 // options object, which is strange. 248 if (sampleSize <= 0) { 249 sampleSize = 1; 250 } 251 252 if (env->GetBooleanField(options, gOptions_justBoundsFieldID)) { 253 onlyDecodeSize = true; 254 } 255 256 // initialize these, in case we fail later on 257 env->SetIntField(options, gOptions_widthFieldID, -1); 258 env->SetIntField(options, gOptions_heightFieldID, -1); 259 env->SetObjectField(options, gOptions_mimeFieldID, 0); 260 261 jobject jconfig = env->GetObjectField(options, gOptions_configFieldID); 262 prefColorType = GraphicsJNI::getNativeBitmapColorType(env, jconfig); 263 isMutable = env->GetBooleanField(options, gOptions_mutableFieldID); 264 requireUnpremultiplied = !env->GetBooleanField(options, gOptions_premultipliedFieldID); 265 javaBitmap = env->GetObjectField(options, gOptions_bitmapFieldID); 266 267 if (env->GetBooleanField(options, gOptions_scaledFieldID)) { 268 const int density = env->GetIntField(options, gOptions_densityFieldID); 269 const int targetDensity = env->GetIntField(options, gOptions_targetDensityFieldID); 270 const int screenDensity = env->GetIntField(options, gOptions_screenDensityFieldID); 271 if (density != 0 && targetDensity != 0 && density != screenDensity) { 272 scale = (float) targetDensity / density; 273 } 274 } 275 } 276 277 // Create the codec. 278 NinePatchPeeker peeker; 279 std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(streamDeleter.release(), 280 &peeker)); 281 if (!codec.get()) { 282 return nullObjectReturn("SkAndroidCodec::NewFromStream returned null"); 283 } 284 285 // Do not allow ninepatch decodes to 565. In the past, decodes to 565 286 // would dither, and we do not want to pre-dither ninepatches, since we 287 // know that they will be stretched. We no longer dither 565 decodes, 288 // but we continue to prevent ninepatches from decoding to 565, in order 289 // to maintain the old behavior. 290 if (peeker.mPatch && kRGB_565_SkColorType == prefColorType) { 291 prefColorType = kN32_SkColorType; 292 } 293 294 // Determine the output size. 295 SkISize size = codec->getSampledDimensions(sampleSize); 296 297 int scaledWidth = size.width(); 298 int scaledHeight = size.height(); 299 bool willScale = false; 300 301 // Apply a fine scaling step if necessary. 302 if (needsFineScale(codec->getInfo().dimensions(), size, sampleSize)) { 303 willScale = true; 304 scaledWidth = codec->getInfo().width() / sampleSize; 305 scaledHeight = codec->getInfo().height() / sampleSize; 306 } 307 308 // Set the options and return if the client only wants the size. 309 if (options != NULL) { 310 jstring mimeType = encodedFormatToString(env, codec->getEncodedFormat()); 311 if (env->ExceptionCheck()) { 312 return nullObjectReturn("OOM in encodedFormatToString()"); 313 } 314 env->SetIntField(options, gOptions_widthFieldID, scaledWidth); 315 env->SetIntField(options, gOptions_heightFieldID, scaledHeight); 316 env->SetObjectField(options, gOptions_mimeFieldID, mimeType); 317 318 if (onlyDecodeSize) { 319 return nullptr; 320 } 321 } 322 323 // Scale is necessary due to density differences. 324 if (scale != 1.0f) { 325 willScale = true; 326 scaledWidth = static_cast<int>(scaledWidth * scale + 0.5f); 327 scaledHeight = static_cast<int>(scaledHeight * scale + 0.5f); 328 } 329 330 android::Bitmap* reuseBitmap = nullptr; 331 unsigned int existingBufferSize = 0; 332 if (javaBitmap != NULL) { 333 reuseBitmap = GraphicsJNI::getBitmap(env, javaBitmap); 334 if (reuseBitmap->peekAtPixelRef()->isImmutable()) { 335 ALOGW("Unable to reuse an immutable bitmap as an image decoder target."); 336 javaBitmap = NULL; 337 reuseBitmap = nullptr; 338 } else { 339 existingBufferSize = GraphicsJNI::getBitmapAllocationByteCount(env, javaBitmap); 340 } 341 } 342 343 JavaPixelAllocator javaAllocator(env); 344 RecyclingPixelAllocator recyclingAllocator(reuseBitmap, existingBufferSize); 345 ScaleCheckingAllocator scaleCheckingAllocator(scale, existingBufferSize); 346 SkBitmap::HeapAllocator heapAllocator; 347 SkBitmap::Allocator* decodeAllocator; 348 if (javaBitmap != nullptr && willScale) { 349 // This will allocate pixels using a HeapAllocator, since there will be an extra 350 // scaling step that copies these pixels into Java memory. This allocator 351 // also checks that the recycled javaBitmap is large enough. 352 decodeAllocator = &scaleCheckingAllocator; 353 } else if (javaBitmap != nullptr) { 354 decodeAllocator = &recyclingAllocator; 355 } else if (willScale) { 356 // This will allocate pixels using a HeapAllocator, since there will be an extra 357 // scaling step that copies these pixels into Java memory. 358 decodeAllocator = &heapAllocator; 359 } else { 360 decodeAllocator = &javaAllocator; 361 } 362 363 // Set the decode colorType. This is necessary because we can't always support 364 // the requested colorType. 365 SkColorType decodeColorType = codec->computeOutputColorType(prefColorType); 366 367 // Construct a color table for the decode if necessary 368 SkAutoTUnref<SkColorTable> colorTable(nullptr); 369 SkPMColor* colorPtr = nullptr; 370 int* colorCount = nullptr; 371 int maxColors = 256; 372 SkPMColor colors[256]; 373 if (kIndex_8_SkColorType == decodeColorType) { 374 colorTable.reset(new SkColorTable(colors, maxColors)); 375 376 // SkColorTable expects us to initialize all of the colors before creating an 377 // SkColorTable. However, we are using SkBitmap with an Allocator to allocate 378 // memory for the decode, so we need to create the SkColorTable before decoding. 379 // It is safe for SkAndroidCodec to modify the colors because this SkBitmap is 380 // not being used elsewhere. 381 colorPtr = const_cast<SkPMColor*>(colorTable->readColors()); 382 colorCount = &maxColors; 383 } 384 385 // Set the alpha type for the decode. 386 SkAlphaType alphaType = codec->computeOutputAlphaType(requireUnpremultiplied); 387 388 const SkImageInfo decodeInfo = SkImageInfo::Make(size.width(), size.height(), decodeColorType, 389 alphaType); 390 SkImageInfo bitmapInfo = decodeInfo; 391 if (decodeColorType == kGray_8_SkColorType) { 392 // The legacy implementation of BitmapFactory used kAlpha8 for 393 // grayscale images (before kGray8 existed). While the codec 394 // recognizes kGray8, we need to decode into a kAlpha8 bitmap 395 // in order to avoid a behavior change. 396 bitmapInfo = SkImageInfo::MakeA8(size.width(), size.height()); 397 } 398 SkBitmap decodingBitmap; 399 if (!decodingBitmap.setInfo(bitmapInfo) || 400 !decodingBitmap.tryAllocPixels(decodeAllocator, colorTable)) { 401 // SkAndroidCodec should recommend a valid SkImageInfo, so setInfo() 402 // should only only fail if the calculated value for rowBytes is too 403 // large. 404 // tryAllocPixels() can fail due to OOM on the Java heap, OOM on the 405 // native heap, or the recycled javaBitmap being too small to reuse. 406 return nullptr; 407 } 408 409 // Use SkAndroidCodec to perform the decode. 410 SkAndroidCodec::AndroidOptions codecOptions; 411 codecOptions.fZeroInitialized = (decodeAllocator == &javaAllocator) ? 412 SkCodec::kYes_ZeroInitialized : SkCodec::kNo_ZeroInitialized; 413 codecOptions.fColorPtr = colorPtr; 414 codecOptions.fColorCount = colorCount; 415 codecOptions.fSampleSize = sampleSize; 416 SkCodec::Result result = codec->getAndroidPixels(decodeInfo, decodingBitmap.getPixels(), 417 decodingBitmap.rowBytes(), &codecOptions); 418 switch (result) { 419 case SkCodec::kSuccess: 420 case SkCodec::kIncompleteInput: 421 break; 422 default: 423 return nullObjectReturn("codec->getAndroidPixels() failed."); 424 } 425 426 jbyteArray ninePatchChunk = NULL; 427 if (peeker.mPatch != NULL) { 428 if (willScale) { 429 scaleNinePatchChunk(peeker.mPatch, scale, scaledWidth, scaledHeight); 430 } 431 432 size_t ninePatchArraySize = peeker.mPatch->serializedSize(); 433 ninePatchChunk = env->NewByteArray(ninePatchArraySize); 434 if (ninePatchChunk == NULL) { 435 return nullObjectReturn("ninePatchChunk == null"); 436 } 437 438 jbyte* array = (jbyte*) env->GetPrimitiveArrayCritical(ninePatchChunk, NULL); 439 if (array == NULL) { 440 return nullObjectReturn("primitive array == null"); 441 } 442 443 memcpy(array, peeker.mPatch, peeker.mPatchSize); 444 env->ReleasePrimitiveArrayCritical(ninePatchChunk, array, 0); 445 } 446 447 jobject ninePatchInsets = NULL; 448 if (peeker.mHasInsets) { 449 ninePatchInsets = env->NewObject(gInsetStruct_class, gInsetStruct_constructorMethodID, 450 peeker.mOpticalInsets[0], peeker.mOpticalInsets[1], peeker.mOpticalInsets[2], peeker.mOpticalInsets[3], 451 peeker.mOutlineInsets[0], peeker.mOutlineInsets[1], peeker.mOutlineInsets[2], peeker.mOutlineInsets[3], 452 peeker.mOutlineRadius, peeker.mOutlineAlpha, scale); 453 if (ninePatchInsets == NULL) { 454 return nullObjectReturn("nine patch insets == null"); 455 } 456 if (javaBitmap != NULL) { 457 env->SetObjectField(javaBitmap, gBitmap_ninePatchInsetsFieldID, ninePatchInsets); 458 } 459 } 460 461 SkBitmap outputBitmap; 462 if (willScale) { 463 // This is weird so let me explain: we could use the scale parameter 464 // directly, but for historical reasons this is how the corresponding 465 // Dalvik code has always behaved. We simply recreate the behavior here. 466 // The result is slightly different from simply using scale because of 467 // the 0.5f rounding bias applied when computing the target image size 468 const float sx = scaledWidth / float(decodingBitmap.width()); 469 const float sy = scaledHeight / float(decodingBitmap.height()); 470 471 // Set the allocator for the outputBitmap. 472 SkBitmap::Allocator* outputAllocator; 473 if (javaBitmap != nullptr) { 474 outputAllocator = &recyclingAllocator; 475 } else { 476 outputAllocator = &javaAllocator; 477 } 478 479 SkColorType scaledColorType = colorTypeForScaledOutput(decodingBitmap.colorType()); 480 // FIXME: If the alphaType is kUnpremul and the image has alpha, the 481 // colors may not be correct, since Skia does not yet support drawing 482 // to/from unpremultiplied bitmaps. 483 outputBitmap.setInfo(SkImageInfo::Make(scaledWidth, scaledHeight, 484 scaledColorType, decodingBitmap.alphaType())); 485 if (!outputBitmap.tryAllocPixels(outputAllocator, NULL)) { 486 // This should only fail on OOM. The recyclingAllocator should have 487 // enough memory since we check this before decoding using the 488 // scaleCheckingAllocator. 489 return nullObjectReturn("allocation failed for scaled bitmap"); 490 } 491 492 SkPaint paint; 493 // kSrc_Mode instructs us to overwrite the unininitialized pixels in 494 // outputBitmap. Otherwise we would blend by default, which is not 495 // what we want. 496 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 497 paint.setFilterQuality(kLow_SkFilterQuality); 498 499 SkCanvas canvas(outputBitmap); 500 canvas.scale(sx, sy); 501 canvas.drawBitmap(decodingBitmap, 0.0f, 0.0f, &paint); 502 } else { 503 outputBitmap.swap(decodingBitmap); 504 } 505 506 if (padding) { 507 if (peeker.mPatch != NULL) { 508 GraphicsJNI::set_jrect(env, padding, 509 peeker.mPatch->paddingLeft, peeker.mPatch->paddingTop, 510 peeker.mPatch->paddingRight, peeker.mPatch->paddingBottom); 511 } else { 512 GraphicsJNI::set_jrect(env, padding, -1, -1, -1, -1); 513 } 514 } 515 516 // If we get here, the outputBitmap should have an installed pixelref. 517 if (outputBitmap.pixelRef() == NULL) { 518 return nullObjectReturn("Got null SkPixelRef"); 519 } 520 521 if (!isMutable && javaBitmap == NULL) { 522 // promise we will never change our pixels (great for sharing and pictures) 523 outputBitmap.setImmutable(); 524 } 525 526 bool isPremultiplied = !requireUnpremultiplied; 527 if (javaBitmap != nullptr) { 528 GraphicsJNI::reinitBitmap(env, javaBitmap, outputBitmap.info(), isPremultiplied); 529 outputBitmap.notifyPixelsChanged(); 530 // If a java bitmap was passed in for reuse, pass it back 531 return javaBitmap; 532 } 533 534 int bitmapCreateFlags = 0x0; 535 if (isMutable) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Mutable; 536 if (isPremultiplied) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Premultiplied; 537 538 // now create the java bitmap 539 return GraphicsJNI::createBitmap(env, javaAllocator.getStorageObjAndReset(), 540 bitmapCreateFlags, ninePatchChunk, ninePatchInsets, -1); 541 } 542 543 static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteArray storage, 544 jobject padding, jobject options) { 545 546 jobject bitmap = NULL; 547 std::unique_ptr<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage)); 548 549 if (stream.get()) { 550 std::unique_ptr<SkStreamRewindable> bufferedStream( 551 SkFrontBufferedStream::Create(stream.release(), SkCodec::MinBufferedBytesNeeded())); 552 SkASSERT(bufferedStream.get() != NULL); 553 bitmap = doDecode(env, bufferedStream.release(), padding, options); 554 } 555 return bitmap; 556 } 557 558 static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fileDescriptor, 559 jobject padding, jobject bitmapFactoryOptions) { 560 561 NPE_CHECK_RETURN_ZERO(env, fileDescriptor); 562 563 int descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor); 564 565 struct stat fdStat; 566 if (fstat(descriptor, &fdStat) == -1) { 567 doThrowIOE(env, "broken file descriptor"); 568 return nullObjectReturn("fstat return -1"); 569 } 570 571 // Restore the descriptor's offset on exiting this function. Even though 572 // we dup the descriptor, both the original and dup refer to the same open 573 // file description and changes to the file offset in one impact the other. 574 AutoFDSeek autoRestore(descriptor); 575 576 // Duplicate the descriptor here to prevent leaking memory. A leak occurs 577 // if we only close the file descriptor and not the file object it is used to 578 // create. If we don't explicitly clean up the file (which in turn closes the 579 // descriptor) the buffers allocated internally by fseek will be leaked. 580 int dupDescriptor = dup(descriptor); 581 582 FILE* file = fdopen(dupDescriptor, "r"); 583 if (file == NULL) { 584 // cleanup the duplicated descriptor since it will not be closed when the 585 // file is cleaned up (fclose). 586 close(dupDescriptor); 587 return nullObjectReturn("Could not open file"); 588 } 589 590 std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file, 591 SkFILEStream::kCallerPasses_Ownership)); 592 593 // If there is no offset for the file descriptor, we use SkFILEStream directly. 594 if (::lseek(descriptor, 0, SEEK_CUR) == 0) { 595 assert(isSeekable(dupDescriptor)); 596 return doDecode(env, fileStream.release(), padding, bitmapFactoryOptions); 597 } 598 599 // Use a buffered stream. Although an SkFILEStream can be rewound, this 600 // ensures that SkImageDecoder::Factory never rewinds beyond the 601 // current position of the file descriptor. 602 std::unique_ptr<SkStreamRewindable> stream(SkFrontBufferedStream::Create(fileStream.release(), 603 SkCodec::MinBufferedBytesNeeded())); 604 605 return doDecode(env, stream.release(), padding, bitmapFactoryOptions); 606 } 607 608 static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, jlong native_asset, 609 jobject padding, jobject options) { 610 611 Asset* asset = reinterpret_cast<Asset*>(native_asset); 612 // since we know we'll be done with the asset when we return, we can 613 // just use a simple wrapper 614 std::unique_ptr<AssetStreamAdaptor> stream(new AssetStreamAdaptor(asset)); 615 return doDecode(env, stream.release(), padding, options); 616 } 617 618 static jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray, 619 jint offset, jint length, jobject options) { 620 621 AutoJavaByteArray ar(env, byteArray); 622 std::unique_ptr<SkMemoryStream> stream(new SkMemoryStream(ar.ptr() + offset, length, false)); 623 return doDecode(env, stream.release(), NULL, options); 624 } 625 626 static jboolean nativeIsSeekable(JNIEnv* env, jobject, jobject fileDescriptor) { 627 jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor); 628 return isSeekable(descriptor) ? JNI_TRUE : JNI_FALSE; 629 } 630 631 jobject decodeBitmap(JNIEnv* env, void* data, size_t size) { 632 SkMemoryStream stream(data, size); 633 return doDecode(env, &stream, NULL, NULL); 634 } 635 636 /////////////////////////////////////////////////////////////////////////////// 637 638 static const JNINativeMethod gMethods[] = { 639 { "nativeDecodeStream", 640 "(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", 641 (void*)nativeDecodeStream 642 }, 643 644 { "nativeDecodeFileDescriptor", 645 "(Ljava/io/FileDescriptor;Landroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", 646 (void*)nativeDecodeFileDescriptor 647 }, 648 649 { "nativeDecodeAsset", 650 "(JLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", 651 (void*)nativeDecodeAsset 652 }, 653 654 { "nativeDecodeByteArray", 655 "([BIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", 656 (void*)nativeDecodeByteArray 657 }, 658 659 { "nativeIsSeekable", 660 "(Ljava/io/FileDescriptor;)Z", 661 (void*)nativeIsSeekable 662 }, 663 }; 664 665 int register_android_graphics_BitmapFactory(JNIEnv* env) { 666 jclass options_class = FindClassOrDie(env, "android/graphics/BitmapFactory$Options"); 667 gOptions_bitmapFieldID = GetFieldIDOrDie(env, options_class, "inBitmap", 668 "Landroid/graphics/Bitmap;"); 669 gOptions_justBoundsFieldID = GetFieldIDOrDie(env, options_class, "inJustDecodeBounds", "Z"); 670 gOptions_sampleSizeFieldID = GetFieldIDOrDie(env, options_class, "inSampleSize", "I"); 671 gOptions_configFieldID = GetFieldIDOrDie(env, options_class, "inPreferredConfig", 672 "Landroid/graphics/Bitmap$Config;"); 673 gOptions_premultipliedFieldID = GetFieldIDOrDie(env, options_class, "inPremultiplied", "Z"); 674 gOptions_mutableFieldID = GetFieldIDOrDie(env, options_class, "inMutable", "Z"); 675 gOptions_ditherFieldID = GetFieldIDOrDie(env, options_class, "inDither", "Z"); 676 gOptions_preferQualityOverSpeedFieldID = GetFieldIDOrDie(env, options_class, 677 "inPreferQualityOverSpeed", "Z"); 678 gOptions_scaledFieldID = GetFieldIDOrDie(env, options_class, "inScaled", "Z"); 679 gOptions_densityFieldID = GetFieldIDOrDie(env, options_class, "inDensity", "I"); 680 gOptions_screenDensityFieldID = GetFieldIDOrDie(env, options_class, "inScreenDensity", "I"); 681 gOptions_targetDensityFieldID = GetFieldIDOrDie(env, options_class, "inTargetDensity", "I"); 682 gOptions_widthFieldID = GetFieldIDOrDie(env, options_class, "outWidth", "I"); 683 gOptions_heightFieldID = GetFieldIDOrDie(env, options_class, "outHeight", "I"); 684 gOptions_mimeFieldID = GetFieldIDOrDie(env, options_class, "outMimeType", "Ljava/lang/String;"); 685 gOptions_mCancelID = GetFieldIDOrDie(env, options_class, "mCancel", "Z"); 686 687 jclass bitmap_class = FindClassOrDie(env, "android/graphics/Bitmap"); 688 gBitmap_ninePatchInsetsFieldID = GetFieldIDOrDie(env, bitmap_class, "mNinePatchInsets", 689 "Landroid/graphics/NinePatch$InsetStruct;"); 690 691 gInsetStruct_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, 692 "android/graphics/NinePatch$InsetStruct")); 693 gInsetStruct_constructorMethodID = GetMethodIDOrDie(env, gInsetStruct_class, "<init>", 694 "(IIIIIIIIFIF)V"); 695 696 return android::RegisterMethodsOrDie(env, "android/graphics/BitmapFactory", 697 gMethods, NELEM(gMethods)); 698 } 699