Do not merge.

Backport changes/fixes related to tile-based decoder from Honeycomb to
Gingerbread.

Bug: 3309014

////////////////////////////////////////////////////////////////////
This is a combination of 3 commits.

Fix 3071104, where decodeRegion returned false for some large image.

decodeRegion() returns false when it cannot find a suitable color config
for SkScaledBitmapSampler. Currently SkScaledBitmapSampler does not
support RGB_565. If cinfo->out_color_space is set to RGB_565 and we
require SkScaledBitmapSampler to do the extra sampling, we will fail in
finding a suitable color config for SkScaledBitmapSampler.

To fix it, we add support of RGB_565 into SkSclaedBitmapSampler.

Change-Id: I506f4f8c55518ff356345e616e16c4b4cd0712de

Fix 3117581, where BitmapRegionDecoder fails in building tile index for
PNG files.

The virtual method of building tile index in SkImageDecoder was changed to onBuildTileIndex().
SkPNGImageDecoder needs to override the method.

Change-Id: I7c78844a4d4f7aadff5fa8fa1aa99173317139b2

Add fPreferQualityOverSpeed to SkImageDecoder.

Currently the field only affects JPEG decode, in that when it is set
to true, we choose a more accurate, but slightly slower, IDCT method.

Bug: 3238925
/////////////////////////////////////////////////////////////////////
diff --git a/include/images/SkImageDecoder.h b/include/images/SkImageDecoder.h
index 3bb287d..3c904ca 100644
--- a/include/images/SkImageDecoder.h
+++ b/include/images/SkImageDecoder.h
@@ -75,6 +75,20 @@
     */
     void setDitherImage(bool dither) { fDitherImage = dither; }
 
+    /** Returns true if the decoder should try to decode the
+        resulting image to a higher quality even at the expense of
+        the decoding speed.
+    */
+    bool getPreferQualityOverSpeed() const { return fPreferQualityOverSpeed; }
+
+    /** Set to true if the the decoder should try to decode the
+        resulting image to a higher quality even at the expense of
+        the decoding speed.
+    */
+    void setPreferQualityOverSpeed(bool qualityOverSpeed) {
+        fPreferQualityOverSpeed = qualityOverSpeed;
+    }
+
     /** \class Peeker
 
         Base class for optional callbacks to retrieve meta/chunk data out of
@@ -389,6 +403,7 @@
     bool                    fDitherImage;
     bool                    fUsePrefTable;
     mutable bool            fShouldCancelDecode;
+    bool                    fPreferQualityOverSpeed;
 
     // illegal
     SkImageDecoder(const SkImageDecoder&);
diff --git a/src/images/SkImageDecoder_libjpeg.cpp b/src/images/SkImageDecoder_libjpeg.cpp
index e3aefea..7e425c1 100644
--- a/src/images/SkImageDecoder_libjpeg.cpp
+++ b/src/images/SkImageDecoder_libjpeg.cpp
@@ -236,7 +236,12 @@
     */
     int sampleSize = this->getSampleSize();
 
-    cinfo.dct_method = JDCT_IFAST;
+    if (this->getPreferQualityOverSpeed()) {
+        cinfo.dct_method = JDCT_ISLOW;
+    } else {
+        cinfo.dct_method = JDCT_IFAST;
+    }
+
     cinfo.scale_num = 1;
     cinfo.scale_denom = sampleSize;
 
@@ -264,13 +269,9 @@
     if (config == SkBitmap::kARGB_8888_Config) {
         cinfo.out_color_space = JCS_RGBA_8888;
     } else if (config == SkBitmap::kRGB_565_Config) {
-        if (sampleSize == 1) {
-            // SkScaledBitmapSampler can't handle RGB_565 yet,
-            // so don't even try.
-            cinfo.out_color_space = JCS_RGB_565;
-            if (this->getDitherImage()) {
-                cinfo.dither_mode = JDITHER_ORDERED;
-            }
+        cinfo.out_color_space = JCS_RGB_565;
+        if (this->getDitherImage()) {
+            cinfo.dither_mode = JDITHER_ORDERED;
         }
     }
 #endif
@@ -360,8 +361,8 @@
 #ifdef ANDROID_RGB
     } else if (JCS_RGBA_8888 == cinfo.out_color_space) {
         sc = SkScaledBitmapSampler::kRGBX;
-    //} else if (JCS_RGB_565 == cinfo.out_color_space) {
-    //    sc = SkScaledBitmapSampler::kRGB_565;
+    } else if (JCS_RGB_565 == cinfo.out_color_space) {
+        sc = SkScaledBitmapSampler::kRGB_565;
 #endif
     } else if (1 == cinfo.out_color_components &&
                JCS_GRAYSCALE == cinfo.out_color_space) {
@@ -468,7 +469,6 @@
     index->index = (huffman_index*)malloc(sizeof(huffman_index));
     jpeg_create_huffman_index(cinfo, index->index);
 
-    cinfo->dct_method = JDCT_IFAST;
     cinfo->scale_num = 1;
     cinfo->scale_denom = 1;
     if (!jpeg_build_huffman_index(cinfo, index->index)) {
@@ -497,7 +497,6 @@
     //jpeg_start_decompress(cinfo);
     jpeg_start_tile_decompress(cinfo);
 
-    cinfo->dct_method = JDCT_IFAST;
     cinfo->scale_num = 1;
     index->cinfo = cinfo;
     *height = cinfo->output_height;
@@ -526,24 +525,30 @@
     int requestedSampleSize = this->getSampleSize();
     cinfo->scale_denom = requestedSampleSize;
 
+    if (this->getPreferQualityOverSpeed()) {
+        cinfo->dct_method = JDCT_ISLOW;
+    } else {
+        cinfo->dct_method = JDCT_IFAST;
+    }
+
     SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, false);
     if (config != SkBitmap::kARGB_8888_Config &&
         config != SkBitmap::kARGB_4444_Config &&
         config != SkBitmap::kRGB_565_Config) {
         config = SkBitmap::kARGB_8888_Config;
     }
+
+    /* default format is RGB */
+    cinfo->out_color_space = JCS_RGB;
+
 #ifdef ANDROID_RGB
     cinfo->dither_mode = JDITHER_NONE;
     if (config == SkBitmap::kARGB_8888_Config) {
         cinfo->out_color_space = JCS_RGBA_8888;
     } else if (config == SkBitmap::kRGB_565_Config) {
-        if (requestedSampleSize == 1) {
-            // SkScaledBitmapSampler can't handle RGB_565 yet,
-            // so don't even try.
-            cinfo->out_color_space = JCS_RGB_565;
-            if (this->getDitherImage()) {
-                cinfo->dither_mode = JDITHER_ORDERED;
-            }
+        cinfo->out_color_space = JCS_RGB_565;
+        if (this->getDitherImage()) {
+            cinfo->dither_mode = JDITHER_ORDERED;
         }
     }
 #endif
@@ -606,6 +611,8 @@
 #ifdef ANDROID_RGB
     } else if (JCS_RGBA_8888 == cinfo->out_color_space) {
         sc = SkScaledBitmapSampler::kRGBX;
+    } else if (JCS_RGB_565 == cinfo->out_color_space) {
+        sc = SkScaledBitmapSampler::kRGB_565;
 #endif
     } else if (1 == cinfo->out_color_components &&
                JCS_GRAYSCALE == cinfo->out_color_space) {
diff --git a/src/images/SkImageDecoder_libpng.cpp b/src/images/SkImageDecoder_libpng.cpp
index 2b6a28e..cd240b4 100644
--- a/src/images/SkImageDecoder_libpng.cpp
+++ b/src/images/SkImageDecoder_libpng.cpp
@@ -62,10 +62,10 @@
             delete index;
         }
     }
-    virtual bool buildTileIndex(SkStream *stream,
-             int *width, int *height, bool isShareable);
 
 protected:
+    virtual bool onBuildTileIndex(SkStream *stream,
+             int *width, int *height);
     virtual bool onDecodeRegion(SkBitmap* bitmap, SkIRect rect);
     virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
 
@@ -419,33 +419,13 @@
     return true;
 }
 
-bool SkPNGImageDecoder::buildTileIndex(SkStream* sk_stream,
-                int *width, int *height, bool isShareable) {
+bool SkPNGImageDecoder::onBuildTileIndex(SkStream* sk_stream, int *width,
+        int *height) {
     png_structp png_ptr;
     png_infop   info_ptr;
 
     this->index = new SkPNGImageIndex();
 
-    if (!isShareable) {
-        size_t len, inputLen = 0;
-        size_t bufferSize = 4096;
-        void *tmp = sk_malloc_throw(bufferSize);
-
-        while ((len = sk_stream->read((char*) tmp + inputLen,
-                        bufferSize - inputLen)) != 0) {
-            inputLen += len;
-            if (inputLen == bufferSize) {
-                bufferSize *= 2;
-                tmp = sk_realloc_throw(tmp, bufferSize);
-            }
-        }
-        tmp = sk_realloc_throw(tmp, inputLen);
-
-        SkMemoryStream *mem_stream = new SkMemoryStream(tmp, inputLen, true);
-        this->index->inputStream = mem_stream;
-        sk_stream = mem_stream;
-    }
-
     if (onDecodeInit(sk_stream, &png_ptr, &info_ptr) == false) {
         return false;
     }
diff --git a/src/images/SkScaledBitmapSampler.cpp b/src/images/SkScaledBitmapSampler.cpp
index 3ba38f7..32b78ef 100644
--- a/src/images/SkScaledBitmapSampler.cpp
+++ b/src/images/SkScaledBitmapSampler.cpp
@@ -93,6 +93,18 @@
     return false;
 }
 
+static bool Sample_D565_D565(void* SK_RESTRICT dstRow,
+                             const uint8_t* SK_RESTRICT src,
+                             int width, int deltaSrc, int, const SkPMColor[]) {
+    uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow;
+    uint16_t* SK_RESTRICT castedSrc = (uint16_t*) src;
+    for (int x = 0; x < width; x++) {
+        dst[x] = castedSrc[0];
+        castedSrc += deltaSrc >> 1;
+    }
+    return false;
+}
+
 static bool Sample_RGBx_D565_D(void* SK_RESTRICT dstRow,
                                const uint8_t* SK_RESTRICT src,
                            int width, int deltaSrc, int y, const SkPMColor[]) {
@@ -335,21 +347,25 @@
         Sample_RGBx_D8888,  Sample_RGBx_D8888,
         Sample_RGBA_D8888,  Sample_RGBA_D8888,
         Sample_Index_D8888, Sample_Index_D8888,
+        NULL,               NULL,
         // 565 (no alpha distinction)
         Sample_Gray_D565,   Sample_Gray_D565_D,
         Sample_RGBx_D565,   Sample_RGBx_D565_D,
         Sample_RGBx_D565,   Sample_RGBx_D565_D,
         Sample_Index_D565,  Sample_Index_D565_D,
+        Sample_D565_D565,   Sample_D565_D565,
         // 4444
         Sample_Gray_D4444,  Sample_Gray_D4444_D,
         Sample_RGBx_D4444,  Sample_RGBx_D4444_D,
         Sample_RGBA_D4444,  Sample_RGBA_D4444_D,
         Sample_Index_D4444, Sample_Index_D4444_D,
+        NULL,               NULL,
         // Index8
         NULL,               NULL,
         NULL,               NULL,
         NULL,               NULL,
         Sample_Index_DI,    Sample_Index_DI,
+        NULL,               NULL,
     };
 
     fCTable = ctable;
@@ -379,6 +395,10 @@
             fSrcPixelSize = 1;
             index += 6;
             break;
+        case SkScaledBitmapSampler::kRGB_565:
+            fSrcPixelSize = 2;
+            index += 8;
+            break;
         default:
             return false;
     }
@@ -388,13 +408,13 @@
             index += 0;
             break;
         case SkBitmap::kRGB_565_Config:
-            index += 8;
+            index += 10;
             break;
         case SkBitmap::kARGB_4444_Config:
-            index += 16;
+            index += 20;
             break;
         case SkBitmap::kIndex8_Config:
-            index += 24;
+            index += 30;
             break;
         default:
             return false;
diff --git a/src/images/SkScaledBitmapSampler.h b/src/images/SkScaledBitmapSampler.h
index 84a75ba..43f16694 100644
--- a/src/images/SkScaledBitmapSampler.h
+++ b/src/images/SkScaledBitmapSampler.h
@@ -21,7 +21,8 @@
         kIndex, // 1 byte per pixel
         kRGB,   // 3 bytes per pixel
         kRGBX,  // 4 byes per pixel (ignore 4th)
-        kRGBA   // 4 bytes per pixel
+        kRGBA,  // 4 bytes per pixel
+        kRGB_565 // 2 bytes per pixel
     };
 
     // Given a dst bitmap (with pixels already allocated) and a src-config,