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,