BitmapFactory.cpp revision 2a3d754549abc4b55e6cfc2d0c986d29782b2492
1525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#define LOG_TAG "BitmapFactory" 2525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 3525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include "BitmapFactory.h" 4525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include "SkImageDecoder.h" 5525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include "SkImageRef_ashmem.h" 6525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include "SkImageRef_GlobalPool.h" 7525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include "SkPixelRef.h" 8525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include "SkStream.h" 9525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include "SkTemplates.h" 10525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include "SkUtils.h" 11525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include "CreateJavaOutputStreamAdaptor.h" 12525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include "AutoDecodeCancel.h" 13525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include "Utils.h" 14525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 15525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include <android_runtime/AndroidRuntime.h> 16525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include <utils/Asset.h> 17525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include <utils/ResourceTypes.h> 18525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include <netinet/in.h> 19525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include <sys/mman.h> 2013f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov#include <sys/stat.h> 21525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 2213f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganovjclass gOptions_class; 2313f542cabd635c55ade5442764cc4a3d2f7880eaSvet GanovjfieldID gOptions_justBoundsFieldID; 24525a66b2bb5abf844aff2109bdc9ed819566beceSvet GanovjfieldID gOptions_sampleSizeFieldID; 25525a66b2bb5abf844aff2109bdc9ed819566beceSvet GanovjfieldID gOptions_configFieldID; 26525a66b2bb5abf844aff2109bdc9ed819566beceSvet GanovjfieldID gOptions_ditherFieldID; 2799a82437ed8e0537d9a355a124d2bb30aea46ad8Svet GanovjfieldID gOptions_purgeableFieldID; 28525a66b2bb5abf844aff2109bdc9ed819566beceSvet GanovjfieldID gOptions_shareableFieldID; 2913f542cabd635c55ade5442764cc4a3d2f7880eaSvet GanovjfieldID gOptions_nativeAllocFieldID; 30525a66b2bb5abf844aff2109bdc9ed819566beceSvet GanovjfieldID gOptions_widthFieldID; 3113f542cabd635c55ade5442764cc4a3d2f7880eaSvet GanovjfieldID gOptions_heightFieldID; 3213f542cabd635c55ade5442764cc4a3d2f7880eaSvet GanovjfieldID gOptions_mimeFieldID; 336f249835a4ff9e7e7e3ca0190b7ecf72e689656dSvetoslavjfieldID gOptions_mCancelID; 346f249835a4ff9e7e7e3ca0190b7ecf72e689656dSvetoslav 35525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic jclass gFileDescriptor_class; 36525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic jfieldID gFileDescriptor_descriptor; 37525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 38525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#if 0 3913f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov #define TRACE_BITMAP(code) code 4013f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov#else 4162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav #define TRACE_BITMAP(code) 42df6444931b030d3cdd9769e23f16f0a16fe9c654Svet Ganov#endif 43525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 4413f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganovusing namespace android; 45525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 46525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovclass NinePatchPeeker : public SkImageDecoder::Peeker { 47525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkImageDecoder* fHost; 48525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovpublic: 49525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov NinePatchPeeker(SkImageDecoder* host) { 50525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // the host lives longer than we do, so a raw ptr is safe 51525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov fHost = host; 52525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov fPatchIsValid = false; 53525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 5415cbc8a03250eafdf947cd8ad4e77f34444d5ba4Svetoslav 55525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov ~NinePatchPeeker() { 56525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (fPatchIsValid) { 57525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov free(fPatch); 58525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 59525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 60525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 61525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov bool fPatchIsValid; 62525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov Res_png_9patch* fPatch; 63525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 64525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov virtual bool peek(const char tag[], const void* data, size_t length) { 65525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (strcmp("npTc", tag) == 0 && length >= sizeof(Res_png_9patch)) { 66525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov Res_png_9patch* patch = (Res_png_9patch*) data; 67525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov size_t patchSize = patch->serializedSize(); 68525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov assert(length == patchSize); 69525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // You have to copy the data because it is owned by the png reader 70525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov Res_png_9patch* patchNew = (Res_png_9patch*) malloc(patchSize); 71525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov memcpy(patchNew, patch, patchSize); 72525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // this relies on deserialization being done in place 73525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov Res_png_9patch::deserialize(patchNew); 74525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov patchNew->fileToDevice(); 75525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (fPatchIsValid) { 76525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov free(fPatch); 77525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 78066bf81b983ce23b91d19b85b7c37a61fba7a9a6Philip P. Moltmann fPatch = patchNew; 79525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov //printf("9patch: (%d,%d)-(%d,%d)\n", 80525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // fPatch.sizeLeft, fPatch.sizeTop, 81fce84f035c35606c5707e735f503f7bdcfd5b2a1Svet Ganov // fPatch.sizeRight, fPatch.sizeBottom); 82fce84f035c35606c5707e735f503f7bdcfd5b2a1Svet Ganov fPatchIsValid = true; 83525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 84525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // now update our host to force index or 32bit config 85525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // 'cause we don't want 565 predithered, since as a 9patch, we know 86525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // we will be stretched, and therefore we want to dither afterwards. 87525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov static const SkBitmap::Config gNo565Pref[] = { 88525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkBitmap::kIndex8_Config, 89525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkBitmap::kIndex8_Config, 90fce84f035c35606c5707e735f503f7bdcfd5b2a1Svet Ganov SkBitmap::kARGB_8888_Config, 91525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkBitmap::kARGB_8888_Config, 92525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkBitmap::kARGB_8888_Config, 93525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkBitmap::kARGB_8888_Config, 94525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov }; 95525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov fHost->setPrefConfigTable(gNo565Pref); 96525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } else { 97525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov fPatch = NULL; 98525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 99525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return true; // keep on decoding 100525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 101525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov}; 102525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 103525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov/////////////////////////////////////////////////////////////////////////////// 104525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 105525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic inline int32_t validOrNeg1(bool isValid, int32_t value) { 106525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov// return isValid ? value : -1; 107525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkASSERT((int)isValid == 0 || (int)isValid == 1); 108525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return ((int32_t)isValid - 1) | value; 109c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov} 110c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov 111c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganovjstring getMimeTypeString(JNIEnv* env, SkImageDecoder::Format format) { 112c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov static const struct { 113c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov SkImageDecoder::Format fFormat; 114c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov const char* fMimeType; 115c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov } gMimeTypes[] = { 116c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov { SkImageDecoder::kBMP_Format, "image/bmp" }, 117c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov { SkImageDecoder::kGIF_Format, "image/gif" }, 118c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov { SkImageDecoder::kICO_Format, "image/x-ico" }, 11938fdd4f486fea2a816ca43f365e68118fe747c61Philip P. Moltmann { SkImageDecoder::kJPEG_Format, "image/jpeg" }, 120c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov { SkImageDecoder::kPNG_Format, "image/png" }, 121525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov { SkImageDecoder::kWBMP_Format, "image/vnd.wap.wbmp" } 122525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov }; 123525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 124525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov const char* cstr = NULL; 1254237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov for (size_t i = 0; i < SK_ARRAY_COUNT(gMimeTypes); i++) { 126c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov if (gMimeTypes[i].fFormat == format) { 127c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov cstr = gMimeTypes[i].fMimeType; 128c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov break; 129c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov } 130525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 131525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 132525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov jstring jstr = 0; 133525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (NULL != cstr) { 134525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov jstr = env->NewStringUTF(cstr); 135525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 136525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return jstr; 137525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov} 138254361f136aa9461e16f11f0170fde05e83a1b92Svetoslav 139525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic bool optionsPurgeable(JNIEnv* env, jobject options) { 140525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return options != NULL && 141525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov env->GetBooleanField(options, gOptions_purgeableFieldID); 142525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov} 143525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 144525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic bool optionsShareable(JNIEnv* env, jobject options) { 145525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return options != NULL && 146525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov env->GetBooleanField(options, gOptions_shareableFieldID); 147525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov} 148525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 149525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic bool optionsJustBounds(JNIEnv* env, jobject options) { 150525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return options != NULL && 151525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov env->GetBooleanField(options, gOptions_justBoundsFieldID); 152525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov} 153525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 154525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic bool optionsReportSizeToVM(JNIEnv* env, jobject options) { 155525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return NULL == options || 156525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov !env->GetBooleanField(options, gOptions_nativeAllocFieldID); 157525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov} 1580d2d9637ed4f46062d508cfa7da0e9776fc444f8Svetoslav 159525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 160525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic SkPixelRef* installPixelRef(SkBitmap* bitmap, SkStream* stream, 161525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov int sampleSize, bool ditherImage) { 162525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkImageRef* pr; 163525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // only use ashmem for large images, since mmaps come at a price 164525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (bitmap->getSize() >= 32 * 1024) { 165525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov pr = new SkImageRef_ashmem(stream, bitmap->config(), sampleSize); 166525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } else { 167525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov pr = new SkImageRef_GlobalPool(stream, bitmap->config(), sampleSize); 168525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 169525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov pr->setDitherImage(ditherImage); 170525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov bitmap->setPixelRef(pr)->unref(); 171525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov pr->isOpaque(bitmap); 172525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return pr; 173525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov} 174525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 175525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov// since we "may" create a purgeable imageref, we require the stream be ref'able 176c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov// i.e. dynamically allocated, since its lifetime may exceed the current stack 177525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov// frame. 178525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding, 179525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov jobject options, bool allowPurgeable, 180525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov bool forcePurgeable = false) { 181525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov int sampleSize = 1; 182525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkImageDecoder::Mode mode = SkImageDecoder::kDecodePixels_Mode; 183525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkBitmap::Config prefConfig = SkBitmap::kNo_Config; 184525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov bool doDither = true; 185525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov bool isPurgeable = forcePurgeable || 186525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov (allowPurgeable && optionsPurgeable(env, options)); 187525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov bool reportSizeToVM = optionsReportSizeToVM(env, options); 188525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 189525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (NULL != options) { 190525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID); 191525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (optionsJustBounds(env, options)) { 192525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mode = SkImageDecoder::kDecodeBounds_Mode; 193525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 194525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // initialize these, in case we fail later on 195525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov env->SetIntField(options, gOptions_widthFieldID, -1); 196525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov env->SetIntField(options, gOptions_heightFieldID, -1); 197525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov env->SetObjectField(options, gOptions_mimeFieldID, 0); 198525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 199525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov jobject jconfig = env->GetObjectField(options, gOptions_configFieldID); 200525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov prefConfig = GraphicsJNI::getNativeBitmapConfig(env, jconfig); 201525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov doDither = env->GetBooleanField(options, gOptions_ditherFieldID); 202525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 203525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 204525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkImageDecoder* decoder = SkImageDecoder::Factory(stream); 205525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (NULL == decoder) { 206525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return nullObjectReturn("SkImageDecoder::Factory returned null"); 207525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 208525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 209525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov decoder->setSampleSize(sampleSize); 210525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov decoder->setDitherImage(doDither); 211525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 212525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov NinePatchPeeker peeker(decoder); 213525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov JavaPixelAllocator javaAllocator(env, reportSizeToVM); 214525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkBitmap* bitmap = new SkBitmap; 215525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov Res_png_9patch dummy9Patch; 216525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 217525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkAutoTDelete<SkImageDecoder> add(decoder); 218525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkAutoTDelete<SkBitmap> adb(bitmap); 219525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 220525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov decoder->setPeeker(&peeker); 221525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (!isPurgeable) { 222525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov decoder->setAllocator(&javaAllocator); 223525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 224525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 225525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov AutoDecoderCancel adc(options, decoder); 226525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 227525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // To fix the race condition in case "requestCancelDecode" 228525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // happens earlier than AutoDecoderCancel object is added 229525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // to the gAutoDecoderCancelMutex linked list. 230525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (NULL != options && env->GetBooleanField(options, gOptions_mCancelID)) { 231525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return nullObjectReturn("gOptions_mCancelID");; 232525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 233525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 234525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkImageDecoder::Mode decodeMode = mode; 235525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (isPurgeable) { 236525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov decodeMode = SkImageDecoder::kDecodeBounds_Mode; 237525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 238525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (!decoder->decode(stream, bitmap, prefConfig, decodeMode)) { 239525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return nullObjectReturn("decoder->decode returned false"); 240525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 241525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 242525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // update options (if any) 243525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (NULL != options) { 244525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov env->SetIntField(options, gOptions_widthFieldID, bitmap->width()); 245525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov env->SetIntField(options, gOptions_heightFieldID, bitmap->height()); 246525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // TODO: set the mimeType field with the data from the codec. 247525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // but how to reuse a set of strings, rather than allocating new one 248525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // each time? 249525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov env->SetObjectField(options, gOptions_mimeFieldID, 250525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov getMimeTypeString(env, decoder->getFormat())); 251525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 252525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 253525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // if we're in justBounds mode, return now (skip the java bitmap) 254525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (SkImageDecoder::kDecodeBounds_Mode == mode) { 255525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return NULL; 256525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 257525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 258525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov jbyteArray ninePatchChunk = NULL; 259525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (peeker.fPatchIsValid) { 260525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov size_t ninePatchArraySize = peeker.fPatch->serializedSize(); 261525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov ninePatchChunk = env->NewByteArray(ninePatchArraySize); 262525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (NULL == ninePatchChunk) { 263525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return nullObjectReturn("ninePatchChunk == null"); 264525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 265525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(ninePatchChunk, 266525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov NULL); 267525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (NULL == array) { 268525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return nullObjectReturn("primitive array == null"); 269525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 270525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov peeker.fPatch->serialize(array); 271525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov env->ReleasePrimitiveArrayCritical(ninePatchChunk, array, 0); 272525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 273525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 274525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // detach bitmap from its autotdeleter, since we want to own it now 275525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov adb.detach(); 276525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 277525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (padding) { 278525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (peeker.fPatchIsValid) { 279525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov GraphicsJNI::set_jrect(env, padding, 280525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov peeker.fPatch->paddingLeft, 281525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov peeker.fPatch->paddingTop, 282525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov peeker.fPatch->paddingRight, 283525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov peeker.fPatch->paddingBottom); 284525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } else { 285525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov GraphicsJNI::set_jrect(env, padding, -1, -1, -1, -1); 286525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 287525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 288525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 289525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkPixelRef* pr; 290525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (isPurgeable) { 291525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov pr = installPixelRef(bitmap, stream, sampleSize, doDither); 292525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } else { 293525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // if we get here, we're in kDecodePixels_Mode and will therefore 294525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // already have a pixelref installed. 295525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov pr = bitmap->pixelRef(); 296525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 297525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // promise we will never change our pixels (great for sharing and pictures) 298525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov pr->setImmutable(); 299525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // now create the java bitmap 300525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return GraphicsJNI::createBitmap(env, bitmap, false, ninePatchChunk); 301525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov} 302525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 303525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic jobject nativeDecodeStream(JNIEnv* env, jobject clazz, 304525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov jobject is, // InputStream 305525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov jbyteArray storage, // byte[] 306525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov jobject padding, 307525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov jobject options) { // BitmapFactory$Options 308525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov jobject bitmap = NULL; 309525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkStream* stream = CreateJavaInputStreamAdaptor(env, is, storage, 0); 310525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 311525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (stream) { 312525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // for now we don't allow purgeable with java inputstreams 313525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov bitmap = doDecode(env, stream, padding, options, false); 314525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov stream->unref(); 315525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 316525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return bitmap; 317525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov} 318525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 319525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic ssize_t getFDSize(int fd) { 320525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov off_t curr = ::lseek(fd, 0, SEEK_CUR); 321525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (curr < 0) { 322525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return 0; 323525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 324525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov size_t size = ::lseek(fd, 0, SEEK_END); 325525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov ::lseek(fd, curr, SEEK_SET); 326525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return size; 327525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov} 328525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 329525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, 330525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov jobject fileDescriptor, 331e6ecba59fd618b80dd13f581b625eea420672a0aSvetoslav jobject padding, 332525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov jobject bitmapFactoryOptions) { 333525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov NPE_CHECK_RETURN_ZERO(env, fileDescriptor); 334525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 335525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov jint descriptor = env->GetIntField(fileDescriptor, 336525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov gFileDescriptor_descriptor); 337525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 338525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov bool isPurgeable = optionsPurgeable(env, bitmapFactoryOptions); 339525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov bool isShareable = optionsShareable(env, bitmapFactoryOptions); 3406f249835a4ff9e7e7e3ca0190b7ecf72e689656dSvetoslav bool weOwnTheFD = false; 341525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (isPurgeable && isShareable) { 342525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov int newFD = ::dup(descriptor); 3436f249835a4ff9e7e7e3ca0190b7ecf72e689656dSvetoslav if (-1 != newFD) { 344525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov weOwnTheFD = true; 345525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov descriptor = newFD; 3466f249835a4ff9e7e7e3ca0190b7ecf72e689656dSvetoslav } 3476f249835a4ff9e7e7e3ca0190b7ecf72e689656dSvetoslav } 348525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 349525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkFDStream* stream = new SkFDStream(descriptor, weOwnTheFD); 350525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkAutoUnref aur(stream); 351525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (!stream->isValid()) { 352525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return NULL; 353525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 354525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 355525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov /* Restore our offset when we leave, so we can be called more than once 356525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov with the same descriptor. This is only required if we didn't dup the 357525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov file descriptor, but it is OK to do it all the time. 358525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov */ 359525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov AutoFDSeek as(descriptor); 360525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 361525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov /* Allow purgeable iff we own the FD, i.e., in the puregeable and 362525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov shareable case. 363525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov */ 364525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return doDecode(env, stream, padding, bitmapFactoryOptions, weOwnTheFD); 365525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov} 366525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 367525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov/* make a deep copy of the asset, and return it as a stream, or NULL if there 36813f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov was an error. 36913f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov */ 370525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic SkStream* copyAssetToStream(Asset* asset) { 371525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // if we could "ref/reopen" the asset, we may not need to copy it here 37213f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov off_t size = asset->seek(0, SEEK_SET); 373525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if ((off_t)-1 == size) { 374525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkDebugf("---- copyAsset: asset rewind failed\n"); 375525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return NULL; 376525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 377525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 378525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov size = asset->getLength(); 379525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (size <= 0) { 380525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkDebugf("---- copyAsset: asset->getLength() returned %d\n", size); 381525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return NULL; 382525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 383525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 384525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkStream* stream = new SkMemoryStream(size); 385525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov void* data = const_cast<void*>(stream->getMemoryBase()); 386525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov off_t len = asset->read(data, size); 387525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (len != size) { 38813f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov SkDebugf("---- copyAsset: asset->read(%d) returned %d\n", size, len); 389525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov delete stream; 390525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov stream = NULL; 391525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 392525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return stream; 393525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov} 394525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 395525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, 396525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov jint native_asset, // Asset 397525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov jobject padding, // Rect 398525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov jobject options) { // BitmapFactory$Options 399525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkStream* stream; 400525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov Asset* asset = reinterpret_cast<Asset*>(native_asset); 401525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov bool forcePurgeable = optionsPurgeable(env, options); 402525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (forcePurgeable) { 403525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // if we could "ref/reopen" the asset, we may not need to copy it here 404525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // and we could assume optionsShareable, since assets are always RO 405525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov stream = copyAssetToStream(asset); 406525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (NULL == stream) { 407525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return NULL; 408525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 409525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } else { 410525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // since we know we'll be done with the asset when we return, we can 411525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // just use a simple wrapper 412525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov stream = new AssetStreamAdaptor(asset); 413525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 414525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkAutoUnref aur(stream); 415525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return doDecode(env, stream, padding, options, true, forcePurgeable); 41613f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov} 41713f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov 41813f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganovstatic jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray, 419525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov int offset, int length, jobject options) { 420525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov /* If optionsShareable() we could decide to just wrap the java array and 421525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov share it, but that means adding a globalref to the java array object 422525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov and managing its lifetime. For now we just always copy the array's data 423525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if optionsPurgeable(), unless we're just decoding bounds. 424525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov */ 425525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov bool purgeable = optionsPurgeable(env, options) 426525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov && !optionsJustBounds(env, options); 42713f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov AutoJavaByteArray ar(env, byteArray); 42813f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov SkStream* stream = new SkMemoryStream(ar.ptr() + offset, length, purgeable); 429525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkAutoUnref aur(stream); 430f6cd14dbc99b38af7afe1e5f72347395603d7de2Svet Ganov return doDecode(env, stream, NULL, options, purgeable); 431f6cd14dbc99b38af7afe1e5f72347395603d7de2Svet Ganov} 4329e795e19c7f900fb2636c5dff3ba30098da65f1bSvetoslav 4334237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganovstatic void nativeRequestCancel(JNIEnv*, jobject joptions) { 4349e795e19c7f900fb2636c5dff3ba30098da65f1bSvetoslav (void)AutoDecoderCancel::RequestCancel(joptions); 435fce84f035c35606c5707e735f503f7bdcfd5b2a1Svet Ganov} 436525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 437525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic jbyteArray nativeScaleNinePatch(JNIEnv* env, jobject, jbyteArray chunkObject, jfloat scale, 438525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov jobject padding) { 439525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 440525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov jbyte* array = env->GetByteArrayElements(chunkObject, 0); 441525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (array != NULL) { 442525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov size_t chunkSize = env->GetArrayLength(chunkObject); 443525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov void* storage = alloca(chunkSize); 44413f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov android::Res_png_9patch* chunk = static_cast<android::Res_png_9patch*>(storage); 44513f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov memcpy(chunk, array, chunkSize); 44613f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov android::Res_png_9patch::deserialize(chunk); 44713f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov 44813f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov chunk->paddingLeft = int(chunk->paddingLeft * scale + 0.5f); 44913f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov chunk->paddingTop = int(chunk->paddingTop * scale + 0.5f); 45013f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov chunk->paddingRight = int(chunk->paddingRight * scale + 0.5f); 45113f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov chunk->paddingBottom = int(chunk->paddingBottom * scale + 0.5f); 45213f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov 45313f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov for (int i = 0; i < chunk->numXDivs; i++) { 45413f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov chunk->xDivs[i] = int(chunk->xDivs[i] * scale + 0.5f); 45513f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov if (i > 0 && chunk->xDivs[i] == chunk->xDivs[i - 1]) { 45613f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov chunk->xDivs[i]++; 45713f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov } 45813f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov } 459f6cd14dbc99b38af7afe1e5f72347395603d7de2Svet Ganov 460525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov for (int i = 0; i < chunk->numYDivs; i++) { 461525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov chunk->yDivs[i] = int(chunk->yDivs[i] * scale + 0.5f); 462525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (i > 0 && chunk->yDivs[i] == chunk->yDivs[i - 1]) { 463525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov chunk->yDivs[i]++; 464525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 465525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 466f6cd14dbc99b38af7afe1e5f72347395603d7de2Svet Ganov 467f6cd14dbc99b38af7afe1e5f72347395603d7de2Svet Ganov memcpy(array, chunk, chunkSize); 468525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 469525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (padding) { 470525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov GraphicsJNI::set_jrect(env, padding, chunk->paddingLeft, chunk->paddingTop, 471525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov chunk->paddingRight, chunk->paddingBottom); 472525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 473c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov 474c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov env->ReleaseByteArrayElements(chunkObject, array, 0); 475c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov } 476c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov return chunkObject; 477525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov} 478525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 4794237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganovstatic void nativeSetDefaultConfig(JNIEnv* env, jobject, int nativeConfig) { 4804237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov SkBitmap::Config config = static_cast<SkBitmap::Config>(nativeConfig); 4814237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov 4824237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov // these are the only default configs that make sense for codecs right now 4834237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov static const SkBitmap::Config gValidDefConfig[] = { 4844237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov SkBitmap::kRGB_565_Config, 4854237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov SkBitmap::kARGB_8888_Config, 4864237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov }; 487525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 48813f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov for (size_t i = 0; i < SK_ARRAY_COUNT(gValidDefConfig); i++) { 48913f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov if (config == gValidDefConfig[i]) { 490eaaf0512fcbf03b926cdbbbb7f54df474ecf861aSvet Ganov SkImageDecoder::SetDeviceConfig(config); 491eaaf0512fcbf03b926cdbbbb7f54df474ecf861aSvet Ganov break; 492eaaf0512fcbf03b926cdbbbb7f54df474ecf861aSvet Ganov } 49313f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov } 49413f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov} 49513f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov 49613f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov/////////////////////////////////////////////////////////////////////////////// 497525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 498525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic JNINativeMethod gMethods[] = { 499525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov { "nativeDecodeStream", 500525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov "(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", 501525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov (void*)nativeDecodeStream 502525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov }, 503525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 504525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov { "nativeDecodeFileDescriptor", 505525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov "(Ljava/io/FileDescriptor;Landroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", 506525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov (void*)nativeDecodeFileDescriptor 5077fd5ada98aa9e035682531d9fe25633fdd24a058Svetoslav }, 508525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 509525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov { "nativeDecodeAsset", 5104237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov "(ILandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", 5114237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov (void*)nativeDecodeAsset 5124237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov }, 513172d840cd133969a5d6c9e9657927ffdbcd44093Philip P. Moltmann 514172d840cd133969a5d6c9e9657927ffdbcd44093Philip P. Moltmann { "nativeDecodeByteArray", 515172d840cd133969a5d6c9e9657927ffdbcd44093Philip P. Moltmann "([BIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", 516172d840cd133969a5d6c9e9657927ffdbcd44093Philip P. Moltmann (void*)nativeDecodeByteArray 517172d840cd133969a5d6c9e9657927ffdbcd44093Philip P. Moltmann }, 518172d840cd133969a5d6c9e9657927ffdbcd44093Philip P. Moltmann 5194237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov { "nativeScaleNinePatch", 520f6cd14dbc99b38af7afe1e5f72347395603d7de2Svet Ganov "([BFLandroid/graphics/Rect;)[B", 5214237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov (void*)nativeScaleNinePatch 5224237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov }, 5234237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov 524525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov { "nativeSetDefaultConfig", "(I)V", (void*)nativeSetDefaultConfig }, 525525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov}; 526525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 527525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic JNINativeMethod gOptionsMethods[] = { 528525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov { "requestCancel", "()V", (void*)nativeRequestCancel } 529525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov}; 530525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 531525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic jclass make_globalref(JNIEnv* env, const char classname[]) { 532525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov jclass c = env->FindClass(classname); 533525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkASSERT(c); 534525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return (jclass)env->NewGlobalRef(c); 535525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov} 5361710e0318db5db833974e390eb4bde54ab2f3c62Svetoslav 5371710e0318db5db833974e390eb4bde54ab2f3c62Svetoslavstatic jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz, 538525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov const char fieldname[], const char type[]) { 539525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov jfieldID id = env->GetFieldID(clazz, fieldname, type); 540525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SkASSERT(id); 541525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return id; 542525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov} 543525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 544525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#define kClassPathName "android/graphics/BitmapFactory" 545525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 546525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#define RETURN_ERR_IF_NULL(value) \ 547525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov do { if (!(value)) { assert(0); return -1; } } while (false) 548525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 549525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovint register_android_graphics_BitmapFactory(JNIEnv* env); 550525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovint register_android_graphics_BitmapFactory(JNIEnv* env) { 551525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov gOptions_class = make_globalref(env, "android/graphics/BitmapFactory$Options"); 552525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov gOptions_justBoundsFieldID = getFieldIDCheck(env, gOptions_class, "inJustDecodeBounds", "Z"); 553525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov gOptions_sampleSizeFieldID = getFieldIDCheck(env, gOptions_class, "inSampleSize", "I"); 554525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov gOptions_configFieldID = getFieldIDCheck(env, gOptions_class, "inPreferredConfig", 555525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov "Landroid/graphics/Bitmap$Config;"); 556525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov gOptions_ditherFieldID = getFieldIDCheck(env, gOptions_class, "inDither", "Z"); 557525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov gOptions_purgeableFieldID = getFieldIDCheck(env, gOptions_class, "inPurgeable", "Z"); 558525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov gOptions_shareableFieldID = getFieldIDCheck(env, gOptions_class, "inInputShareable", "Z"); 559525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov gOptions_nativeAllocFieldID = getFieldIDCheck(env, gOptions_class, "inNativeAlloc", "Z"); 560525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov gOptions_widthFieldID = getFieldIDCheck(env, gOptions_class, "outWidth", "I"); 561525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov gOptions_heightFieldID = getFieldIDCheck(env, gOptions_class, "outHeight", "I"); 562525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov gOptions_mimeFieldID = getFieldIDCheck(env, gOptions_class, "outMimeType", "Ljava/lang/String;"); 563525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov gOptions_mCancelID = getFieldIDCheck(env, gOptions_class, "mCancel", "Z"); 564525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 565525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov gFileDescriptor_class = make_globalref(env, "java/io/FileDescriptor"); 566525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov gFileDescriptor_descriptor = getFieldIDCheck(env, gFileDescriptor_class, "descriptor", "I"); 567525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 568525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov int ret = AndroidRuntime::registerNativeMethods(env, 569525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov "android/graphics/BitmapFactory$Options", 570525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov gOptionsMethods, 571525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov SK_ARRAY_COUNT(gOptionsMethods)); 572525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (ret) { 573525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return ret; 574525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 575525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return android::AndroidRuntime::registerNativeMethods(env, kClassPathName, 576525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov gMethods, SK_ARRAY_COUNT(gMethods)); 577525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov} 578525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov