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