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