Test region decoding in skimage, plus fixes.

Add tests in skimage to perform region decoding. Write out a
PNG of the region as well as a bitmap obtained with extractSubset
for comparison.

Rename decodeRegion to decodeSubset, so it will not be confused
with SkRegion. (Leave a function called decodeRegion which calls
decodeSubset.)

Clean up some comments.

Use png_set_interlaced_pass instead of modifying pass directly.

Make some changes to region decoding to fix problems I discovered
during testing:

Only call getAddr within a valid range.
Check for a NULL fInputStream.
Return a boolean for whether cropBitmap succeeded.
In cropBitmap, do not attempt to draw to a bitmap to an Index8
bitmap, which crashes. Use extractSubset instead.
Remove an assert.

R=djsollen@google.com

Review URL: https://codereview.chromium.org/14567011

git-svn-id: http://skia.googlecode.com/svn/trunk@8996 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/images/SkImageDecoder.cpp b/src/images/SkImageDecoder.cpp
index de0bc14..9ffae5f 100644
--- a/src/images/SkImageDecoder.cpp
+++ b/src/images/SkImageDecoder.cpp
@@ -33,9 +33,14 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 SkImageDecoder::SkImageDecoder()
-    : fPeeker(NULL), fChooser(NULL), fAllocator(NULL), fSampleSize(1),
-      fDefaultPref(SkBitmap::kNo_Config), fDitherImage(true),
-      fUsePrefTable(false),fPreferQualityOverSpeed(false) {
+    : fPeeker(NULL)
+    , fChooser(NULL)
+    , fAllocator(NULL)
+    , fSampleSize(1)
+    , fDefaultPref(SkBitmap::kNo_Config)
+    , fDitherImage(true)
+    , fUsePrefTable(false)
+    , fPreferQualityOverSpeed(false) {
 }
 
 SkImageDecoder::~SkImageDecoder() {
@@ -177,14 +182,14 @@
     return true;
 }
 
-bool SkImageDecoder::decodeRegion(SkBitmap* bm, const SkIRect& rect,
+bool SkImageDecoder::decodeSubset(SkBitmap* bm, const SkIRect& rect,
                                   SkBitmap::Config pref) {
-    // we reset this to false before calling onDecodeRegion
+    // we reset this to false before calling onDecodeSubset
     fShouldCancelDecode = false;
     // assign this, for use by getPrefConfig(), in case fUsePrefTable is false
     fDefaultPref = pref;
 
-    return this->onDecodeRegion(bm, rect);
+    return this->onDecodeSubset(bm, rect);
 }
 
 bool SkImageDecoder::buildTileIndex(SkStream* stream,
@@ -195,11 +200,25 @@
     return this->onBuildTileIndex(stream, width, height);
 }
 
-void SkImageDecoder::cropBitmap(SkBitmap *dst, SkBitmap *src, int sampleSize,
-                int dstX, int dstY, int width, int height,
-                int srcX, int srcY) {
+bool SkImageDecoder::cropBitmap(SkBitmap *dst, SkBitmap *src, int sampleSize,
+                                int dstX, int dstY, int width, int height,
+                                int srcX, int srcY) {
     int w = width / sampleSize;
     int h = height / sampleSize;
+    if (src->getConfig() == SkBitmap::kIndex8_Config) {
+        // kIndex8 does not allow drawing via an SkCanvas, as is done below.
+        // Instead, use extractSubset. Note that this shares the SkPixelRef and
+        // SkColorTable.
+        // FIXME: Since src is discarded in practice, this holds on to more
+        // pixels than is strictly necessary. Switch to a copy if memory
+        // savings are more important than speed here. This also means
+        // that the pixels in dst can not be reused (though there is no
+        // allocation, which was already done on src).
+        int x = (dstX - srcX) / sampleSize;
+        int y = (dstY - srcY) / sampleSize;
+        SkIRect subset = SkIRect::MakeXYWH(x, y, w, h);
+        return src->extractSubset(dst, subset);
+    }
     // if the destination has no pixels then we must allocate them.
     if (dst->isNull()) {
         dst->setConfig(src->getConfig(), w, h);
@@ -207,13 +226,15 @@
 
         if (!this->allocPixelRef(dst, NULL)) {
             SkDEBUGF(("failed to allocate pixels needed to crop the bitmap"));
-            return;
+            return false;
         }
     }
     // 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(dst->width() >= w && dst->height() >= h);
+    if (dst->width() < w || dst->height() < h) {
+        SkDEBUGF(("SkImageDecoder::cropBitmap does not have a large enough bitmap.\n"));
+    }
 
     // Set the Src_Mode for the paint to prevent transparency issue in the
     // dest in the event that the dest was being re-used.
@@ -224,6 +245,7 @@
     canvas.drawSprite(*src, (srcX - dstX) / sampleSize,
                             (srcY - dstY) / sampleSize,
                             &paint);
+    return true;
 }
 
 ///////////////////////////////////////////////////////////////////////////////