19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#define LOG_TAG "BitmapFactory" 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3f1f48bc7f200f54c76b22d845d8ba8419879b375Joseph Wen#include "BitmapFactory.h" 4a06d86ab8177ee9e631e0ee4e39688bf42179bdeLeon Scroggins#include "NinePatchPeeker.h" 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "SkImageDecoder.h" 6c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed#include "SkImageRef_ashmem.h" 7c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed#include "SkImageRef_GlobalPool.h" 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "SkPixelRef.h" 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "SkStream.h" 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "SkTemplates.h" 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "SkUtils.h" 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "CreateJavaOutputStreamAdaptor.h" 13f1f48bc7f200f54c76b22d845d8ba8419879b375Joseph Wen#include "AutoDecodeCancel.h" 146b849e2123be98eb2a1a25b8abf0b13a279ce952Wei-Ta Chen#include "Utils.h" 15a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes#include "JNIHelp.h" 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <android_runtime/AndroidRuntime.h> 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/Asset.h> 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <utils/ResourceTypes.h> 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <netinet/in.h> 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/mman.h> 222dcfbefbbeac406d16ec379c6430dd9ee9fd23a1Joseph Wen#include <sys/stat.h> 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 24f1f48bc7f200f54c76b22d845d8ba8419879b375Joseph WenjfieldID gOptions_justBoundsFieldID; 25f1f48bc7f200f54c76b22d845d8ba8419879b375Joseph WenjfieldID gOptions_sampleSizeFieldID; 26f1f48bc7f200f54c76b22d845d8ba8419879b375Joseph WenjfieldID gOptions_configFieldID; 272361098da3b9d9c3eeed410dc72ba62c0e9177cfRomain GuyjfieldID gOptions_mutableFieldID; 28f1f48bc7f200f54c76b22d845d8ba8419879b375Joseph WenjfieldID gOptions_ditherFieldID; 29f1f48bc7f200f54c76b22d845d8ba8419879b375Joseph WenjfieldID gOptions_purgeableFieldID; 30f1f48bc7f200f54c76b22d845d8ba8419879b375Joseph WenjfieldID gOptions_shareableFieldID; 31953f9094a2ec14594fa8501d5f3e2d9e300b1b62Wei-Ta ChenjfieldID gOptions_preferQualityOverSpeedFieldID; 32f1f48bc7f200f54c76b22d845d8ba8419879b375Joseph WenjfieldID gOptions_widthFieldID; 33f1f48bc7f200f54c76b22d845d8ba8419879b375Joseph WenjfieldID gOptions_heightFieldID; 34f1f48bc7f200f54c76b22d845d8ba8419879b375Joseph WenjfieldID gOptions_mimeFieldID; 35f1f48bc7f200f54c76b22d845d8ba8419879b375Joseph WenjfieldID gOptions_mCancelID; 3637f74cad46c6f1799aec3c52e8f47598237f43d4Chet HaasejfieldID gOptions_bitmapFieldID; 3737f74cad46c6f1799aec3c52e8f47598237f43d4Chet HaasejfieldID gBitmap_nativeBitmapFieldID; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#if 0 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project #define TRACE_BITMAP(code) code 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#else 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project #define TRACE_BITMAP(code) 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#endif 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectusing namespace android; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic inline int32_t validOrNeg1(bool isValid, int32_t value) { 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// return isValid ? value : -1; 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkASSERT((int)isValid == 0 || (int)isValid == 1); 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ((int32_t)isValid - 1) | value; 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 53f1f48bc7f200f54c76b22d845d8ba8419879b375Joseph Wenjstring getMimeTypeString(JNIEnv* env, SkImageDecoder::Format format) { 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static const struct { 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkImageDecoder::Format fFormat; 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const char* fMimeType; 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } gMimeTypes[] = { 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { SkImageDecoder::kBMP_Format, "image/bmp" }, 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { SkImageDecoder::kGIF_Format, "image/gif" }, 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { SkImageDecoder::kICO_Format, "image/x-ico" }, 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { SkImageDecoder::kJPEG_Format, "image/jpeg" }, 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { SkImageDecoder::kPNG_Format, "image/png" }, 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { SkImageDecoder::kWBMP_Format, "image/vnd.wap.wbmp" } 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 65a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const char* cstr = NULL; 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (size_t i = 0; i < SK_ARRAY_COUNT(gMimeTypes); i++) { 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (gMimeTypes[i].fFormat == format) { 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cstr = gMimeTypes[i].fMimeType; 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jstring jstr = 0; 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (NULL != cstr) { 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jstr = env->NewStringUTF(cstr); 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return jstr; 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 81c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reedstatic bool optionsPurgeable(JNIEnv* env, jobject options) { 82c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed return options != NULL && 83c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed env->GetBooleanField(options, gOptions_purgeableFieldID); 84c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed} 85c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed 86c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reedstatic bool optionsShareable(JNIEnv* env, jobject options) { 87c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed return options != NULL && 88c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed env->GetBooleanField(options, gOptions_shareableFieldID); 89c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed} 90c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed 912a3d754549abc4b55e6cfc2d0c986d29782b2492Bryan Mawhinneystatic bool optionsJustBounds(JNIEnv* env, jobject options) { 922a3d754549abc4b55e6cfc2d0c986d29782b2492Bryan Mawhinney return options != NULL && 932a3d754549abc4b55e6cfc2d0c986d29782b2492Bryan Mawhinney env->GetBooleanField(options, gOptions_justBoundsFieldID); 942a3d754549abc4b55e6cfc2d0c986d29782b2492Bryan Mawhinney} 952a3d754549abc4b55e6cfc2d0c986d29782b2492Bryan Mawhinney 96c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reedstatic SkPixelRef* installPixelRef(SkBitmap* bitmap, SkStream* stream, 9717154417e8ad488d18d9133bf802f598e7506483Mike Reed int sampleSize, bool ditherImage) { 9817154417e8ad488d18d9133bf802f598e7506483Mike Reed SkImageRef* pr; 99c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed // only use ashmem for large images, since mmaps come at a price 1002a2c5cd74128a7750f05683614c9824c9262addcWei-Ta Chen if (bitmap->getSize() >= 32 * 1024) { 101c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed pr = new SkImageRef_ashmem(stream, bitmap->config(), sampleSize); 102c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed } else { 103c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed pr = new SkImageRef_GlobalPool(stream, bitmap->config(), sampleSize); 104c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed } 10517154417e8ad488d18d9133bf802f598e7506483Mike Reed pr->setDitherImage(ditherImage); 106c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed bitmap->setPixelRef(pr)->unref(); 107288471d8a57e1c318742cbfc28697877436fdb87Romain Guy pr->isOpaque(bitmap); 108c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed return pr; 109c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed} 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 111c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed// since we "may" create a purgeable imageref, we require the stream be ref'able 112c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed// i.e. dynamically allocated, since its lifetime may exceed the current stack 113c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed// frame. 114c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reedstatic jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding, 11536ad54acef82f80dbf0ecdd8c44f5764df1be119Mike Reed jobject options, bool allowPurgeable, 11636ad54acef82f80dbf0ecdd8c44f5764df1be119Mike Reed bool forcePurgeable = false) { 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int sampleSize = 1; 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkImageDecoder::Mode mode = SkImageDecoder::kDecodePixels_Mode; 11999b7b7a7f896f8b98e84c4d87e1239541f518f76Romain Guy SkBitmap::Config prefConfig = SkBitmap::kARGB_8888_Config; 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bool doDither = true; 1212361098da3b9d9c3eeed410dc72ba62c0e9177cfRomain Guy bool isMutable = false; 12236ad54acef82f80dbf0ecdd8c44f5764df1be119Mike Reed bool isPurgeable = forcePurgeable || 12336ad54acef82f80dbf0ecdd8c44f5764df1be119Mike Reed (allowPurgeable && optionsPurgeable(env, options)); 124953f9094a2ec14594fa8501d5f3e2d9e300b1b62Wei-Ta Chen bool preferQualityOverSpeed = false; 12537f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase jobject javaBitmap = NULL; 126a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (NULL != options) { 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID); 1292a3d754549abc4b55e6cfc2d0c986d29782b2492Bryan Mawhinney if (optionsJustBounds(env, options)) { 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mode = SkImageDecoder::kDecodeBounds_Mode; 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // initialize these, in case we fail later on 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project env->SetIntField(options, gOptions_widthFieldID, -1); 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project env->SetIntField(options, gOptions_heightFieldID, -1); 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project env->SetObjectField(options, gOptions_mimeFieldID, 0); 136a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jobject jconfig = env->GetObjectField(options, gOptions_configFieldID); 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project prefConfig = GraphicsJNI::getNativeBitmapConfig(env, jconfig); 1392361098da3b9d9c3eeed410dc72ba62c0e9177cfRomain Guy isMutable = env->GetBooleanField(options, gOptions_mutableFieldID); 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project doDither = env->GetBooleanField(options, gOptions_ditherFieldID); 141953f9094a2ec14594fa8501d5f3e2d9e300b1b62Wei-Ta Chen preferQualityOverSpeed = env->GetBooleanField(options, 142953f9094a2ec14594fa8501d5f3e2d9e300b1b62Wei-Ta Chen gOptions_preferQualityOverSpeedFieldID); 14337f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase javaBitmap = env->GetObjectField(options, gOptions_bitmapFieldID); 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkImageDecoder* decoder = SkImageDecoder::Factory(stream); 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (NULL == decoder) { 148c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed return nullObjectReturn("SkImageDecoder::Factory returned null"); 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 150a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project decoder->setSampleSize(sampleSize); 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project decoder->setDitherImage(doDither); 153953f9094a2ec14594fa8501d5f3e2d9e300b1b62Wei-Ta Chen decoder->setPreferQualityOverSpeed(preferQualityOverSpeed); 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15539f10ec7dac59b5a8bc6f7e5b86846da77c30337Mike Reed NinePatchPeeker peeker(decoder); 1562118b25ad422e946d4d87e191c5710bfacd7503eCarl Shapiro JavaPixelAllocator javaAllocator(env); 15737f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase SkBitmap* bitmap; 15837f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase if (javaBitmap == NULL) { 15937f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase bitmap = new SkBitmap; 16037f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase } else { 161decc8cd41eca3770c8f5ee13d81b9cd5f0c25ccdChet Haase if (sampleSize != 1) { 162decc8cd41eca3770c8f5ee13d81b9cd5f0c25ccdChet Haase return nullObjectReturn("SkImageDecoder: Cannot reuse bitmap with sampleSize != 1"); 163decc8cd41eca3770c8f5ee13d81b9cd5f0c25ccdChet Haase } 16437f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase bitmap = (SkBitmap *) env->GetIntField(javaBitmap, gBitmap_nativeBitmapFieldID); 16537f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase // config of supplied bitmap overrules config set in options 16637f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase prefConfig = bitmap->getConfig(); 16737f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase } 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Res_png_9patch dummy9Patch; 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkAutoTDelete<SkImageDecoder> add(decoder); 171decc8cd41eca3770c8f5ee13d81b9cd5f0c25ccdChet Haase SkAutoTDelete<SkBitmap> adb(bitmap, (javaBitmap == NULL)); 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project decoder->setPeeker(&peeker); 174c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed if (!isPurgeable) { 175c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed decoder->setAllocator(&javaAllocator); 176c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed } 177c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project AutoDecoderCancel adc(options, decoder); 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1800a6a0e9e95fffc3b53be92ba617e97fff66d1401Ray Chen // To fix the race condition in case "requestCancelDecode" 1810a6a0e9e95fffc3b53be92ba617e97fff66d1401Ray Chen // happens earlier than AutoDecoderCancel object is added 1820a6a0e9e95fffc3b53be92ba617e97fff66d1401Ray Chen // to the gAutoDecoderCancelMutex linked list. 183c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed if (NULL != options && env->GetBooleanField(options, gOptions_mCancelID)) { 18437f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase return nullObjectReturn("gOptions_mCancelID"); 1850a6a0e9e95fffc3b53be92ba617e97fff66d1401Ray Chen } 1860a6a0e9e95fffc3b53be92ba617e97fff66d1401Ray Chen 187c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed SkImageDecoder::Mode decodeMode = mode; 188c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed if (isPurgeable) { 189c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed decodeMode = SkImageDecoder::kDecodeBounds_Mode; 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19137f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase if (!decoder->decode(stream, bitmap, prefConfig, decodeMode, javaBitmap != NULL)) { 192c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed return nullObjectReturn("decoder->decode returned false"); 193c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed } 194c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // update options (if any) 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (NULL != options) { 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project env->SetIntField(options, gOptions_widthFieldID, bitmap->width()); 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project env->SetIntField(options, gOptions_heightFieldID, bitmap->height()); 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: set the mimeType field with the data from the codec. 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // but how to reuse a set of strings, rather than allocating new one 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // each time? 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project env->SetObjectField(options, gOptions_mimeFieldID, 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getMimeTypeString(env, decoder->getFormat())); 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 205c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // if we're in justBounds mode, return now (skip the java bitmap) 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (SkImageDecoder::kDecodeBounds_Mode == mode) { 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jbyteArray ninePatchChunk = NULL; 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (peeker.fPatchIsValid) { 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project size_t ninePatchArraySize = peeker.fPatch->serializedSize(); 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ninePatchChunk = env->NewByteArray(ninePatchArraySize); 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (NULL == ninePatchChunk) { 216c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed return nullObjectReturn("ninePatchChunk == null"); 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(ninePatchChunk, 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project NULL); 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (NULL == array) { 221c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed return nullObjectReturn("primitive array == null"); 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project peeker.fPatch->serialize(array); 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project env->ReleasePrimitiveArrayCritical(ninePatchChunk, array, 0); 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 227e4ac2d6b5723c95e648c489b187ddde449452c13Patrick Dubroy // detach bitmap from its autodeleter, since we want to own it now 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project adb.detach(); 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (padding) { 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (peeker.fPatchIsValid) { 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project GraphicsJNI::set_jrect(env, padding, 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project peeker.fPatch->paddingLeft, 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project peeker.fPatch->paddingTop, 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project peeker.fPatch->paddingRight, 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project peeker.fPatch->paddingBottom); 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project GraphicsJNI::set_jrect(env, padding, -1, -1, -1, -1); 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 242c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed SkPixelRef* pr; 243c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed if (isPurgeable) { 24417154417e8ad488d18d9133bf802f598e7506483Mike Reed pr = installPixelRef(bitmap, stream, sampleSize, doDither); 245c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed } else { 246c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed // if we get here, we're in kDecodePixels_Mode and will therefore 247c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed // already have a pixelref installed. 248c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed pr = bitmap->pixelRef(); 249c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed } 2502361098da3b9d9c3eeed410dc72ba62c0e9177cfRomain Guy 2512361098da3b9d9c3eeed410dc72ba62c0e9177cfRomain Guy if (!isMutable) { 2522361098da3b9d9c3eeed410dc72ba62c0e9177cfRomain Guy // promise we will never change our pixels (great for sharing and pictures) 2532361098da3b9d9c3eeed410dc72ba62c0e9177cfRomain Guy pr->setImmutable(); 2542361098da3b9d9c3eeed410dc72ba62c0e9177cfRomain Guy } 25537f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase 25637f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase if (javaBitmap != NULL) { 25737f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase // If a java bitmap was passed in for reuse, pass it back 25837f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase return javaBitmap; 25937f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase } 260c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed // now create the java bitmap 2612361098da3b9d9c3eeed410dc72ba62c0e9177cfRomain Guy return GraphicsJNI::createBitmap(env, bitmap, javaAllocator.getStorageObj(), 2622361098da3b9d9c3eeed410dc72ba62c0e9177cfRomain Guy isMutable, ninePatchChunk); 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jobject nativeDecodeStream(JNIEnv* env, jobject clazz, 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jobject is, // InputStream 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jbyteArray storage, // byte[] 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jobject padding, 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jobject options) { // BitmapFactory$Options 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jobject bitmap = NULL; 271f1f48bc7f200f54c76b22d845d8ba8419879b375Joseph Wen SkStream* stream = CreateJavaInputStreamAdaptor(env, is, storage, 0); 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (stream) { 274c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed // for now we don't allow purgeable with java inputstreams 275c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed bitmap = doDecode(env, stream, padding, options, false); 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project stream->unref(); 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return bitmap; 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic ssize_t getFDSize(int fd) { 282ddb76c4644756b31be948d70aaa8ee541dd94999Kenny Root off64_t curr = ::lseek64(fd, 0, SEEK_CUR); 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (curr < 0) { 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project size_t size = ::lseek(fd, 0, SEEK_END); 287ddb76c4644756b31be948d70aaa8ee541dd94999Kenny Root ::lseek64(fd, curr, SEEK_SET); 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return size; 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jobject fileDescriptor, 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jobject padding, 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jobject bitmapFactoryOptions) { 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project NPE_CHECK_RETURN_ZERO(env, fileDescriptor); 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 297a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor); 298c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed 299c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed bool isPurgeable = optionsPurgeable(env, bitmapFactoryOptions); 300c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed bool isShareable = optionsShareable(env, bitmapFactoryOptions); 301c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed bool weOwnTheFD = false; 302c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed if (isPurgeable && isShareable) { 303c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed int newFD = ::dup(descriptor); 304c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed if (-1 != newFD) { 305c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed weOwnTheFD = true; 306c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed descriptor = newFD; 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 310c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed SkFDStream* stream = new SkFDStream(descriptor, weOwnTheFD); 311c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed SkAutoUnref aur(stream); 312c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed if (!stream->isValid()) { 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return NULL; 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 315c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed 316c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed /* Restore our offset when we leave, so we can be called more than once 317c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed with the same descriptor. This is only required if we didn't dup the 318c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed file descriptor, but it is OK to do it all the time. 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project AutoFDSeek as(descriptor); 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3222a2c5cd74128a7750f05683614c9824c9262addcWei-Ta Chen /* Allow purgeable iff we own the FD, i.e., in the puregeable and 3232a2c5cd74128a7750f05683614c9824c9262addcWei-Ta Chen shareable case. 3242a2c5cd74128a7750f05683614c9824c9262addcWei-Ta Chen */ 3252a2c5cd74128a7750f05683614c9824c9262addcWei-Ta Chen return doDecode(env, stream, padding, bitmapFactoryOptions, weOwnTheFD); 326c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed} 327c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed 328c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed/* make a deep copy of the asset, and return it as a stream, or NULL if there 329c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed was an error. 330c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed */ 331c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reedstatic SkStream* copyAssetToStream(Asset* asset) { 332c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed // if we could "ref/reopen" the asset, we may not need to copy it here 333ddb76c4644756b31be948d70aaa8ee541dd94999Kenny Root off64_t size = asset->seek(0, SEEK_SET); 334ddb76c4644756b31be948d70aaa8ee541dd94999Kenny Root if ((off64_t)-1 == size) { 335c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed SkDebugf("---- copyAsset: asset rewind failed\n"); 336c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed return NULL; 337c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed } 338c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed 339c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed size = asset->getLength(); 340c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed if (size <= 0) { 341c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed SkDebugf("---- copyAsset: asset->getLength() returned %d\n", size); 342c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed return NULL; 343c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed } 344c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed 345c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed SkStream* stream = new SkMemoryStream(size); 346c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed void* data = const_cast<void*>(stream->getMemoryBase()); 347ddb76c4644756b31be948d70aaa8ee541dd94999Kenny Root off64_t len = asset->read(data, size); 348c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed if (len != size) { 349c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed SkDebugf("---- copyAsset: asset->read(%d) returned %d\n", size, len); 350c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed delete stream; 351c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed stream = NULL; 352c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed } 353c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed return stream; 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jint native_asset, // Asset 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jobject padding, // Rect 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jobject options) { // BitmapFactory$Options 360c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed SkStream* stream; 361c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed Asset* asset = reinterpret_cast<Asset*>(native_asset); 36218ef37258d897928c68b89535a93b99d8a817d3cRomain Guy bool forcePurgeable = optionsPurgeable(env, options); 36318ef37258d897928c68b89535a93b99d8a817d3cRomain Guy if (forcePurgeable) { 364c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed // if we could "ref/reopen" the asset, we may not need to copy it here 365c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed // and we could assume optionsShareable, since assets are always RO 366c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed stream = copyAssetToStream(asset); 367c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed if (NULL == stream) { 368c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed return NULL; 369c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed } 370c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed } else { 371c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed // since we know we'll be done with the asset when we return, we can 372c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed // just use a simple wrapper 373c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed stream = new AssetStreamAdaptor(asset); 374c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed } 375c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed SkAutoUnref aur(stream); 37636ad54acef82f80dbf0ecdd8c44f5764df1be119Mike Reed return doDecode(env, stream, padding, options, true, forcePurgeable); 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray, 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int offset, int length, jobject options) { 381c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed /* If optionsShareable() we could decide to just wrap the java array and 382c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed share it, but that means adding a globalref to the java array object 383c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed and managing its lifetime. For now we just always copy the array's data 3842a3d754549abc4b55e6cfc2d0c986d29782b2492Bryan Mawhinney if optionsPurgeable(), unless we're just decoding bounds. 385c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed */ 3862a3d754549abc4b55e6cfc2d0c986d29782b2492Bryan Mawhinney bool purgeable = optionsPurgeable(env, options) 3872a3d754549abc4b55e6cfc2d0c986d29782b2492Bryan Mawhinney && !optionsJustBounds(env, options); 388c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed AutoJavaByteArray ar(env, byteArray); 3892a3d754549abc4b55e6cfc2d0c986d29782b2492Bryan Mawhinney SkStream* stream = new SkMemoryStream(ar.ptr() + offset, length, purgeable); 390c70e06bbfac0d92ec218a32e35d9d7fa80f23cc9Mike Reed SkAutoUnref aur(stream); 3912a3d754549abc4b55e6cfc2d0c986d29782b2492Bryan Mawhinney return doDecode(env, stream, NULL, options, purgeable); 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic void nativeRequestCancel(JNIEnv*, jobject joptions) { 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (void)AutoDecoderCancel::RequestCancel(joptions); 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jbyteArray nativeScaleNinePatch(JNIEnv* env, jobject, jbyteArray chunkObject, jfloat scale, 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jobject padding) { 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jbyte* array = env->GetByteArrayElements(chunkObject, 0); 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (array != NULL) { 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project size_t chunkSize = env->GetArrayLength(chunkObject); 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void* storage = alloca(chunkSize); 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project android::Res_png_9patch* chunk = static_cast<android::Res_png_9patch*>(storage); 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project memcpy(chunk, array, chunkSize); 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project android::Res_png_9patch::deserialize(chunk); 4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project chunk->paddingLeft = int(chunk->paddingLeft * scale + 0.5f); 4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project chunk->paddingTop = int(chunk->paddingTop * scale + 0.5f); 4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project chunk->paddingRight = int(chunk->paddingRight * scale + 0.5f); 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project chunk->paddingBottom = int(chunk->paddingBottom * scale + 0.5f); 4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < chunk->numXDivs; i++) { 4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project chunk->xDivs[i] = int(chunk->xDivs[i] * scale + 0.5f); 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (i > 0 && chunk->xDivs[i] == chunk->xDivs[i - 1]) { 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project chunk->xDivs[i]++; 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < chunk->numYDivs; i++) { 422a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes chunk->yDivs[i] = int(chunk->yDivs[i] * scale + 0.5f); 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (i > 0 && chunk->yDivs[i] == chunk->yDivs[i - 1]) { 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project chunk->yDivs[i]++; 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project memcpy(array, chunk, chunkSize); 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (padding) { 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project GraphicsJNI::set_jrect(env, padding, chunk->paddingLeft, chunk->paddingTop, 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project chunk->paddingRight, chunk->paddingBottom); 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project env->ReleaseByteArrayElements(chunkObject, array, 0); 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return chunkObject; 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 440ab4a0c164b5a44d5bfd37069cfe499db31e7620cMike Reedstatic void nativeSetDefaultConfig(JNIEnv* env, jobject, int nativeConfig) { 441ab4a0c164b5a44d5bfd37069cfe499db31e7620cMike Reed SkBitmap::Config config = static_cast<SkBitmap::Config>(nativeConfig); 442ab4a0c164b5a44d5bfd37069cfe499db31e7620cMike Reed 443ab4a0c164b5a44d5bfd37069cfe499db31e7620cMike Reed // these are the only default configs that make sense for codecs right now 444ab4a0c164b5a44d5bfd37069cfe499db31e7620cMike Reed static const SkBitmap::Config gValidDefConfig[] = { 445ab4a0c164b5a44d5bfd37069cfe499db31e7620cMike Reed SkBitmap::kRGB_565_Config, 446ab4a0c164b5a44d5bfd37069cfe499db31e7620cMike Reed SkBitmap::kARGB_8888_Config, 447ab4a0c164b5a44d5bfd37069cfe499db31e7620cMike Reed }; 448ab4a0c164b5a44d5bfd37069cfe499db31e7620cMike Reed 449ab4a0c164b5a44d5bfd37069cfe499db31e7620cMike Reed for (size_t i = 0; i < SK_ARRAY_COUNT(gValidDefConfig); i++) { 450ab4a0c164b5a44d5bfd37069cfe499db31e7620cMike Reed if (config == gValidDefConfig[i]) { 451ab4a0c164b5a44d5bfd37069cfe499db31e7620cMike Reed SkImageDecoder::SetDeviceConfig(config); 452ab4a0c164b5a44d5bfd37069cfe499db31e7620cMike Reed break; 453ab4a0c164b5a44d5bfd37069cfe499db31e7620cMike Reed } 454ab4a0c164b5a44d5bfd37069cfe499db31e7620cMike Reed } 455ab4a0c164b5a44d5bfd37069cfe499db31e7620cMike Reed} 456ab4a0c164b5a44d5bfd37069cfe499db31e7620cMike Reed 457a9d0d47076ecf2d1739bb3534abc9deead8ebebdOwen Linstatic jboolean nativeIsSeekable(JNIEnv* env, jobject, jobject fileDescriptor) { 458a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor); 459a9d0d47076ecf2d1739bb3534abc9deead8ebebdOwen Lin return ::lseek64(descriptor, 0, SEEK_CUR) != -1 ? JNI_TRUE : JNI_FALSE; 460a9d0d47076ecf2d1739bb3534abc9deead8ebebdOwen Lin} 461a9d0d47076ecf2d1739bb3534abc9deead8ebebdOwen Lin 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/////////////////////////////////////////////////////////////////////////////// 4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic JNINativeMethod gMethods[] = { 4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { "nativeDecodeStream", 4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", 4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (void*)nativeDecodeStream 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }, 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { "nativeDecodeFileDescriptor", 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "(Ljava/io/FileDescriptor;Landroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", 4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (void*)nativeDecodeFileDescriptor 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }, 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { "nativeDecodeAsset", 4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "(ILandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", 4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (void*)nativeDecodeAsset 4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }, 4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { "nativeDecodeByteArray", 4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "([BIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (void*)nativeDecodeByteArray 4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }, 4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { "nativeScaleNinePatch", 4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "([BFLandroid/graphics/Rect;)[B", 4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (void*)nativeScaleNinePatch 488ab4a0c164b5a44d5bfd37069cfe499db31e7620cMike Reed }, 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 490ab4a0c164b5a44d5bfd37069cfe499db31e7620cMike Reed { "nativeSetDefaultConfig", "(I)V", (void*)nativeSetDefaultConfig }, 491a9d0d47076ecf2d1739bb3534abc9deead8ebebdOwen Lin 492a9d0d47076ecf2d1739bb3534abc9deead8ebebdOwen Lin { "nativeIsSeekable", 493a9d0d47076ecf2d1739bb3534abc9deead8ebebdOwen Lin "(Ljava/io/FileDescriptor;)Z", 494a9d0d47076ecf2d1739bb3534abc9deead8ebebdOwen Lin (void*)nativeIsSeekable 495a9d0d47076ecf2d1739bb3534abc9deead8ebebdOwen Lin }, 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}; 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic JNINativeMethod gOptionsMethods[] = { 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project { "requestCancel", "()V", (void*)nativeRequestCancel } 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}; 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz, 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project const char fieldname[], const char type[]) { 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jfieldID id = env->GetFieldID(clazz, fieldname, type); 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SkASSERT(id); 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return id; 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectint register_android_graphics_BitmapFactory(JNIEnv* env) { 510a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes jclass options_class = env->FindClass("android/graphics/BitmapFactory$Options"); 511a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes SkASSERT(options_class); 512a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes gOptions_bitmapFieldID = getFieldIDCheck(env, options_class, "inBitmap", 51337f74cad46c6f1799aec3c52e8f47598237f43d4Chet Haase "Landroid/graphics/Bitmap;"); 514a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes gOptions_justBoundsFieldID = getFieldIDCheck(env, options_class, "inJustDecodeBounds", "Z"); 515a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes gOptions_sampleSizeFieldID = getFieldIDCheck(env, options_class, "inSampleSize", "I"); 516a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes gOptions_configFieldID = getFieldIDCheck(env, options_class, "inPreferredConfig", 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Landroid/graphics/Bitmap$Config;"); 518a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes gOptions_mutableFieldID = getFieldIDCheck(env, options_class, "inMutable", "Z"); 519a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes gOptions_ditherFieldID = getFieldIDCheck(env, options_class, "inDither", "Z"); 520a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes gOptions_purgeableFieldID = getFieldIDCheck(env, options_class, "inPurgeable", "Z"); 521a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes gOptions_shareableFieldID = getFieldIDCheck(env, options_class, "inInputShareable", "Z"); 522a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes gOptions_preferQualityOverSpeedFieldID = getFieldIDCheck(env, options_class, 523953f9094a2ec14594fa8501d5f3e2d9e300b1b62Wei-Ta Chen "inPreferQualityOverSpeed", "Z"); 524a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes gOptions_widthFieldID = getFieldIDCheck(env, options_class, "outWidth", "I"); 525a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes gOptions_heightFieldID = getFieldIDCheck(env, options_class, "outHeight", "I"); 526a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes gOptions_mimeFieldID = getFieldIDCheck(env, options_class, "outMimeType", "Ljava/lang/String;"); 527a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes gOptions_mCancelID = getFieldIDCheck(env, options_class, "mCancel", "Z"); 5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 529a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes jclass bitmap_class = env->FindClass("android/graphics/Bitmap"); 530a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes SkASSERT(bitmap_class); 531a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes gBitmap_nativeBitmapFieldID = getFieldIDCheck(env, bitmap_class, "mNativeBitmap", "I"); 5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int ret = AndroidRuntime::registerNativeMethods(env, 5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "android/graphics/BitmapFactory$Options", 5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project gOptionsMethods, 5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SK_ARRAY_COUNT(gOptionsMethods)); 5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ret) { 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ret; 5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 540a3804cf77f0edd93f6247a055cdafb856b117eecElliott Hughes return android::AndroidRuntime::registerNativeMethods(env, "android/graphics/BitmapFactory", 5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project gMethods, SK_ARRAY_COUNT(gMethods)); 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 543