19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define LOG_TAG "BitmapFactory" 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3f1f48bc7f200f54c76b22d845d8ba8419879b375Joseph Wen#include "BitmapFactory.h" 460126efd7d905ca24822765c6dafac17fef278abBen Wagner#include "CreateJavaOutputStreamAdaptor.h" 560126efd7d905ca24822765c6dafac17fef278abBen Wagner#include "GraphicsJNI.h" 6a06d86ab8177ee9e631e0ee4e39688bf42179bdeLeon Scroggins#include "NinePatchPeeker.h" 7b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett#include "SkAndroidCodec.h" 8b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett#include "SkBRDAllocator.h" 97315f1baee19476363235127bc1438e2a291fa15Leon Scroggins III#include "SkFrontBufferedStream.h" 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "SkImageDecoder.h" 1146cb9bdbf56b27cbf2ab878b41d21e30896a4feaLeon Scroggins#include "SkMath.h" 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "SkPixelRef.h" 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "SkStream.h" 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "SkUtils.h" 156b849e2123be98eb2a1a25b8abf0b13a279ce952Wei-Ta Chen#include "Utils.h" 16ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe#include "core_jni_helpers.h" 1760126efd7d905ca24822765c6dafac17fef278abBen Wagner 1860126efd7d905ca24822765c6dafac17fef278abBen Wagner#include <JNIHelp.h> 19b13b9bdad2baf6ad1ec2e56b6b7598fa20f55fc4Mathias Agopian#include <androidfw/Asset.h> 20b13b9bdad2baf6ad1ec2e56b6b7598fa20f55fc4Mathias Agopian#include <androidfw/ResourceTypes.h> 21bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik#include <cutils/compiler.h> 2260126efd7d905ca24822765c6dafac17fef278abBen Wagner#include <memory> 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <netinet/in.h> 240102f8a87a7571b1ff537a1293d67ae8fa001167Leon Scroggins III#include <stdio.h> 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/mman.h> 262dcfbefbbeac406d16ec379c6430dd9ee9fd23a1Joseph Wen#include <sys/stat.h> 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28f1f48bc7f200f54c76b22d845d8ba8419879b375Joseph WenjfieldID gOptions_justBoundsFieldID; 29f1f48bc7f200f54c76b22d845d8ba8419879b375Joseph WenjfieldID gOptions_sampleSizeFieldID; 30f1f48bc7f200f54c76b22d845d8ba8419879b375Joseph WenjfieldID gOptions_configFieldID; 311abf5d62429e5a9329520b2f7c2b5a5e7a8e72ecChris CraikjfieldID gOptions_premultipliedFieldID; 322361098da3b9d9c3eeed410dc72ba62c0e9177cfRomain GuyjfieldID gOptions_mutableFieldID; 33f1f48bc7f200f54c76b22d845d8ba8419879b375Joseph WenjfieldID gOptions_ditherFieldID; 34953f9094a2ec14594fa8501d5f3e2d9e300b1b62Wei-Ta ChenjfieldID gOptions_preferQualityOverSpeedFieldID; 35905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris CraikjfieldID gOptions_scaledFieldID; 36905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris CraikjfieldID gOptions_densityFieldID; 37905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris CraikjfieldID gOptions_screenDensityFieldID; 38905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris CraikjfieldID gOptions_targetDensityFieldID; 39f1f48bc7f200f54c76b22d845d8ba8419879b375Joseph WenjfieldID gOptions_widthFieldID; 40f1f48bc7f200f54c76b22d845d8ba8419879b375Joseph WenjfieldID gOptions_heightFieldID; 41f1f48bc7f200f54c76b22d845d8ba8419879b375Joseph WenjfieldID gOptions_mimeFieldID; 42f1f48bc7f200f54c76b22d845d8ba8419879b375Joseph WenjfieldID gOptions_mCancelID; 4337f74cad46c6f1799aec3c52e8f47598237f43d4Chet HaasejfieldID gOptions_bitmapFieldID; 4447cd8e921db73e894f94ec4729ade90da50996f5Chris Craik 4547cd8e921db73e894f94ec4729ade90da50996f5Chris CraikjfieldID gBitmap_ninePatchInsetsFieldID; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4747cd8e921db73e894f94ec4729ade90da50996f5Chris Craikjclass gInsetStruct_class; 4847cd8e921db73e894f94ec4729ade90da50996f5Chris CraikjmethodID gInsetStruct_constructorMethodID; 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectusing namespace android; 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 52b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarettjstring encodedFormatToString(JNIEnv* env, SkEncodedFormat format) { 53b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett const char* mimeType; 54b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett switch (format) { 55b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett case SkEncodedFormat::kBMP_SkEncodedFormat: 56b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett mimeType = "image/bmp"; 57b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett break; 58b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett case SkEncodedFormat::kGIF_SkEncodedFormat: 59b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett mimeType = "image/gif"; 60b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett break; 61b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett case SkEncodedFormat::kICO_SkEncodedFormat: 62b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett mimeType = "image/x-ico"; 63b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett break; 64b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett case SkEncodedFormat::kJPEG_SkEncodedFormat: 65b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett mimeType = "image/jpeg"; 66b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett break; 67b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett case SkEncodedFormat::kPNG_SkEncodedFormat: 68b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett mimeType = "image/png"; 69b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett break; 70b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett case SkEncodedFormat::kWEBP_SkEncodedFormat: 71b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett mimeType = "image/webp"; 72b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett break; 73b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett case SkEncodedFormat::kWBMP_SkEncodedFormat: 74b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett mimeType = "image/vnd.wap.wbmp"; 75b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett break; 76990ea136b202a9956a5d35ac7895655ece34f5f6Yujie Qin case SkEncodedFormat::kRAW_SkEncodedFormat: 77990ea136b202a9956a5d35ac7895655ece34f5f6Yujie Qin mimeType = "image/x-adobe-dng"; 78990ea136b202a9956a5d35ac7895655ece34f5f6Yujie Qin break; 79b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett default: 80b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett mimeType = nullptr; 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 847ab249a18e08bfefb8c2d60af1fb668c67ba4368Vladimir Marko jstring jstr = nullptr; 85b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett if (mimeType) { 867ab249a18e08bfefb8c2d60af1fb668c67ba4368Vladimir Marko // NOTE: Caller should env->ExceptionCheck() for OOM 877ab249a18e08bfefb8c2d60af1fb668c67ba4368Vladimir Marko // (can't check for nullptr as it's a valid return value) 88b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett jstr = env->NewStringUTF(mimeType); 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return jstr; 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 93bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craikstatic void scaleDivRange(int32_t* divs, int count, float scale, int maxValue) { 94bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik for (int i = 0; i < count; i++) { 95bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik divs[i] = int32_t(divs[i] * scale + 0.5f); 96bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik if (i > 0 && divs[i] == divs[i - 1]) { 97bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik divs[i]++; // avoid collisions 987b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy } 997b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy } 1007b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy 101bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik if (CC_UNLIKELY(divs[count - 1] > maxValue)) { 102bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik // if the collision avoidance above put some divs outside the bounds of the bitmap, 103bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik // slide outer stretchable divs inward to stay within bounds 104bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik int highestAvailable = maxValue; 105bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik for (int i = count - 1; i >= 0; i--) { 106bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik divs[i] = highestAvailable; 107bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik if (i > 0 && divs[i] <= divs[i-1]){ 108bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik // keep shifting 109bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik highestAvailable = divs[i] - 1; 110bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik } else { 111bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik break; 112bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik } 1137b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy } 1147b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy } 1157b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy} 1167b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy 117bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craikstatic void scaleNinePatchChunk(android::Res_png_9patch* chunk, float scale, 118bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik int scaledWidth, int scaledHeight) { 119bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik chunk->paddingLeft = int(chunk->paddingLeft * scale + 0.5f); 120bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik chunk->paddingTop = int(chunk->paddingTop * scale + 0.5f); 121bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik chunk->paddingRight = int(chunk->paddingRight * scale + 0.5f); 122bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik chunk->paddingBottom = int(chunk->paddingBottom * scale + 0.5f); 123bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik 124bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik scaleDivRange(chunk->getXDivs(), chunk->numXDivs, scale, scaledWidth); 125bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik scaleDivRange(chunk->getYDivs(), chunk->numYDivs, scale, scaledHeight); 126bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik} 127bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik 12846cb9bdbf56b27cbf2ab878b41d21e30896a4feaLeon Scrogginsstatic SkColorType colorTypeForScaledOutput(SkColorType colorType) { 12946cb9bdbf56b27cbf2ab878b41d21e30896a4feaLeon Scroggins switch (colorType) { 13046cb9bdbf56b27cbf2ab878b41d21e30896a4feaLeon Scroggins case kUnknown_SkColorType: 13146cb9bdbf56b27cbf2ab878b41d21e30896a4feaLeon Scroggins case kIndex_8_SkColorType: 1324a9c3891d4f890109e02bc83fecf9bcdf56a9395Mike Reed return kN32_SkColorType; 133905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik default: 134905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik break; 135905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik } 13646cb9bdbf56b27cbf2ab878b41d21e30896a4feaLeon Scroggins return colorType; 137905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik} 138905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik 139905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craikclass ScaleCheckingAllocator : public SkBitmap::HeapAllocator { 140905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craikpublic: 141905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik ScaleCheckingAllocator(float scale, int size) 142905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik : mScale(scale), mSize(size) { 143905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik } 144905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik 145905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) { 146905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik // accounts for scale in final allocation, using eventual size and config 14746cb9bdbf56b27cbf2ab878b41d21e30896a4feaLeon Scroggins const int bytesPerPixel = SkColorTypeBytesPerPixel( 14846cb9bdbf56b27cbf2ab878b41d21e30896a4feaLeon Scroggins colorTypeForScaledOutput(bitmap->colorType())); 149905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik const int requestedSize = bytesPerPixel * 150905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik int(bitmap->width() * mScale + 0.5f) * 151905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik int(bitmap->height() * mScale + 0.5f); 152905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik if (requestedSize > mSize) { 153905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik ALOGW("bitmap for alloc reuse (%d bytes) can't fit scaled bitmap (%d bytes)", 154905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik mSize, requestedSize); 155905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik return false; 156905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik } 157905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik return SkBitmap::HeapAllocator::allocPixelRef(bitmap, ctable); 158905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik } 159905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craikprivate: 160905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik const float mScale; 161905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik const int mSize; 162905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik}; 163905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik 1647e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craikclass RecyclingPixelAllocator : public SkBitmap::Allocator { 1657e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craikpublic: 166f29ed28c7b878ef28058bc730715d0d32445bc57John Reck RecyclingPixelAllocator(android::Bitmap* bitmap, unsigned int size) 167f29ed28c7b878ef28058bc730715d0d32445bc57John Reck : mBitmap(bitmap), mSize(size) { 1687e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craik } 1697e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craik 1707e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craik ~RecyclingPixelAllocator() { 1717e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craik } 1727e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craik 1737e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craik virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) { 17446cb9bdbf56b27cbf2ab878b41d21e30896a4feaLeon Scroggins const SkImageInfo& info = bitmap->info(); 175f35b989d26bb98900f6c5fa2e586326b30b6e161Leon Scroggins III if (info.colorType() == kUnknown_SkColorType) { 17646cb9bdbf56b27cbf2ab878b41d21e30896a4feaLeon Scroggins ALOGW("unable to reuse a bitmap as the target has an unknown bitmap configuration"); 1777e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craik return false; 1787e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craik } 179cd0ba71aa942f35fcdb26808b86f20073b8aff92Chris Craik 18046cb9bdbf56b27cbf2ab878b41d21e30896a4feaLeon Scroggins const int64_t size64 = info.getSafeSize64(bitmap->rowBytes()); 18146cb9bdbf56b27cbf2ab878b41d21e30896a4feaLeon Scroggins if (!sk_64_isS32(size64)) { 18246cb9bdbf56b27cbf2ab878b41d21e30896a4feaLeon Scroggins ALOGW("bitmap is too large"); 18346cb9bdbf56b27cbf2ab878b41d21e30896a4feaLeon Scroggins return false; 18446cb9bdbf56b27cbf2ab878b41d21e30896a4feaLeon Scroggins } 18546cb9bdbf56b27cbf2ab878b41d21e30896a4feaLeon Scroggins 18646cb9bdbf56b27cbf2ab878b41d21e30896a4feaLeon Scroggins const size_t size = sk_64_asS32(size64); 18746cb9bdbf56b27cbf2ab878b41d21e30896a4feaLeon Scroggins if (size > mSize) { 18846d8444631b4b1253a76bfcc78a29d26014d022fDan Albert ALOGW("bitmap marked for reuse (%u bytes) can't fit new bitmap " 18946d8444631b4b1253a76bfcc78a29d26014d022fDan Albert "(%zu bytes)", mSize, size); 190b644a3b84521e2155a5af985a4d4ed305474e567Derek Sollenberger return false; 191b644a3b84521e2155a5af985a4d4ed305474e567Derek Sollenberger } 192b644a3b84521e2155a5af985a4d4ed305474e567Derek Sollenberger 193f29ed28c7b878ef28058bc730715d0d32445bc57John Reck mBitmap->reconfigure(info, bitmap->rowBytes(), ctable); 194ae2e8b4891491e8e89bed5f2c9626415adee09cbJohn Reck bitmap->setPixelRef(mBitmap->refPixelRef())->unref(); 195cd0ba71aa942f35fcdb26808b86f20073b8aff92Chris Craik 196cd0ba71aa942f35fcdb26808b86f20073b8aff92Chris Craik // since we're already allocated, we lockPixels right away 197cd0ba71aa942f35fcdb26808b86f20073b8aff92Chris Craik // HeapAllocator/JavaPixelAllocator behaves this way too 1987e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craik bitmap->lockPixels(); 1997e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craik return true; 2007e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craik } 2017e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craik 2027e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craikprivate: 203f29ed28c7b878ef28058bc730715d0d32445bc57John Reck android::Bitmap* const mBitmap; 2047e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craik const unsigned int mSize; 2057e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craik}; 2067e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craik 2074e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert// Necessary for decodes when the native decoder cannot scale to appropriately match the sampleSize 2084e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert// (for example, RAW). If the sampleSize divides evenly into the dimension, we require that the 2094e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert// scale matches exactly. If sampleSize does not divide evenly, we allow the decoder to choose how 2104e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert// best to round. 2114e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubertstatic bool needsFineScale(const int fullSize, const int decodedSize, const int sampleSize) { 2124e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert if (fullSize % sampleSize == 0 && fullSize / sampleSize != decodedSize) { 2134e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert return true; 2144e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert } else if ((fullSize / sampleSize + 1) != decodedSize && 2154e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert (fullSize / sampleSize) != decodedSize) { 2164e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert return true; 2174e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert } 2184e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert return false; 2194e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert} 2204e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert 2214e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubertstatic bool needsFineScale(const SkISize fullSize, const SkISize decodedSize, 2224e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert const int sampleSize) { 2234e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert return needsFineScale(fullSize.width(), decodedSize.width(), sampleSize) || 2244e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert needsFineScale(fullSize.height(), decodedSize.height(), sampleSize); 2254e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert} 2264e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert 22747cd8e921db73e894f94ec4729ade90da50996f5Chris Craikstatic jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding, jobject options) { 228b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // This function takes ownership of the input stream. Since the SkAndroidCodec 229b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // will take ownership of the stream, we don't necessarily need to take ownership 230b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // here. This is a precaution - if we were to return before creating the codec, 231b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // we need to make sure that we delete the stream. 232b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett std::unique_ptr<SkStreamRewindable> streamDeleter(stream); 2337b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy 234b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // Set default values for the options parameters. 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int sampleSize = 1; 236b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett bool onlyDecodeSize = false; 23742a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed SkColorType prefColorType = kN32_SkColorType; 2382361098da3b9d9c3eeed410dc72ba62c0e9177cfRomain Guy bool isMutable = false; 239905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik float scale = 1.0f; 2401abf5d62429e5a9329520b2f7c2b5a5e7a8e72ecChris Craik bool requireUnpremultiplied = false; 24137f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase jobject javaBitmap = NULL; 242a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes 243b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // Update with options supplied by the client. 2447b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy if (options != NULL) { 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID); 246b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // Correct a non-positive sampleSize. sampleSize defaults to zero within the 247b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // options object, which is strange. 248b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett if (sampleSize <= 0) { 249b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett sampleSize = 1; 250b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett } 251b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett 252b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett if (env->GetBooleanField(options, gOptions_justBoundsFieldID)) { 253b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett onlyDecodeSize = true; 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2557b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // initialize these, in case we fail later on 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project env->SetIntField(options, gOptions_widthFieldID, -1); 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project env->SetIntField(options, gOptions_heightFieldID, -1); 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project env->SetObjectField(options, gOptions_mimeFieldID, 0); 260a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jobject jconfig = env->GetObjectField(options, gOptions_configFieldID); 26242a1d08df7d417fd4e67eabc91ff05ee77fd9995Mike Reed prefColorType = GraphicsJNI::getNativeBitmapColorType(env, jconfig); 2632361098da3b9d9c3eeed410dc72ba62c0e9177cfRomain Guy isMutable = env->GetBooleanField(options, gOptions_mutableFieldID); 2641abf5d62429e5a9329520b2f7c2b5a5e7a8e72ecChris Craik requireUnpremultiplied = !env->GetBooleanField(options, gOptions_premultipliedFieldID); 26537f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase javaBitmap = env->GetObjectField(options, gOptions_bitmapFieldID); 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 267905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik if (env->GetBooleanField(options, gOptions_scaledFieldID)) { 268905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik const int density = env->GetIntField(options, gOptions_densityFieldID); 269905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik const int targetDensity = env->GetIntField(options, gOptions_targetDensityFieldID); 270905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik const int screenDensity = env->GetIntField(options, gOptions_screenDensityFieldID); 271905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik if (density != 0 && targetDensity != 0 && density != screenDensity) { 272905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik scale = (float) targetDensity / density; 273905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik } 274905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik } 2757b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy } 276905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik 277b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // Create the codec. 278b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett NinePatchPeeker peeker; 279b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(streamDeleter.release(), 280b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett &peeker)); 281b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett if (!codec.get()) { 282b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett return nullObjectReturn("SkAndroidCodec::NewFromStream returned null"); 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 284a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes 2853b1b68d6c764a4f60d034e57a94879b7df65fd43Matt Sarett // Do not allow ninepatch decodes to 565. In the past, decodes to 565 2863b1b68d6c764a4f60d034e57a94879b7df65fd43Matt Sarett // would dither, and we do not want to pre-dither ninepatches, since we 2873b1b68d6c764a4f60d034e57a94879b7df65fd43Matt Sarett // know that they will be stretched. We no longer dither 565 decodes, 2883b1b68d6c764a4f60d034e57a94879b7df65fd43Matt Sarett // but we continue to prevent ninepatches from decoding to 565, in order 2893b1b68d6c764a4f60d034e57a94879b7df65fd43Matt Sarett // to maintain the old behavior. 2903b1b68d6c764a4f60d034e57a94879b7df65fd43Matt Sarett if (peeker.mPatch && kRGB_565_SkColorType == prefColorType) { 2913b1b68d6c764a4f60d034e57a94879b7df65fd43Matt Sarett prefColorType = kN32_SkColorType; 2923b1b68d6c764a4f60d034e57a94879b7df65fd43Matt Sarett } 2933b1b68d6c764a4f60d034e57a94879b7df65fd43Matt Sarett 2944e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert // Determine the output size. 295b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett SkISize size = codec->getSampledDimensions(sampleSize); 2964e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert 2974e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert int scaledWidth = size.width(); 2984e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert int scaledHeight = size.height(); 2994e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert bool willScale = false; 3004e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert 3014e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert // Apply a fine scaling step if necessary. 3024e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert if (needsFineScale(codec->getInfo().dimensions(), size, sampleSize)) { 3034e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert willScale = true; 3044e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert scaledWidth = codec->getInfo().width() / sampleSize; 3054e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert scaledHeight = codec->getInfo().height() / sampleSize; 3064e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert } 3074e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert 3084e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert // Set the options and return if the client only wants the size. 309b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett if (options != NULL) { 310b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett jstring mimeType = encodedFormatToString(env, codec->getEncodedFormat()); 311b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett if (env->ExceptionCheck()) { 312d31512b9a6d9d6913b1d45ad2fb029a98c1804bfMatt Sarett return nullObjectReturn("OOM in encodedFormatToString()"); 313b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett } 3144e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert env->SetIntField(options, gOptions_widthFieldID, scaledWidth); 3154e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert env->SetIntField(options, gOptions_heightFieldID, scaledHeight); 316b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett env->SetObjectField(options, gOptions_mimeFieldID, mimeType); 317b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett 318b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett if (onlyDecodeSize) { 319b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett return nullptr; 320b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett } 321b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett } 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3234e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert // Scale is necessary due to density differences. 3244e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert if (scale != 1.0f) { 3254e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert willScale = true; 3264e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert scaledWidth = static_cast<int>(scaledWidth * scale + 0.5f); 3274e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert scaledHeight = static_cast<int>(scaledHeight * scale + 0.5f); 3284e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert } 3294e5ec34e98faa8338ca04282a160ef2b0d13bc9dAnton Daubert 330f29ed28c7b878ef28058bc730715d0d32445bc57John Reck android::Bitmap* reuseBitmap = nullptr; 3319f58361e98be7386a4eadd3aa254e9b7d09d0a3bChris Craik unsigned int existingBufferSize = 0; 3327e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craik if (javaBitmap != NULL) { 333f29ed28c7b878ef28058bc730715d0d32445bc57John Reck reuseBitmap = GraphicsJNI::getBitmap(env, javaBitmap); 334ae2e8b4891491e8e89bed5f2c9626415adee09cbJohn Reck if (reuseBitmap->peekAtPixelRef()->isImmutable()) { 3352a6ecae93d4effa47827029d74f2136b5ae8558dDerek Sollenberger ALOGW("Unable to reuse an immutable bitmap as an image decoder target."); 3367e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craik javaBitmap = NULL; 337f29ed28c7b878ef28058bc730715d0d32445bc57John Reck reuseBitmap = nullptr; 3387e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craik } else { 3397e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craik existingBufferSize = GraphicsJNI::getBitmapAllocationByteCount(env, javaBitmap); 3402a6ecae93d4effa47827029d74f2136b5ae8558dDerek Sollenberger } 34137f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase } 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 343905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik JavaPixelAllocator javaAllocator(env); 344f29ed28c7b878ef28058bc730715d0d32445bc57John Reck RecyclingPixelAllocator recyclingAllocator(reuseBitmap, existingBufferSize); 345905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik ScaleCheckingAllocator scaleCheckingAllocator(scale, existingBufferSize); 346b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett SkBitmap::HeapAllocator heapAllocator; 347b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett SkBitmap::Allocator* decodeAllocator; 348b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett if (javaBitmap != nullptr && willScale) { 349b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // This will allocate pixels using a HeapAllocator, since there will be an extra 350b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // scaling step that copies these pixels into Java memory. This allocator 351b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // also checks that the recycled javaBitmap is large enough. 352b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett decodeAllocator = &scaleCheckingAllocator; 353b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett } else if (javaBitmap != nullptr) { 354b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett decodeAllocator = &recyclingAllocator; 355b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett } else if (willScale) { 356b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // This will allocate pixels using a HeapAllocator, since there will be an extra 357b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // scaling step that copies these pixels into Java memory. 358b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett decodeAllocator = &heapAllocator; 359b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett } else { 360b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett decodeAllocator = &javaAllocator; 361905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik } 362905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik 3639e7cd6351b8245d3b0eff902beb89dc4c6d3ed19Matt Sarett // Set the decode colorType. This is necessary because we can't always support 3649e7cd6351b8245d3b0eff902beb89dc4c6d3ed19Matt Sarett // the requested colorType. 3659e7cd6351b8245d3b0eff902beb89dc4c6d3ed19Matt Sarett SkColorType decodeColorType = codec->computeOutputColorType(prefColorType); 366b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett 367b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // Construct a color table for the decode if necessary 368b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett SkAutoTUnref<SkColorTable> colorTable(nullptr); 369b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett SkPMColor* colorPtr = nullptr; 370b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett int* colorCount = nullptr; 371b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett int maxColors = 256; 372b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett SkPMColor colors[256]; 373b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett if (kIndex_8_SkColorType == decodeColorType) { 374b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett colorTable.reset(new SkColorTable(colors, maxColors)); 375b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett 376b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // SkColorTable expects us to initialize all of the colors before creating an 377b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // SkColorTable. However, we are using SkBitmap with an Allocator to allocate 378b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // memory for the decode, so we need to create the SkColorTable before decoding. 379b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // It is safe for SkAndroidCodec to modify the colors because this SkBitmap is 380b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // not being used elsewhere. 381b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett colorPtr = const_cast<SkPMColor*>(colorTable->readColors()); 382b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett colorCount = &maxColors; 383b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett } 3846b0437c2c7a552c8195956444facff3532e25c21Derek Sollenberger 3859e7cd6351b8245d3b0eff902beb89dc4c6d3ed19Matt Sarett // Set the alpha type for the decode. 3869e7cd6351b8245d3b0eff902beb89dc4c6d3ed19Matt Sarett SkAlphaType alphaType = codec->computeOutputAlphaType(requireUnpremultiplied); 3876b0437c2c7a552c8195956444facff3532e25c21Derek Sollenberger 388b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett const SkImageInfo decodeInfo = SkImageInfo::Make(size.width(), size.height(), decodeColorType, 389b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett alphaType); 390b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett SkImageInfo bitmapInfo = decodeInfo; 391b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett if (decodeColorType == kGray_8_SkColorType) { 392b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // The legacy implementation of BitmapFactory used kAlpha8 for 393b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // grayscale images (before kGray8 existed). While the codec 394b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // recognizes kGray8, we need to decode into a kAlpha8 bitmap 395b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // in order to avoid a behavior change. 396b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett bitmapInfo = SkImageInfo::MakeA8(size.width(), size.height()); 397b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett } 3987e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craik SkBitmap decodingBitmap; 399b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett if (!decodingBitmap.setInfo(bitmapInfo) || 400b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett !decodingBitmap.tryAllocPixels(decodeAllocator, colorTable)) { 401b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // SkAndroidCodec should recommend a valid SkImageInfo, so setInfo() 402b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // should only only fail if the calculated value for rowBytes is too 403b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // large. 404b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // tryAllocPixels() can fail due to OOM on the Java heap, OOM on the 405b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // native heap, or the recycled javaBitmap being too small to reuse. 406b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett return nullptr; 407c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed } 408c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed 409b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // Use SkAndroidCodec to perform the decode. 410b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett SkAndroidCodec::AndroidOptions codecOptions; 411b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett codecOptions.fZeroInitialized = (decodeAllocator == &javaAllocator) ? 412b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett SkCodec::kYes_ZeroInitialized : SkCodec::kNo_ZeroInitialized; 413b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett codecOptions.fColorPtr = colorPtr; 414b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett codecOptions.fColorCount = colorCount; 415b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett codecOptions.fSampleSize = sampleSize; 416b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett SkCodec::Result result = codec->getAndroidPixels(decodeInfo, decodingBitmap.getPixels(), 417b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett decodingBitmap.rowBytes(), &codecOptions); 418b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett switch (result) { 419b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett case SkCodec::kSuccess: 420b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett case SkCodec::kIncompleteInput: 421b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett break; 422b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett default: 4233b1b68d6c764a4f60d034e57a94879b7df65fd43Matt Sarett return nullObjectReturn("codec->getAndroidPixels() failed."); 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jbyteArray ninePatchChunk = NULL; 42747cd8e921db73e894f94ec4729ade90da50996f5Chris Craik if (peeker.mPatch != NULL) { 4287b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy if (willScale) { 429bd8db2e87e16900ff9b87937d3ccff6a50bd5b2aChris Craik scaleNinePatchChunk(peeker.mPatch, scale, scaledWidth, scaledHeight); 4307b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy } 4317b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy 43247cd8e921db73e894f94ec4729ade90da50996f5Chris Craik size_t ninePatchArraySize = peeker.mPatch->serializedSize(); 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ninePatchChunk = env->NewByteArray(ninePatchArraySize); 4347b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy if (ninePatchChunk == NULL) { 435c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed return nullObjectReturn("ninePatchChunk == null"); 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4377b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy 4387b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy jbyte* array = (jbyte*) env->GetPrimitiveArrayCritical(ninePatchChunk, NULL); 4397b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy if (array == NULL) { 440c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed return nullObjectReturn("primitive array == null"); 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4427b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy 44347cd8e921db73e894f94ec4729ade90da50996f5Chris Craik memcpy(array, peeker.mPatch, peeker.mPatchSize); 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project env->ReleasePrimitiveArrayCritical(ninePatchChunk, array, 0); 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 44747cd8e921db73e894f94ec4729ade90da50996f5Chris Craik jobject ninePatchInsets = NULL; 44847cd8e921db73e894f94ec4729ade90da50996f5Chris Craik if (peeker.mHasInsets) { 44947cd8e921db73e894f94ec4729ade90da50996f5Chris Craik ninePatchInsets = env->NewObject(gInsetStruct_class, gInsetStruct_constructorMethodID, 45047cd8e921db73e894f94ec4729ade90da50996f5Chris Craik peeker.mOpticalInsets[0], peeker.mOpticalInsets[1], peeker.mOpticalInsets[2], peeker.mOpticalInsets[3], 45147cd8e921db73e894f94ec4729ade90da50996f5Chris Craik peeker.mOutlineInsets[0], peeker.mOutlineInsets[1], peeker.mOutlineInsets[2], peeker.mOutlineInsets[3], 45277b5cad3efedd20f2b7cc14d87ccce1b0261960aChris Craik peeker.mOutlineRadius, peeker.mOutlineAlpha, scale); 453a08d10fa7051668b629d561bb8411e34d28fdabfMathieu Chartier if (ninePatchInsets == NULL) { 454a08d10fa7051668b629d561bb8411e34d28fdabfMathieu Chartier return nullObjectReturn("nine patch insets == null"); 455a08d10fa7051668b629d561bb8411e34d28fdabfMathieu Chartier } 456ec4a50428d5f26a22df3edaf7e5b08f41d5cb54bAmith Yamasani if (javaBitmap != NULL) { 45747cd8e921db73e894f94ec4729ade90da50996f5Chris Craik env->SetObjectField(javaBitmap, gBitmap_ninePatchInsetsFieldID, ninePatchInsets); 458ec4a50428d5f26a22df3edaf7e5b08f41d5cb54bAmith Yamasani } 459ec4a50428d5f26a22df3edaf7e5b08f41d5cb54bAmith Yamasani } 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 461f29ed28c7b878ef28058bc730715d0d32445bc57John Reck SkBitmap outputBitmap; 4627b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy if (willScale) { 4637b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy // This is weird so let me explain: we could use the scale parameter 4647b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy // directly, but for historical reasons this is how the corresponding 4657b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy // Dalvik code has always behaved. We simply recreate the behavior here. 4667b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy // The result is slightly different from simply using scale because of 4677b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy // the 0.5f rounding bias applied when computing the target image size 4687e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craik const float sx = scaledWidth / float(decodingBitmap.width()); 4697e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craik const float sy = scaledHeight / float(decodingBitmap.height()); 4707b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy 471b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // Set the allocator for the outputBitmap. 472b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett SkBitmap::Allocator* outputAllocator; 473b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett if (javaBitmap != nullptr) { 474b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett outputAllocator = &recyclingAllocator; 475b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett } else { 476b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett outputAllocator = &javaAllocator; 477b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett } 478b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett 479b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett SkColorType scaledColorType = colorTypeForScaledOutput(decodingBitmap.colorType()); 4808790be6de3644e332ec6a17c855da89ffc13a9bfLeon Scroggins III // FIXME: If the alphaType is kUnpremul and the image has alpha, the 4818790be6de3644e332ec6a17c855da89ffc13a9bfLeon Scroggins III // colors may not be correct, since Skia does not yet support drawing 4828790be6de3644e332ec6a17c855da89ffc13a9bfLeon Scroggins III // to/from unpremultiplied bitmaps. 483f29ed28c7b878ef28058bc730715d0d32445bc57John Reck outputBitmap.setInfo(SkImageInfo::Make(scaledWidth, scaledHeight, 484b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett scaledColorType, decodingBitmap.alphaType())); 485f29ed28c7b878ef28058bc730715d0d32445bc57John Reck if (!outputBitmap.tryAllocPixels(outputAllocator, NULL)) { 486b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // This should only fail on OOM. The recyclingAllocator should have 487b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // enough memory since we check this before decoding using the 488b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // scaleCheckingAllocator. 489005bfc694d167b7da4b565a1c4de03592fdbe86eRaph Levien return nullObjectReturn("allocation failed for scaled bitmap"); 490005bfc694d167b7da4b565a1c4de03592fdbe86eRaph Levien } 4911ffe727c0616ca11092a45c3dfb94479fe55fdd9Leon Scroggins III 4927b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy SkPaint paint; 493b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // kSrc_Mode instructs us to overwrite the unininitialized pixels in 494b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // outputBitmap. Otherwise we would blend by default, which is not 495b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // what we want. 496b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett paint.setXfermodeMode(SkXfermode::kSrc_Mode); 4972a1ce8a4e5258b6599cb8e86864eb816d24d69b4Mike Reed paint.setFilterQuality(kLow_SkFilterQuality); 4987b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy 499f29ed28c7b878ef28058bc730715d0d32445bc57John Reck SkCanvas canvas(outputBitmap); 5007b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy canvas.scale(sx, sy); 5017e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craik canvas.drawBitmap(decodingBitmap, 0.0f, 0.0f, &paint); 5027e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craik } else { 503f29ed28c7b878ef28058bc730715d0d32445bc57John Reck outputBitmap.swap(decodingBitmap); 5047b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy } 5057b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (padding) { 50747cd8e921db73e894f94ec4729ade90da50996f5Chris Craik if (peeker.mPatch != NULL) { 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project GraphicsJNI::set_jrect(env, padding, 50947cd8e921db73e894f94ec4729ade90da50996f5Chris Craik peeker.mPatch->paddingLeft, peeker.mPatch->paddingTop, 51047cd8e921db73e894f94ec4729ade90da50996f5Chris Craik peeker.mPatch->paddingRight, peeker.mPatch->paddingBottom); 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project GraphicsJNI::set_jrect(env, padding, -1, -1, -1, -1); 5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 516b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett // If we get here, the outputBitmap should have an installed pixelref. 517f29ed28c7b878ef28058bc730715d0d32445bc57John Reck if (outputBitmap.pixelRef() == NULL) { 518b2fe3be4fffc9ff1bfbba0c450d64ccd6e6c4011Marco Nelissen return nullObjectReturn("Got null SkPixelRef"); 519b2fe3be4fffc9ff1bfbba0c450d64ccd6e6c4011Marco Nelissen } 5202361098da3b9d9c3eeed410dc72ba62c0e9177cfRomain Guy 5217e8c03c0fed64c73a4f0cfb96a2c6905b348a143Chris Craik if (!isMutable && javaBitmap == NULL) { 5222361098da3b9d9c3eeed410dc72ba62c0e9177cfRomain Guy // promise we will never change our pixels (great for sharing and pictures) 523f29ed28c7b878ef28058bc730715d0d32445bc57John Reck outputBitmap.setImmutable(); 5242361098da3b9d9c3eeed410dc72ba62c0e9177cfRomain Guy } 52537f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase 526b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett bool isPremultiplied = !requireUnpremultiplied; 527b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett if (javaBitmap != nullptr) { 528f29ed28c7b878ef28058bc730715d0d32445bc57John Reck GraphicsJNI::reinitBitmap(env, javaBitmap, outputBitmap.info(), isPremultiplied); 529f29ed28c7b878ef28058bc730715d0d32445bc57John Reck outputBitmap.notifyPixelsChanged(); 53037f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase // If a java bitmap was passed in for reuse, pass it back 53137f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase return javaBitmap; 53237f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase } 5331abf5d62429e5a9329520b2f7c2b5a5e7a8e72ecChris Craik 5341abf5d62429e5a9329520b2f7c2b5a5e7a8e72ecChris Craik int bitmapCreateFlags = 0x0; 5351abf5d62429e5a9329520b2f7c2b5a5e7a8e72ecChris Craik if (isMutable) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Mutable; 536b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett if (isPremultiplied) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Premultiplied; 5371abf5d62429e5a9329520b2f7c2b5a5e7a8e72ecChris Craik 538c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed // now create the java bitmap 539f29ed28c7b878ef28058bc730715d0d32445bc57John Reck return GraphicsJNI::createBitmap(env, javaAllocator.getStorageObjAndReset(), 54047cd8e921db73e894f94ec4729ade90da50996f5Chris Craik bitmapCreateFlags, ninePatchChunk, ninePatchInsets, -1); 5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 543905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craikstatic jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteArray storage, 544905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik jobject padding, jobject options) { 5457b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy 5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jobject bitmap = NULL; 54760126efd7d905ca24822765c6dafac17fef278abBen Wagner std::unique_ptr<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage)); 5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 549ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III if (stream.get()) { 55060126efd7d905ca24822765c6dafac17fef278abBen Wagner std::unique_ptr<SkStreamRewindable> bufferedStream( 55196ffbdc9ddd8e8fd6582a907b1c5e916d21e44faMatt Sarett SkFrontBufferedStream::Create(stream.release(), SkCodec::MinBufferedBytesNeeded())); 5527315f1baee19476363235127bc1438e2a291fa15Leon Scroggins III SkASSERT(bufferedStream.get() != NULL); 553b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett bitmap = doDecode(env, bufferedStream.release(), padding, options); 5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return bitmap; 5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5587b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guystatic jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fileDescriptor, 5597b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy jobject padding, jobject bitmapFactoryOptions) { 5607b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy 5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project NPE_CHECK_RETURN_ZERO(env, fileDescriptor); 5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5635cb769d99952ef9fb4f576abba70423fe157342bDerek Sollenberger int descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor); 564c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed 5655827cb5059ed0eec4c73adf1acbd7ee47b2c5c8fDerek Sollenberger struct stat fdStat; 5665827cb5059ed0eec4c73adf1acbd7ee47b2c5c8fDerek Sollenberger if (fstat(descriptor, &fdStat) == -1) { 5675827cb5059ed0eec4c73adf1acbd7ee47b2c5c8fDerek Sollenberger doThrowIOE(env, "broken file descriptor"); 5685827cb5059ed0eec4c73adf1acbd7ee47b2c5c8fDerek Sollenberger return nullObjectReturn("fstat return -1"); 5695827cb5059ed0eec4c73adf1acbd7ee47b2c5c8fDerek Sollenberger } 5705827cb5059ed0eec4c73adf1acbd7ee47b2c5c8fDerek Sollenberger 5715cb769d99952ef9fb4f576abba70423fe157342bDerek Sollenberger // Restore the descriptor's offset on exiting this function. Even though 5725cb769d99952ef9fb4f576abba70423fe157342bDerek Sollenberger // we dup the descriptor, both the original and dup refer to the same open 5735cb769d99952ef9fb4f576abba70423fe157342bDerek Sollenberger // file description and changes to the file offset in one impact the other. 574d29c902f9822ab4b11dd4b91729c64d6987cdf29Jérôme Poichet AutoFDSeek autoRestore(descriptor); 5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5765cb769d99952ef9fb4f576abba70423fe157342bDerek Sollenberger // Duplicate the descriptor here to prevent leaking memory. A leak occurs 5775cb769d99952ef9fb4f576abba70423fe157342bDerek Sollenberger // if we only close the file descriptor and not the file object it is used to 5785cb769d99952ef9fb4f576abba70423fe157342bDerek Sollenberger // create. If we don't explicitly clean up the file (which in turn closes the 5795cb769d99952ef9fb4f576abba70423fe157342bDerek Sollenberger // descriptor) the buffers allocated internally by fseek will be leaked. 5805cb769d99952ef9fb4f576abba70423fe157342bDerek Sollenberger int dupDescriptor = dup(descriptor); 5815cb769d99952ef9fb4f576abba70423fe157342bDerek Sollenberger 5825cb769d99952ef9fb4f576abba70423fe157342bDerek Sollenberger FILE* file = fdopen(dupDescriptor, "r"); 5830102f8a87a7571b1ff537a1293d67ae8fa001167Leon Scroggins III if (file == NULL) { 5845cb769d99952ef9fb4f576abba70423fe157342bDerek Sollenberger // cleanup the duplicated descriptor since it will not be closed when the 5855cb769d99952ef9fb4f576abba70423fe157342bDerek Sollenberger // file is cleaned up (fclose). 5865cb769d99952ef9fb4f576abba70423fe157342bDerek Sollenberger close(dupDescriptor); 5870102f8a87a7571b1ff537a1293d67ae8fa001167Leon Scroggins III return nullObjectReturn("Could not open file"); 588f65183fd76aa82eedaebcbde9395a5dba42fc969Leon Scroggins III } 5890102f8a87a7571b1ff537a1293d67ae8fa001167Leon Scroggins III 59060126efd7d905ca24822765c6dafac17fef278abBen Wagner std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file, 5913449789b9ca58fee7e5cd02ff89d544f4a6bc9b5Leon Scroggins III SkFILEStream::kCallerPasses_Ownership)); 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 593c1d7b7f71ce1a55548d7e8bb32d728190e2ffd47Yujie Qin // If there is no offset for the file descriptor, we use SkFILEStream directly. 594c1d7b7f71ce1a55548d7e8bb32d728190e2ffd47Yujie Qin if (::lseek(descriptor, 0, SEEK_CUR) == 0) { 595c1d7b7f71ce1a55548d7e8bb32d728190e2ffd47Yujie Qin assert(isSeekable(dupDescriptor)); 596c1d7b7f71ce1a55548d7e8bb32d728190e2ffd47Yujie Qin return doDecode(env, fileStream.release(), padding, bitmapFactoryOptions); 597c1d7b7f71ce1a55548d7e8bb32d728190e2ffd47Yujie Qin } 598c1d7b7f71ce1a55548d7e8bb32d728190e2ffd47Yujie Qin 5990aa39dc2dcfca20f4d9cbeb1699d48a4808f2c70Leon Scroggins III // Use a buffered stream. Although an SkFILEStream can be rewound, this 6000aa39dc2dcfca20f4d9cbeb1699d48a4808f2c70Leon Scroggins III // ensures that SkImageDecoder::Factory never rewinds beyond the 6010aa39dc2dcfca20f4d9cbeb1699d48a4808f2c70Leon Scroggins III // current position of the file descriptor. 60260126efd7d905ca24822765c6dafac17fef278abBen Wagner std::unique_ptr<SkStreamRewindable> stream(SkFrontBufferedStream::Create(fileStream.release(), 60396ffbdc9ddd8e8fd6582a907b1c5e916d21e44faMatt Sarett SkCodec::MinBufferedBytesNeeded())); 6042826e5f20295a1adb3b341c8b32f27d748e2ee19Leon Scroggins III 605b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett return doDecode(env, stream.release(), padding, bitmapFactoryOptions); 606c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed} 607c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed 60836bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhatstatic jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, jlong native_asset, 609905e8246ef0bd20ee28d81ce3da0c5e5fc8e3913Chris Craik jobject padding, jobject options) { 6107b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy 611c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed Asset* asset = reinterpret_cast<Asset*>(native_asset); 6120aa39dc2dcfca20f4d9cbeb1699d48a4808f2c70Leon Scroggins III // since we know we'll be done with the asset when we return, we can 6130aa39dc2dcfca20f4d9cbeb1699d48a4808f2c70Leon Scroggins III // just use a simple wrapper 614b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett std::unique_ptr<AssetStreamAdaptor> stream(new AssetStreamAdaptor(asset)); 615b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett return doDecode(env, stream.release(), padding, options); 6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray, 61936bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat jint offset, jint length, jobject options) { 6207b2f8b8fb7064a1d3b6d942b978c30c24c9d7299Romain Guy 621c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed AutoJavaByteArray ar(env, byteArray); 622b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett std::unique_ptr<SkMemoryStream> stream(new SkMemoryStream(ar.ptr() + offset, length, false)); 623b8adc9a37fc92006ebc3c621316f4cd233d4bb83Matt Sarett return doDecode(env, stream.release(), NULL, options); 6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 626a9d0d47076ecf2d1739bb3534abc9deead8ebebdOwen Linstatic jboolean nativeIsSeekable(JNIEnv* env, jobject, jobject fileDescriptor) { 627a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor); 628c1d7b7f71ce1a55548d7e8bb32d728190e2ffd47Yujie Qin return isSeekable(descriptor) ? JNI_TRUE : JNI_FALSE; 629a9d0d47076ecf2d1739bb3534abc9deead8ebebdOwen Lin} 630a9d0d47076ecf2d1739bb3534abc9deead8ebebdOwen Lin 6314147877b388eb4a6f4e1ee116edfa58a018891caJohn Reckjobject decodeBitmap(JNIEnv* env, void* data, size_t size) { 63260126efd7d905ca24822765c6dafac17fef278abBen Wagner SkMemoryStream stream(data, size); 6334147877b388eb4a6f4e1ee116edfa58a018891caJohn Reck return doDecode(env, &stream, NULL, NULL); 6344147877b388eb4a6f4e1ee116edfa58a018891caJohn Reck} 6354147877b388eb4a6f4e1ee116edfa58a018891caJohn Reck 6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/////////////////////////////////////////////////////////////////////////////// 6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 63876f6a86de25e1bf74717e047e55fd44b089673f3Daniel Micaystatic const JNINativeMethod gMethods[] = { 6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { "nativeDecodeStream", 6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", 6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (void*)nativeDecodeStream 6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }, 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { "nativeDecodeFileDescriptor", 6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "(Ljava/io/FileDescriptor;Landroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", 6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (void*)nativeDecodeFileDescriptor 6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }, 6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { "nativeDecodeAsset", 65036bef0bf30d6bae48cf3837df351075ca4fce654Ashok Bhat "(JLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", 6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (void*)nativeDecodeAsset 6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }, 6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { "nativeDecodeByteArray", 6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "([BIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", 6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (void*)nativeDecodeByteArray 6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }, 6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 659a9d0d47076ecf2d1739bb3534abc9deead8ebebdOwen Lin { "nativeIsSeekable", 660a9d0d47076ecf2d1739bb3534abc9deead8ebebdOwen Lin "(Ljava/io/FileDescriptor;)Z", 661a9d0d47076ecf2d1739bb3534abc9deead8ebebdOwen Lin (void*)nativeIsSeekable 662a9d0d47076ecf2d1739bb3534abc9deead8ebebdOwen Lin }, 6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}; 6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint register_android_graphics_BitmapFactory(JNIEnv* env) { 666ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe jclass options_class = FindClassOrDie(env, "android/graphics/BitmapFactory$Options"); 667ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gOptions_bitmapFieldID = GetFieldIDOrDie(env, options_class, "inBitmap", 66847cd8e921db73e894f94ec4729ade90da50996f5Chris Craik "Landroid/graphics/Bitmap;"); 669ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gOptions_justBoundsFieldID = GetFieldIDOrDie(env, options_class, "inJustDecodeBounds", "Z"); 670ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gOptions_sampleSizeFieldID = GetFieldIDOrDie(env, options_class, "inSampleSize", "I"); 671ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gOptions_configFieldID = GetFieldIDOrDie(env, options_class, "inPreferredConfig", 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Landroid/graphics/Bitmap$Config;"); 673ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gOptions_premultipliedFieldID = GetFieldIDOrDie(env, options_class, "inPremultiplied", "Z"); 674ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gOptions_mutableFieldID = GetFieldIDOrDie(env, options_class, "inMutable", "Z"); 675ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gOptions_ditherFieldID = GetFieldIDOrDie(env, options_class, "inDither", "Z"); 676ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gOptions_preferQualityOverSpeedFieldID = GetFieldIDOrDie(env, options_class, 677953f9094a2ec14594fa8501d5f3e2d9e300b1b62Wei-Ta Chen "inPreferQualityOverSpeed", "Z"); 678ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gOptions_scaledFieldID = GetFieldIDOrDie(env, options_class, "inScaled", "Z"); 679ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gOptions_densityFieldID = GetFieldIDOrDie(env, options_class, "inDensity", "I"); 680ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gOptions_screenDensityFieldID = GetFieldIDOrDie(env, options_class, "inScreenDensity", "I"); 681ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gOptions_targetDensityFieldID = GetFieldIDOrDie(env, options_class, "inTargetDensity", "I"); 682ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gOptions_widthFieldID = GetFieldIDOrDie(env, options_class, "outWidth", "I"); 683ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gOptions_heightFieldID = GetFieldIDOrDie(env, options_class, "outHeight", "I"); 684ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gOptions_mimeFieldID = GetFieldIDOrDie(env, options_class, "outMimeType", "Ljava/lang/String;"); 685ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gOptions_mCancelID = GetFieldIDOrDie(env, options_class, "mCancel", "Z"); 686ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe 687ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe jclass bitmap_class = FindClassOrDie(env, "android/graphics/Bitmap"); 688ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gBitmap_ninePatchInsetsFieldID = GetFieldIDOrDie(env, bitmap_class, "mNinePatchInsets", 68947cd8e921db73e894f94ec4729ade90da50996f5Chris Craik "Landroid/graphics/NinePatch$InsetStruct;"); 69047cd8e921db73e894f94ec4729ade90da50996f5Chris Craik 691ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gInsetStruct_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, 692ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe "android/graphics/NinePatch$InsetStruct")); 693ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gInsetStruct_constructorMethodID = GetMethodIDOrDie(env, gInsetStruct_class, "<init>", 694ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe "(IIIIIIIIFIF)V"); 69547cd8e921db73e894f94ec4729ade90da50996f5Chris Craik 696ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe return android::RegisterMethodsOrDie(env, "android/graphics/BitmapFactory", 697ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe gMethods, NELEM(gMethods)); 6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 699