Reconcile with jb-release nakasi-factoryrom-release
Change-Id: Ica7c000a9aa45215dbefec538d8221d9d8134236
diff --git a/src/images/SkImageDecoder.cpp b/src/images/SkImageDecoder.cpp
index de0afbb..c4eac9c 100644
--- a/src/images/SkImageDecoder.cpp
+++ b/src/images/SkImageDecoder.cpp
@@ -171,19 +171,14 @@
bool SkImageDecoder::decodeRegion(SkBitmap* bm, SkIRect rect,
SkBitmap::Config pref) {
- // pass a temporary bitmap, so that if we return false, we are assured of
- // leaving the caller's bitmap untouched.
- SkBitmap tmp;
-
// we reset this to false before calling onDecodeRegion
fShouldCancelDecode = false;
// assign this, for use by getPrefConfig(), in case fUsePrefTable is false
fDefaultPref = pref;
- if (!this->onDecodeRegion(&tmp, rect)) {
+ if (!this->onDecodeRegion(bm, rect)) {
return false;
}
- bm->swap(tmp);
return true;
}
@@ -200,25 +195,30 @@
int width, int height, int srcX, int srcY) {
int w = width / sampleSize;
int h = height / sampleSize;
- if (w == src->width() && h == src->height() &&
- (srcX - destX) / sampleSize == 0 && (srcY - destY) / sampleSize == 0) {
- // The output rect is the same as the decode result
- dest->swap(*src);
- return;
- }
- dest->setConfig(src->getConfig(), w, h);
- dest->setIsOpaque(src->isOpaque());
+ // if the destination has no pixels then we must allocate them.
+ if (dest->isNull()) {
+ dest->setConfig(src->getConfig(), w, h);
+ dest->setIsOpaque(src->isOpaque());
- if (!this->allocPixelRef(dest, NULL)) {
-#ifdef SK_DEBUG
- SkDebugf("failed to allocate pixels needed to crop the bitmap");
-#endif
- return;
+ if (!this->allocPixelRef(dest, NULL)) {
+ SkDEBUGF(("failed to allocate pixels needed to crop the bitmap"));
+ return;
+ }
}
+ // check to see if the destination is large enough to decode the desired
+ // region. If this assert fails we will just draw as much of the source
+ // into the destination that we can.
+ SkASSERT(dest->width() >= w && dest->height() >= h);
+
+ // Set the Src_Mode for the paint to prevent transparency issue in the
+ // dest in the event that the dest was being re-used.
+ SkPaint paint;
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
SkCanvas canvas(*dest);
- canvas.drawBitmap(*src, (srcX - destX) / sampleSize,
- (srcY - destY) / sampleSize);
+ canvas.drawSprite(*src, (srcX - destX) / sampleSize,
+ (srcY - destY) / sampleSize,
+ &paint);
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/images/SkImageDecoder_libjpeg.cpp b/src/images/SkImageDecoder_libjpeg.cpp
index 8d87450..fbb6887 100644
--- a/src/images/SkImageDecoder_libjpeg.cpp
+++ b/src/images/SkImageDecoder_libjpeg.cpp
@@ -77,6 +77,8 @@
virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
private:
SkJPEGImageIndex *index;
+ int imageWidth;
+ int imageHeight;
};
//////////////////////////////////////////////////////////////////////////
@@ -528,7 +530,8 @@
index->cinfo = cinfo;
*height = cinfo->output_height;
*width = cinfo->output_width;
-
+ this->imageWidth = *width;
+ this->imageHeight = *height;
this->index = index;
return true;
}
@@ -537,11 +540,14 @@
if (index == NULL) {
return false;
}
- int startX = region.fLeft;
- int startY = region.fTop;
- int width = region.width();
- int height = region.height();
jpeg_decompress_struct *cinfo = index->cinfo;
+
+ SkIRect rect = SkIRect::MakeWH(this->imageWidth, this->imageHeight);
+ if (!rect.intersect(region)) {
+ // If the requested region is entirely outsides the image, just
+ // returns false
+ return false;
+ }
SkAutoMalloc srcStorage;
skjpeg_error_mgr sk_err;
cinfo->err = jpeg_std_error(&sk_err);
@@ -579,11 +585,11 @@
}
}
#endif
+ int startX = rect.fLeft;
+ int startY = rect.fTop;
+ int width = rect.width();
+ int height = rect.height();
- int oriStartX = startX;
- int oriStartY = startY;
- int oriWidth = width;
- int oriHeight = height;
jpeg_init_read_tile_scanline(cinfo, index->index,
&startX, &startY, &width, &height);
int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo);
@@ -604,9 +610,30 @@
{
bitmap->setConfig(config, cinfo->output_width, height);
bitmap->setIsOpaque(true);
- if (!this->allocPixelRef(bitmap, NULL)) {
- return return_false(*cinfo, *bitmap, "allocPixelRef");
+
+ // Check ahead of time if the swap(dest, src) is possible or not.
+ // If yes, then we will stick to AllocPixelRef since it's cheaper
+ // with the swap happening. If no, then we will use alloc to allocate
+ // pixels to prevent garbage collection.
+ //
+ // Not using a recycled-bitmap and the output rect is same as the
+ // decoded region.
+ int w = rect.width() / actualSampleSize;
+ int h = rect.height() / actualSampleSize;
+ bool swapOnly = (rect == region) && bm->isNull() &&
+ (w == bitmap->width()) && (h == bitmap->height()) &&
+ ((startX - rect.x()) / actualSampleSize == 0) &&
+ ((startY - rect.y()) / actualSampleSize == 0);
+ if (swapOnly) {
+ if (!this->allocPixelRef(bitmap, NULL)) {
+ return return_false(*cinfo, *bitmap, "allocPixelRef");
+ }
+ } else {
+ if (!bitmap->allocPixels()) {
+ return return_false(*cinfo, *bitmap, "allocPixels");
+ }
}
+
SkAutoLockPixels alp(*bitmap);
JSAMPLE* rowptr = (JSAMPLE*)bitmap->getPixels();
INT32 const bpr = bitmap->rowBytes();
@@ -626,8 +653,13 @@
row_total_count += row_count;
rowptr += bpr;
}
- cropBitmap(bm, bitmap, actualSampleSize, oriStartX, oriStartY,
- oriWidth, oriHeight, startX, startY);
+
+ if (swapOnly) {
+ bm->swap(*bitmap);
+ } else {
+ cropBitmap(bm, bitmap, actualSampleSize, region.x(), region.y(),
+ region.width(), region.height(), startX, startY);
+ }
return true;
}
#endif
@@ -653,8 +685,24 @@
bitmap->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
bitmap->setIsOpaque(true);
- if (!this->allocPixelRef(bitmap, NULL)) {
- return return_false(*cinfo, *bitmap, "allocPixelRef");
+ // Check ahead of time if the swap(dest, src) is possible or not.
+ // If yes, then we will stick to AllocPixelRef since it's cheaper with the
+ // swap happening. If no, then we will use alloc to allocate pixels to
+ // prevent garbage collection.
+ int w = rect.width() / actualSampleSize;
+ int h = rect.height() / actualSampleSize;
+ bool swapOnly = (rect == region) && bm->isNull() &&
+ (w == bitmap->width()) && (h == bitmap->height()) &&
+ ((startX - rect.x()) / actualSampleSize == 0) &&
+ ((startY - rect.y()) / actualSampleSize == 0);
+ if (swapOnly) {
+ if (!this->allocPixelRef(bitmap, NULL)) {
+ return return_false(*cinfo, *bitmap, "allocPixelRef");
+ }
+ } else {
+ if (!bitmap->allocPixels()) {
+ return return_false(*cinfo, *bitmap, "allocPixels");
+ }
}
SkAutoLockPixels alp(*bitmap);
@@ -691,8 +739,12 @@
return return_false(*cinfo, *bitmap, "skip rows");
}
}
- cropBitmap(bm, bitmap, actualSampleSize, oriStartX, oriStartY,
- oriWidth, oriHeight, startX, startY);
+ if (swapOnly) {
+ bm->swap(*bitmap);
+ } else {
+ cropBitmap(bm, bitmap, actualSampleSize, region.x(), region.y(),
+ region.width(), region.height(), startX, startY);
+ }
return true;
}
diff --git a/src/images/SkImageDecoder_libpng.cpp b/src/images/SkImageDecoder_libpng.cpp
index 138c28c..fa35239 100644
--- a/src/images/SkImageDecoder_libpng.cpp
+++ b/src/images/SkImageDecoder_libpng.cpp
@@ -58,7 +58,7 @@
protected:
virtual bool onBuildTileIndex(SkStream *stream,
int *width, int *height);
- virtual bool onDecodeRegion(SkBitmap* bitmap, SkIRect rect);
+ virtual bool onDecodeRegion(SkBitmap* bitmap, SkIRect region);
virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
private:
@@ -616,7 +616,7 @@
return true;
}
-bool SkPNGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect rect) {
+bool SkPNGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect region) {
int i;
png_structp png_ptr = this->index->png_ptr;
png_infop info_ptr = this->index->info_ptr;
@@ -624,14 +624,19 @@
return false;
}
- int requestedHeight = rect.fBottom - rect.fTop;
- int requestedWidth = rect.fRight - rect.fLeft;
-
png_uint_32 origWidth, origHeight;
int bit_depth, color_type, interlace_type;
png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth,
&color_type, &interlace_type, int_p_NULL, int_p_NULL);
+ SkIRect rect = SkIRect::MakeWH(origWidth, origHeight);
+
+ if (!rect.intersect(region)) {
+ // If the requested region is entirely outsides the image, just
+ // returns false
+ return false;
+ }
+
SkBitmap::Config config;
bool hasAlpha = false;
bool doDither = this->getDitherImage();
@@ -643,7 +648,7 @@
}
const int sampleSize = this->getSampleSize();
- SkScaledBitmapSampler sampler(origWidth, requestedHeight, sampleSize);
+ SkScaledBitmapSampler sampler(origWidth, rect.height(), sampleSize);
SkBitmap *decodedBitmap = new SkBitmap;
SkAutoTDelete<SkBitmap> adb(decodedBitmap);
@@ -666,12 +671,25 @@
SkAutoUnref aur(colorTable);
- if (!this->allocPixelRef(decodedBitmap,
- SkBitmap::kIndex8_Config == config ?
- colorTable : NULL)) {
- return false;
+ // Check ahead of time if the swap(dest, src) is possible in crop or not.
+ // If yes, then we will stick to AllocPixelRef since it's cheaper with the swap happening.
+ // If no, then we will use alloc to allocate pixels to prevent garbage collection.
+ int w = rect.width() / sampleSize;
+ int h = rect.height() / sampleSize;
+ bool swapOnly = (rect == region) && (w == decodedBitmap->width()) &&
+ (h == decodedBitmap->height()) &&
+ ((0 - rect.x()) / sampleSize == 0) && bm->isNull();
+ if (swapOnly) {
+ if (!this->allocPixelRef(decodedBitmap,
+ SkBitmap::kIndex8_Config == config ? colorTable : NULL)) {
+ return false;
+ }
+ } else {
+ if (!decodedBitmap->allocPixels(
+ NULL, SkBitmap::kIndex8_Config == config ? colorTable : NULL)) {
+ return false;
+ }
}
-
SkAutoLockPixels alp(*decodedBitmap);
/* Add filler (or alpha) byte (before/after each RGB triplet) */
@@ -693,8 +711,6 @@
png_ptr->pass = 0;
png_read_update_info(png_ptr, info_ptr);
- // SkDebugf("Request size %d %d\n", requestedWidth, requestedHeight);
-
int actualTop = rect.fTop;
if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) {
@@ -744,7 +760,7 @@
png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
}
uint8_t* row = base;
- for (png_uint_32 y = 0; y < requestedHeight; y++) {
+ for (png_uint_32 y = 0; y < rect.height(); y++) {
uint8_t* bmRow = row;
png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
row += rb;
@@ -777,8 +793,12 @@
}
}
}
- cropBitmap(bm, decodedBitmap, sampleSize, rect.fLeft, rect.fTop,
- requestedWidth, requestedHeight, 0, rect.fTop);
+ if (swapOnly) {
+ bm->swap(*decodedBitmap);
+ } else {
+ cropBitmap(bm, decodedBitmap, sampleSize, region.x(), region.y(),
+ region.width(), region.height(), 0, rect.y());
+ }
if (0 != theTranspColor) {
reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor);
diff --git a/src/images/SkImageDecoder_libwebp.cpp b/src/images/SkImageDecoder_libwebp.cpp
index c2fce45..3e416cc 100644
--- a/src/images/SkImageDecoder_libwebp.cpp
+++ b/src/images/SkImageDecoder_libwebp.cpp
@@ -21,6 +21,7 @@
#include "SkStream.h"
#include "SkTemplates.h"
#include "SkUtils.h"
+#include "SkTScopedPtr.h"
// A WebP decoder only, on top of (subset of) libwebp
// For more information on WebP image format, and libwebp library, see:
@@ -151,7 +152,7 @@
// Incremental WebP image decoding. Reads input buffer of 64K size iteratively
// and decodes this block to appropriate color-space as per config object.
static bool webp_idecode(SkStream* stream, WebPDecoderConfig& config) {
- WebPIDecoder* idec = WebPIDecode(NULL, NULL, &config);
+ WebPIDecoder* idec = WebPIDecode(NULL, 0, &config);
if (idec == NULL) {
WebPFreeDecBuffer(&config.output);
return false;
@@ -309,33 +310,82 @@
return true;
}
+static bool isConfigCompatiable(SkBitmap* bitmap) {
+ SkBitmap::Config config = bitmap->config();
+ return config == SkBitmap::kARGB_4444_Config ||
+ config == SkBitmap::kRGB_565_Config ||
+ config == SkBitmap::kARGB_8888_Config;
+}
+
bool SkWEBPImageDecoder::onDecodeRegion(SkBitmap* decodedBitmap,
SkIRect region) {
- const int width = region.width();
- const int height = region.height();
+ SkIRect rect = SkIRect::MakeWH(origWidth, origHeight);
- const int sampleSize = this->getSampleSize();
- SkScaledBitmapSampler sampler(width, height, sampleSize);
-
- if (!setDecodeConfig(decodedBitmap, sampler.scaledWidth(),
- sampler.scaledHeight())) {
+ if (!rect.intersect(region)) {
+ // If the requested region is entirely outsides the image, just
+ // returns false
return false;
}
- if (!this->allocPixelRef(decodedBitmap, NULL)) {
- return return_false(*decodedBitmap, "allocPixelRef");
+ const int sampleSize = this->getSampleSize();
+ SkScaledBitmapSampler sampler(rect.width(), rect.height(), sampleSize);
+ const int width = sampler.scaledWidth();
+ const int height = sampler.scaledHeight();
+
+ // The image can be decoded directly to decodedBitmap if
+ // 1. the region is within the image range
+ // 2. bitmap's config is compatible
+ // 3. bitmap's size is same as the required region (after sampled)
+ bool directDecode = (rect == region) &&
+ (decodedBitmap->isNull() ||
+ isConfigCompatiable(decodedBitmap) &&
+ (decodedBitmap->width() == width) &&
+ (decodedBitmap->height() == height));
+ SkTScopedPtr<SkBitmap> adb;
+ SkBitmap *bitmap = decodedBitmap;
+
+ if (!directDecode) {
+ // allocates a temp bitmap
+ bitmap = new SkBitmap;
+ adb.reset(bitmap);
}
- SkAutoLockPixels alp(*decodedBitmap);
+ if (bitmap->isNull()) {
+ if (!setDecodeConfig(bitmap, width, height)) {
+ return false;
+ }
+ // alloc from native heap if it is a temp bitmap. (prevent GC)
+ bool allocResult = (bitmap == decodedBitmap)
+ ? allocPixelRef(bitmap, NULL)
+ : bitmap->allocPixels();
+ if (!allocResult) {
+ return return_false(*decodedBitmap, "allocPixelRef");
+ }
+ } else {
+ // This is also called in setDecodeConfig in above block.
+ // i.e., when bitmap->isNull() is true.
+ if (!chooseFromOneChoice(bitmap->config(), width, height)) {
+ return false;
+ }
+ }
+ SkAutoLockPixels alp(*bitmap);
WebPDecoderConfig config;
- if (!webp_get_config_resize_crop(config, decodedBitmap, region)) {
+ if (!webp_get_config_resize_crop(config, bitmap, rect)) {
return false;
}
// Decode the WebP image data stream using WebP incremental decoding for
// the specified cropped image-region.
- return webp_idecode(this->inputStream, config);
+ if (!webp_idecode(this->inputStream, config)) {
+ return false;
+ }
+
+ if (!directDecode) {
+ cropBitmap(decodedBitmap, bitmap, sampleSize, region.x(), region.y(),
+ region.width(), region.height(), rect.x(), rect.y());
+ }
+ return true;
}
bool SkWEBPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap,