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