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