am 9bc988da: Merge "Fix assembly code for clang"

* commit '9bc988dadc2fb0a129e085882a09e8a370cba680':
  Fix assembly code for clang
diff --git a/include/core/SkImageDecoder.h b/include/core/SkImageDecoder.h
index 200c6bc..16c5a58 100644
--- a/include/core/SkImageDecoder.h
+++ b/include/core/SkImageDecoder.h
@@ -247,13 +247,26 @@
         kDecodePixels_Mode  //!< return entire bitmap (including pixels)
     };
 
+    /** Result of a decode. If read as a boolean, a partial success is
+        considered a success (true).
+    */
+    enum Result {
+        kFailure        = 0,    //!< Image failed to decode. bitmap will be
+                                //   unchanged.
+        kPartialSuccess = 1,    //!< Part of the image decoded. The rest is
+                                //   filled in automatically
+        kSuccess        = 2     //!< The entire image was decoded, if Mode is
+                                //   kDecodePixels_Mode, or the bounds were
+                                //   decoded, in kDecodeBounds_Mode.
+    };
+
     /** Given a stream, decode it into the specified bitmap.
         If the decoder can decompress the image, it calls bitmap.setInfo(),
         and then if the Mode is kDecodePixels_Mode, call allocPixelRef(),
         which will allocated a pixelRef. To access the pixel memory, the codec
         needs to call lockPixels/unlockPixels on the
         bitmap. It can then set the pixels with the decompressed image.
-    *   If the image cannot be decompressed, return false. After the
+    *   If the image cannot be decompressed, return kFailure. After the
     *   decoding, the function converts the decoded colortype in bitmap
     *   to pref if possible. Whether a conversion is feasible is
     *   tested by Bitmap::canCopyTo(pref).
@@ -266,8 +279,8 @@
         If a Peeker is installed via setPeeker, it may be used to peek into
         meta data during the decode.
     */
-    bool decode(SkStream*, SkBitmap* bitmap, SkColorType pref, Mode);
-    bool decode(SkStream* stream, SkBitmap* bitmap, Mode mode) {
+    Result decode(SkStream*, SkBitmap* bitmap, SkColorType pref, Mode);
+    Result decode(SkStream* stream, SkBitmap* bitmap, Mode mode) {
         return this->decode(stream, bitmap, kUnknown_SkColorType, mode);
     }
 
@@ -377,7 +390,7 @@
 
 protected:
     // must be overridden in subclasses. This guy is called by decode(...)
-    virtual bool onDecode(SkStream*, SkBitmap* bitmap, Mode) = 0;
+    virtual Result onDecode(SkStream*, SkBitmap* bitmap, Mode) = 0;
 
     // If the decoder wants to support tiled based decoding,
     // this method must be overridden. This guy is called by buildTileIndex(...)
diff --git a/include/core/SkPixelRef.h b/include/core/SkPixelRef.h
index 7f9fd2c..3252a2b 100644
--- a/include/core/SkPixelRef.h
+++ b/include/core/SkPixelRef.h
@@ -126,6 +126,17 @@
     */
     uint32_t getGenerationID() const;
 
+#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
+    /** Returns a non-zero, unique value corresponding to this SkPixelRef,
+        which is unchanged when the pixels are changed and even when this
+        object is deleted.
+
+        Can be used as a key which must remain unique across changes and
+        deletions.
+     */
+    uint32_t getStableID() const { return fStableID; }
+#endif
+
     /**
      *  Call this if you have changed the contents of the pixels. This will in-
      *  turn cause a different generation ID value to be returned from
@@ -343,6 +354,9 @@
 
     mutable uint32_t fGenerationID;
     mutable bool     fUniqueGenerationID;
+#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
+    const uint32_t fStableID;
+#endif
 
     SkTDArray<GenIDChangeListener*> fGenIDChangeListeners;  // pointers are owned
 
diff --git a/src/core/SkColorTable.cpp b/src/core/SkColorTable.cpp
index b8e7b05..0920a87 100644
--- a/src/core/SkColorTable.cpp
+++ b/src/core/SkColorTable.cpp
@@ -73,7 +73,10 @@
 }
 
 const uint16_t* SkColorTable::lock16BitCache() {
-    if (this->isOpaque() && NULL == f16BitCache) {
+    // Assert that we're opaque, since our 16-bit cache will be sort of useless
+    // if there is alpha (which we're throwing away)
+    SkASSERT(this->isOpaque());
+    if (NULL == f16BitCache) {
         f16BitCache = (uint16_t*)sk_malloc_throw(fCount * sizeof(uint16_t));
         build_16bitcache(f16BitCache, fColors, fCount);
     }
diff --git a/src/core/SkPixelRef.cpp b/src/core/SkPixelRef.cpp
index bfa4ae2..420d32e 100644
--- a/src/core/SkPixelRef.cpp
+++ b/src/core/SkPixelRef.cpp
@@ -83,7 +83,12 @@
 // just need a > 0 value, so pick a funny one to aid in debugging
 #define SKPIXELREF_PRELOCKED_LOCKCOUNT     123456789
 
-SkPixelRef::SkPixelRef(const SkImageInfo& info) : fInfo(info) {
+SkPixelRef::SkPixelRef(const SkImageInfo& info)
+        : fInfo(info)
+#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
+        , fStableID(SkNextPixelRefGenerationID())
+#endif
+{
     this->setMutex(NULL);
     fRec.zero();
     fLockCount = 0;
@@ -93,7 +98,12 @@
 }
 
 
-SkPixelRef::SkPixelRef(const SkImageInfo& info, SkBaseMutex* mutex) : fInfo(info) {
+SkPixelRef::SkPixelRef(const SkImageInfo& info, SkBaseMutex* mutex)
+        : fInfo(info)
+#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
+        , fStableID(SkNextPixelRefGenerationID())
+#endif
+{
     this->setMutex(mutex);
     fRec.zero();
     fLockCount = 0;
@@ -111,6 +121,9 @@
 SkPixelRef::SkPixelRef(SkReadBuffer& buffer, SkBaseMutex* mutex)
         : INHERITED(buffer)
         , fInfo(read_info(buffer))
+#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
+        , fStableID(SkNextPixelRefGenerationID())
+#endif
 {
     this->setMutex(mutex);
     fRec.zero();
diff --git a/src/images/SkImageDecoder.cpp b/src/images/SkImageDecoder.cpp
index fe61906..b965f42 100644
--- a/src/images/SkImageDecoder.cpp
+++ b/src/images/SkImageDecoder.cpp
@@ -180,7 +180,8 @@
     return ct;
 }
 
-bool SkImageDecoder::decode(SkStream* stream, SkBitmap* bm, SkColorType pref, Mode mode) {
+SkImageDecoder::Result SkImageDecoder::decode(SkStream* stream, SkBitmap* bm, SkColorType pref,
+                                              Mode mode) {
     // we reset this to false before calling onDecode
     fShouldCancelDecode = false;
     // assign this, for use by getPrefColorType(), in case fUsePrefTable is false
@@ -188,12 +189,12 @@
 
     // pass a temporary bitmap, so that if we return false, we are assured of
     // leaving the caller's bitmap untouched.
-    SkBitmap    tmp;
-    if (!this->onDecode(stream, &tmp, mode)) {
-        return false;
+    SkBitmap tmp;
+    const Result result = this->onDecode(stream, &tmp, mode);
+    if (kFailure != result) {
+        bm->swap(tmp);
     }
-    bm->swap(tmp);
-    return true;
+    return result;
 }
 
 bool SkImageDecoder::decodeSubset(SkBitmap* bm, const SkIRect& rect, SkColorType pref) {
diff --git a/src/images/SkImageDecoder_ktx.cpp b/src/images/SkImageDecoder_ktx.cpp
index effc1ed..31c43d3 100644
--- a/src/images/SkImageDecoder_ktx.cpp
+++ b/src/images/SkImageDecoder_ktx.cpp
@@ -41,22 +41,22 @@
     }
 
 protected:
-    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
+    virtual Result onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
 
 private:
     typedef SkImageDecoder INHERITED;
 };
 
-bool SkKTXImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
+SkImageDecoder::Result SkKTXImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
     // TODO: Implement SkStream::copyToData() that's cheap for memory and file streams
     SkAutoDataUnref data(CopyStreamToData(stream));
     if (NULL == data) {
-        return false;
+        return kFailure;
     }
 
     SkKTXFile ktxFile(data);
     if (!ktxFile.valid()) {
-        return false;
+        return kFailure;
     }
 
     const unsigned short width = ktxFile.width();
@@ -65,7 +65,7 @@
 #ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER
     // should we allow the Chooser (if present) to pick a config for us???
     if (!this->chooseFromOneChoice(kN32_SkColorType, width, height)) {
-        return false;
+        return kFailure;
     }
 #endif
 
@@ -84,7 +84,7 @@
             // If the client wants unpremul colors and we only have
             // premul, then we cannot honor their wish.
             if (bSrcIsPremul) {
-                return false;
+                return kFailure;
             }
         } else {
             alphaType = kPremul_SkAlphaType;
@@ -94,12 +94,12 @@
     // Set the config...
     bm->setInfo(SkImageInfo::MakeN32(sampler.scaledWidth(), sampler.scaledHeight(), alphaType));
     if (SkImageDecoder::kDecodeBounds_Mode == mode) {
-        return true;
+        return kSuccess;
     }
     
     // If we've made it this far, then we know how to grok the data.
     if (!this->allocPixelRef(bm, NULL)) {
-        return false;
+        return kFailure;
     }
 
     // Lock the pixels, since we're about to write to them...
@@ -107,7 +107,7 @@
 
     if (ktxFile.isETC1()) {
         if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) {
-            return false;
+            return kFailure;
         }
 
         // ETC1 Data is encoded as RGB pixels, so we should extract it as such
@@ -118,7 +118,7 @@
         // Decode ETC1
         const etc1_byte *buf = reinterpret_cast<const etc1_byte *>(ktxFile.pixelData());
         if (etc1_decode_image(buf, outRGBDataPtr, width, height, 3, width*3)) {
-            return false;
+            return kFailure;
         }
 
         // Set each of the pixels...
@@ -131,13 +131,13 @@
             srcRow += sampler.srcDY() * srcRowBytes;
         }
 
-        return true;
+        return kSuccess;
 
     } else if (ktxFile.isRGB8()) {
 
         // Uncompressed RGB data (without alpha)
         if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) {
-            return false;
+            return kFailure;
         }
 
         // Just need to read RGB pixels
@@ -150,7 +150,7 @@
             srcRow += sampler.srcDY() * srcRowBytes;
         }
 
-        return true;
+        return kSuccess;
 
     } else if (ktxFile.isRGBA8()) {
 
@@ -167,7 +167,7 @@
         } 
 
         if (!sampler.begin(bm, SkScaledBitmapSampler::kRGBA, opts)) {
-            return false;
+            return kFailure;
         }
 
         // Just need to read RGBA pixels
@@ -180,10 +180,10 @@
             srcRow += sampler.srcDY() * srcRowBytes;
         }
 
-        return true;
+        return kSuccess;
     }
 
-    return false;
+    return kFailure;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/images/SkImageDecoder_libbmp.cpp b/src/images/SkImageDecoder_libbmp.cpp
index f9dd247..3a9a436 100644
--- a/src/images/SkImageDecoder_libbmp.cpp
+++ b/src/images/SkImageDecoder_libbmp.cpp
@@ -24,7 +24,7 @@
     }
 
 protected:
-    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode) SK_OVERRIDE;
+    virtual Result onDecode(SkStream* stream, SkBitmap* bm, Mode mode) SK_OVERRIDE;
 
 private:
     typedef SkImageDecoder INHERITED;
@@ -92,7 +92,7 @@
     bool fJustBounds;
 };
 
-bool SkBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
+SkImageDecoder::Result SkBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
     // First read the entire stream, so that all of the data can be passed to
     // the BmpDecoderHelper.
 
@@ -101,7 +101,7 @@
     // Byte length of all of the data.
     const size_t length = CopyStreamToStorage(&storage, stream);
     if (0 == length) {
-        return 0;
+        return kFailure;
     }
 
     const bool justBounds = SkImageDecoder::kDecodeBounds_Mode == mode;
@@ -113,7 +113,7 @@
         const int max_pixels = 16383*16383; // max width*height
         if (!helper.DecodeImage((const char*)storage.get(), length,
                                 max_pixels, &callback)) {
-            return false;
+            return kFailure;
         }
     }
 
@@ -136,17 +136,17 @@
                                   colorType, kOpaque_SkAlphaType));
 
     if (justBounds) {
-        return true;
+        return kSuccess;
     }
 
     if (!this->allocPixelRef(bm, NULL)) {
-        return false;
+        return kFailure;
     }
 
     SkAutoLockPixels alp(*bm);
 
     if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) {
-        return false;
+        return kFailure;
     }
 
     const int srcRowBytes = width * 3;
@@ -158,5 +158,5 @@
         sampler.next(srcRow);
         srcRow += sampler.srcDY() * srcRowBytes;
     }
-    return true;
+    return kSuccess;
 }
diff --git a/src/images/SkImageDecoder_libgif.cpp b/src/images/SkImageDecoder_libgif.cpp
index 0c8461f..830e58c 100644
--- a/src/images/SkImageDecoder_libgif.cpp
+++ b/src/images/SkImageDecoder_libgif.cpp
@@ -24,7 +24,7 @@
     }
 
 protected:
-    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode) SK_OVERRIDE;
+    virtual Result onDecode(SkStream* stream, SkBitmap* bm, Mode mode) SK_OVERRIDE;
 
 private:
     typedef SkImageDecoder INHERITED;
@@ -152,14 +152,15 @@
     return transpIndex;
 }
 
-static bool error_return(const SkBitmap& bm, const char msg[]) {
+static SkImageDecoder::Result error_return(const SkBitmap& bm, const char msg[]) {
     if (!c_suppressGIFImageDecoderWarnings) {
         SkDebugf("libgif error [%s] bitmap [%d %d] pixels %p colortable %p\n",
                  msg, bm.width(), bm.height(), bm.getPixels(),
                  bm.getColorTable());
     }
-    return false;
+    return SkImageDecoder::kFailure;
 }
+
 static void gif_warning(const SkBitmap& bm, const char msg[]) {
     if (!c_suppressGIFImageDecoderWarnings) {
         SkDebugf("libgif warning [%s] bitmap [%d %d] pixels %p colortable %p\n",
@@ -228,7 +229,7 @@
     }
 }
 
-bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, Mode mode) {
+SkImageDecoder::Result SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, Mode mode) {
 #if GIFLIB_MAJOR < 5
     GifFileType* gif = DGifOpen(sk_stream, DecodeCallBackProc);
 #else
@@ -322,7 +323,7 @@
                                           kIndex_8_SkColorType, kPremul_SkAlphaType));
 
             if (SkImageDecoder::kDecodeBounds_Mode == mode) {
-                return true;
+                return kSuccess;
             }
 
 
@@ -427,7 +428,7 @@
                             sampler.sampleInterlaced(scanline, iter.currY());
                             iter.next();
                         }
-                        return true;
+                        return kPartialSuccess;
                     }
                     sampler.sampleInterlaced(scanline, iter.currY());
                     iter.next();
@@ -443,7 +444,7 @@
                         for (; y < outHeight; y++) {
                             sampler.next(scanline);
                         }
-                        return true;
+                        return kPartialSuccess;
                     }
                     // scanline now contains the raw data. Sample it.
                     sampler.next(scanline);
@@ -457,7 +458,7 @@
                 skip_src_rows(gif, scanline, innerWidth, innerHeight - read);
             }
             sanitize_indexed_bitmap(bm);
-            return true;
+            return kSuccess;
             } break;
 
         case EXTENSION_RECORD_TYPE:
@@ -502,7 +503,7 @@
     } while (recType != TERMINATE_RECORD_TYPE);
 
     sanitize_indexed_bitmap(bm);
-    return true;
+    return kSuccess;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/images/SkImageDecoder_libico.cpp b/src/images/SkImageDecoder_libico.cpp
index f8502d6..eae5bce 100644
--- a/src/images/SkImageDecoder_libico.cpp
+++ b/src/images/SkImageDecoder_libico.cpp
@@ -20,7 +20,7 @@
     }
 
 protected:
-    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
+    virtual Result onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
 
 private:
     typedef SkImageDecoder INHERITED;
@@ -72,12 +72,12 @@
     return 0;
 }
 
-bool SkICOImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode)
+SkImageDecoder::Result SkICOImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode)
 {
     SkAutoMalloc autoMal;
     const size_t length = CopyStreamToStorage(&autoMal, stream);
     if (0 == length) {
-        return false;
+        return kFailure;
     }
 
     unsigned char* buf = (unsigned char*)autoMal.get();
@@ -86,13 +86,16 @@
     //incorrect values, but still decode properly?
     int reserved = read2Bytes(buf, 0);    // 0
     int type = read2Bytes(buf, 2);        // 1
-    if (reserved != 0 || type != 1)
-        return false;
+    if (reserved != 0 || type != 1) {
+        return kFailure;
+    }
+
     int count = read2Bytes(buf, 4);
 
     //need to at least have enough space to hold the initial table of info
-    if (length < (size_t)(6 + count*16))
-        return false;
+    if (length < (size_t)(6 + count*16)) {
+        return kFailure;
+    }
 
 #ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER
     int choice;
@@ -137,8 +140,9 @@
     }
 
     //you never know what the chooser is going to supply
-    if (choice >= count || choice < 0)
-        return false;
+    if (choice >= count || choice < 0) {
+        return kFailure;
+    }
 #else
     const int choice = 0;   // TODO: fold this value into the expressions below
 #endif
@@ -156,7 +160,7 @@
     const size_t offset = read4Bytes(buf, 18 + choice*16);
     // promote the sum to 64-bits to avoid overflow
     if (((uint64_t)offset + size) > length) {
-        return false;
+        return kFailure;
     }
 
     // Check to see if this is a PNG image inside the ICO
@@ -165,13 +169,18 @@
         SkAutoTDelete<SkImageDecoder> otherDecoder(SkImageDecoder::Factory(&subStream));
         if (otherDecoder.get() != NULL) {
             // Disallow nesting ICO files within one another
+            // FIXME: Can ICO files contain other formats besides PNG?
             if (otherDecoder->getFormat() == SkImageDecoder::kICO_Format) {
-                return false;
+                return kFailure;
             }
             // Set fields on the other decoder to be the same as this one.
             this->copyFieldsToOther(otherDecoder.get());
-            if(otherDecoder->decode(&subStream, bm, this->getDefaultPref(), mode)) {
-                return true;
+            const Result result = otherDecoder->decode(&subStream, bm, this->getDefaultPref(),
+                                                       mode);
+            // FIXME: Should we just return result here? Is it possible that data that looked like
+            // a subimage was not, but was actually a valid ICO?
+            if (result != kFailure) {
+                return result;
             }
         }
     }
@@ -209,7 +218,7 @@
             break;
         default:
             SkDEBUGF(("Decoding %ibpp is unimplemented\n", bitCount));
-            return false;
+            return kFailure;
     }
 
     //these should all be zero, but perhaps are not - need to check
@@ -260,13 +269,13 @@
 
     if (SkImageDecoder::kDecodeBounds_Mode == mode) {
         delete[] colors;
-        return true;
+        return kSuccess;
     }
 
     if (!this->allocPixelRef(bm, NULL))
     {
         delete[] colors;
-        return false;
+        return kFailure;
     }
 
     SkAutoLockPixels alp(*bm);
@@ -296,7 +305,7 @@
     //ensure we haven't read off the end?
     //of course this doesn't help us if the andOffset was a lie...
     //return andOffset + (andLineWidth >> 3) <= length;
-    return true;
+    return kSuccess;
 }   //onDecode
 
 //function to place the pixel, determined by the bitCount
diff --git a/src/images/SkImageDecoder_libjpeg.cpp b/src/images/SkImageDecoder_libjpeg.cpp
index 9b93716..8ef96fb 100644
--- a/src/images/SkImageDecoder_libjpeg.cpp
+++ b/src/images/SkImageDecoder_libjpeg.cpp
@@ -238,7 +238,7 @@
     virtual bool onBuildTileIndex(SkStreamRewindable *stream, int *width, int *height) SK_OVERRIDE;
     virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRIDE;
 #endif
-    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
+    virtual Result onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
 
 private:
 #ifdef SK_BUILD_FOR_ANDROID
@@ -322,19 +322,34 @@
 }
 #endif
 
+///////////////////////////////////////////////////////////////////////////////
+
 // This guy exists just to aid in debugging, as it allows debuggers to just
 // set a break-point in one place to see all error exists.
-static bool return_false(const jpeg_decompress_struct& cinfo,
-                         const SkBitmap& bm, const char caller[]) {
+static void print_jpeg_decoder_errors(const jpeg_decompress_struct& cinfo,
+                         int width, int height, const char caller[]) {
     if (!(c_suppressJPEGImageDecoderErrors)) {
         char buffer[JMSG_LENGTH_MAX];
         cinfo.err->format_message((const j_common_ptr)&cinfo, buffer);
         SkDebugf("libjpeg error %d <%s> from %s [%d %d]\n",
-                 cinfo.err->msg_code, buffer, caller, bm.width(), bm.height());
+                 cinfo.err->msg_code, buffer, caller, width, height);
     }
-    return false;   // must always return false
 }
 
+static bool return_false(const jpeg_decompress_struct& cinfo,
+                         const SkBitmap& bm, const char caller[]) {
+    print_jpeg_decoder_errors(cinfo, bm.width(), bm.height(), caller);
+    return false;
+}
+
+static SkImageDecoder::Result return_failure(const jpeg_decompress_struct& cinfo,
+                                             const SkBitmap& bm, const char caller[]) {
+    print_jpeg_decoder_errors(cinfo, bm.width(), bm.height(), caller);
+    return SkImageDecoder::kFailure;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
 // Convert a scanline of CMYK samples to RGBX in place. Note that this
 // method moves the "scanline" pointer in its processing
 static void convert_CMYK_to_RGB(uint8_t* scanline, unsigned int width) {
@@ -483,7 +498,6 @@
 #endif
 }
 
-
 /**
    Sets all pixels in given bitmap to SK_ColorWHITE for all rows >= y.
    Used when decoding fails partway through reading scanlines to fill
@@ -529,7 +543,7 @@
     return true;
 }
 
-bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
+SkImageDecoder::Result SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
 #ifdef TIME_DECODE
     SkAutoTime atm("JPEG Decode");
 #endif
@@ -545,7 +559,7 @@
     // All objects need to be instantiated before this setjmp call so that
     // they will be cleaned up properly if an error occurs.
     if (setjmp(errorManager.fJmpBuf)) {
-        return return_false(cinfo, *bm, "setjmp");
+        return return_failure(cinfo, *bm, "setjmp");
     }
 
     initialize_info(&cinfo, &srcManager);
@@ -553,7 +567,7 @@
 
     int status = jpeg_read_header(&cinfo, true);
     if (status != JPEG_HEADER_OK) {
-        return return_false(cinfo, *bm, "read_header");
+        return return_failure(cinfo, *bm, "read_header");
     }
 
     /*  Try to fulfill the requested sampleSize. Since jpeg can do it (when it
@@ -580,8 +594,9 @@
         // individual pixel. It is very unlikely to be opaque, since
         // an opaque A8 bitmap would not be very interesting.
         // Otherwise, a jpeg image is opaque.
-        return bm->setInfo(SkImageInfo::Make(cinfo.image_width, cinfo.image_height,
-                                             colorType, alphaType));
+        bool success = bm->setInfo(SkImageInfo::Make(cinfo.image_width, cinfo.image_height,
+                                                     colorType, alphaType));
+        return success ? kSuccess : kFailure;
     }
 
     /*  image_width and image_height are the original dimensions, available
@@ -605,10 +620,11 @@
             // individual pixel. It is very unlikely to be opaque, since
             // an opaque A8 bitmap would not be very interesting.
             // Otherwise, a jpeg image is opaque.
-            return bm->setInfo(SkImageInfo::Make(smpl.scaledWidth(), smpl.scaledHeight(),
-                                                 colorType, alphaType));
+            bool success = bm->setInfo(SkImageInfo::Make(smpl.scaledWidth(), smpl.scaledHeight(),
+                                                         colorType, alphaType));
+            return success ? kSuccess : kFailure;
         } else {
-            return return_false(cinfo, *bm, "start_decompress");
+            return return_failure(cinfo, *bm, "start_decompress");
         }
     }
     sampleSize = recompute_sampleSize(sampleSize, cinfo);
@@ -616,7 +632,7 @@
 #ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER
     // should we allow the Chooser (if present) to pick a colortype for us???
     if (!this->chooseFromOneChoice(colorType, cinfo.output_width, cinfo.output_height)) {
-        return return_false(cinfo, *bm, "chooseFromOneChoice");
+        return return_failure(cinfo, *bm, "chooseFromOneChoice");
     }
 #endif
 
@@ -628,10 +644,10 @@
     bm->setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(),
                                   colorType, alphaType));
     if (SkImageDecoder::kDecodeBounds_Mode == mode) {
-        return true;
+        return kSuccess;
     }
     if (!this->allocPixelRef(bm, NULL)) {
-        return return_false(cinfo, *bm, "allocPixelRef");
+        return return_failure(cinfo, *bm, "allocPixelRef");
     }
 
     SkAutoLockPixels alp(*bm);
@@ -654,15 +670,16 @@
                 // so return early.  We will return a partial image.
                 fill_below_level(cinfo.output_scanline, bm);
                 cinfo.output_scanline = cinfo.output_height;
-                break;  // Skip to jpeg_finish_decompress()
+                jpeg_finish_decompress(&cinfo);
+                return kPartialSuccess;
             }
             if (this->shouldCancelDecode()) {
-                return return_false(cinfo, *bm, "shouldCancelDecode");
+                return return_failure(cinfo, *bm, "shouldCancelDecode");
             }
             rowptr += bpr;
         }
         jpeg_finish_decompress(&cinfo);
-        return true;
+        return kSuccess;
     }
 #endif
 
@@ -671,11 +688,11 @@
     int srcBytesPerPixel;
 
     if (!get_src_config(cinfo, &sc, &srcBytesPerPixel)) {
-        return return_false(cinfo, *bm, "jpeg colorspace");
+        return return_failure(cinfo, *bm, "jpeg colorspace");
     }
 
     if (!sampler.begin(bm, sc, *this)) {
-        return return_false(cinfo, *bm, "sampler.begin");
+        return return_failure(cinfo, *bm, "sampler.begin");
     }
 
     SkAutoMalloc srcStorage(cinfo.output_width * srcBytesPerPixel);
@@ -683,7 +700,7 @@
 
     //  Possibly skip initial rows [sampler.srcY0]
     if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) {
-        return return_false(cinfo, *bm, "skip rows");
+        return return_failure(cinfo, *bm, "skip rows");
     }
 
     // now loop through scanlines until y == bm->height() - 1
@@ -695,10 +712,11 @@
             // so return early.  We will return a partial image.
             fill_below_level(y, bm);
             cinfo.output_scanline = cinfo.output_height;
-            break;  // Skip to jpeg_finish_decompress()
+            jpeg_finish_decompress(&cinfo);
+            return kSuccess;
         }
         if (this->shouldCancelDecode()) {
-            return return_false(cinfo, *bm, "shouldCancelDecode");
+            return return_failure(cinfo, *bm, "shouldCancelDecode");
         }
 
         if (JCS_CMYK == cinfo.out_color_space) {
@@ -712,18 +730,18 @@
         }
 
         if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) {
-            return return_false(cinfo, *bm, "skip rows");
+            return return_failure(cinfo, *bm, "skip rows");
         }
     }
 
     // we formally skip the rest, so we don't get a complaint from libjpeg
     if (!skip_src_rows(&cinfo, srcRow,
                        cinfo.output_height - cinfo.output_scanline)) {
-        return return_false(cinfo, *bm, "skip rows");
+        return return_failure(cinfo, *bm, "skip rows");
     }
     jpeg_finish_decompress(&cinfo);
 
-    return true;
+    return kSuccess;
 }
 
 #ifdef SK_BUILD_FOR_ANDROID
diff --git a/src/images/SkImageDecoder_libpng.cpp b/src/images/SkImageDecoder_libpng.cpp
index 01b7c69..7e42e6d 100644
--- a/src/images/SkImageDecoder_libpng.cpp
+++ b/src/images/SkImageDecoder_libpng.cpp
@@ -91,7 +91,7 @@
     virtual bool onBuildTileIndex(SkStreamRewindable *stream, int *width, int *height) SK_OVERRIDE;
     virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& region) SK_OVERRIDE;
 #endif
-    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
+    virtual Result onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
 
 private:
     SkPNGImageIndex* fImageIndex;
@@ -297,19 +297,19 @@
     return true;
 }
 
-bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
-                                 Mode mode) {
+SkImageDecoder::Result SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
+                                                   Mode mode) {
     png_structp png_ptr;
     png_infop info_ptr;
 
     if (!onDecodeInit(sk_stream, &png_ptr, &info_ptr)) {
-        return false;
+        return kFailure;
     }
 
     PNGAutoClean autoClean(png_ptr, info_ptr);
 
     if (setjmp(png_jmpbuf(png_ptr))) {
-        return false;
+        return kFailure;
     }
 
     png_uint_32 origWidth, origHeight;
@@ -322,7 +322,7 @@
     SkPMColor           theTranspColor = 0; // 0 tells us not to try to match
 
     if (!this->getBitmapColorType(png_ptr, info_ptr, &colorType, &hasAlpha, &theTranspColor)) {
-        return false;
+        return kFailure;
     }
 
     SkAlphaType alphaType = this->getRequireUnpremultipliedColors() ?
@@ -333,7 +333,7 @@
                                              colorType, alphaType));
 
     if (SkImageDecoder::kDecodeBounds_Mode == mode) {
-        return true;
+        return kSuccess;
     }
 
     // from here down we are concerned with colortables and pixels
@@ -352,7 +352,7 @@
 
     if (!this->allocPixelRef(decodedBitmap,
                              kIndex_8_SkColorType == colorType ? colorTable : NULL)) {
-        return false;
+        return kFailure;
     }
 
     SkAutoLockPixels alp(*decodedBitmap);
@@ -410,7 +410,7 @@
          */
         SkAutoLockColors ctLock(colorTable);
         if (!sampler.begin(decodedBitmap, sc, *this, ctLock.colors())) {
-            return false;
+            return kFailure;
         }
         const int height = decodedBitmap->height();
 
@@ -467,7 +467,7 @@
                 // Fall through.
             case kARGB_4444_SkColorType:
                 // We have chosen not to support unpremul for these colortypes.
-                return false;
+                return kFailure;
             default: {
                 // Fall through to finish the decode. This colortype either
                 // supports unpremul or it is irrelevant because it has no
@@ -480,7 +480,7 @@
     if (!reallyHasAlpha) {
         decodedBitmap->setAlphaType(kOpaque_SkAlphaType);
     }
-    return true;
+    return kSuccess;
 }
 
 
diff --git a/src/images/SkImageDecoder_libwebp.cpp b/src/images/SkImageDecoder_libwebp.cpp
index f7cfa8b..e755b6a 100644
--- a/src/images/SkImageDecoder_libwebp.cpp
+++ b/src/images/SkImageDecoder_libwebp.cpp
@@ -111,7 +111,7 @@
 protected:
     virtual bool onBuildTileIndex(SkStreamRewindable *stream, int *width, int *height) SK_OVERRIDE;
     virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRIDE;
-    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
+    virtual Result onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
 
 private:
     /**
@@ -162,11 +162,22 @@
 
 // This guy exists just to aid in debugging, as it allows debuggers to just
 // set a break-point in one place to see all error exists.
-static bool return_false(const SkBitmap& bm, const char msg[]) {
+static void print_webp_error(const SkBitmap& bm, const char msg[]) {
     SkDEBUGF(("libwebp error %s [%d %d]", msg, bm.width(), bm.height()));
+}
+
+static bool return_false(const SkBitmap& bm, const char msg[]) {
+    print_webp_error(bm, msg);
     return false; // must always return false
 }
 
+static SkImageDecoder::Result return_failure(const SkBitmap& bm, const char msg[]) {
+    print_webp_error(bm, msg);
+    return SkImageDecoder::kFailure; // must always return kFailure
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
 static WEBP_CSP_MODE webp_decode_mode(const SkBitmap* decodedBitmap, bool premultiply) {
     WEBP_CSP_MODE mode = MODE_LAST;
     const SkColorType ct = decodedBitmap->colorType();
@@ -409,15 +420,15 @@
     return true;
 }
 
-bool SkWEBPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap,
-                                  Mode mode) {
+SkImageDecoder::Result SkWEBPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap,
+                                                    Mode mode) {
 #ifdef TIME_DECODE
     AutoTimeMillis atm("WEBP Decode");
 #endif
 
     int origWidth, origHeight, hasAlpha;
     if (!webp_parse_header(stream, &origWidth, &origHeight, &hasAlpha)) {
-        return false;
+        return kFailure;
     }
     this->fHasAlpha = hasAlpha;
 
@@ -425,16 +436,16 @@
     SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize);
     if (!setDecodeConfig(decodedBitmap, sampler.scaledWidth(),
                          sampler.scaledHeight())) {
-        return false;
+        return kFailure;
     }
 
     // If only bounds are requested, done
     if (SkImageDecoder::kDecodeBounds_Mode == mode) {
-        return true;
+        return kSuccess;
     }
 
     if (!this->allocPixelRef(decodedBitmap, NULL)) {
-        return return_false(*decodedBitmap, "allocPixelRef");
+        return return_failure(*decodedBitmap, "allocPixelRef");
     }
 
     SkAutoLockPixels alp(*decodedBitmap);
@@ -442,11 +453,11 @@
     WebPDecoderConfig config;
     if (!webp_get_config_resize(&config, decodedBitmap, origWidth, origHeight,
                                 this->shouldPremultiply())) {
-        return false;
+        return kFailure;
     }
 
     // Decode the WebP image data stream using WebP incremental decoding.
-    return webp_idecode(stream, &config);
+    return webp_idecode(stream, &config) ? kSuccess : kFailure;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/images/SkImageDecoder_pkm.cpp b/src/images/SkImageDecoder_pkm.cpp
index d555c6a..e0c59c9 100644
--- a/src/images/SkImageDecoder_pkm.cpp
+++ b/src/images/SkImageDecoder_pkm.cpp
@@ -23,7 +23,7 @@
     }
 
 protected:
-    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
+    virtual Result onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
 
 private:
     typedef SkImageDecoder INHERITED;
@@ -31,11 +31,11 @@
 
 /////////////////////////////////////////////////////////////////////////////////////////
 
-bool SkPKMImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
+SkImageDecoder::Result SkPKMImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
     SkAutoMalloc autoMal;
     const size_t length = CopyStreamToStorage(&autoMal, stream);
     if (0 == length) {
-        return false;
+        return kFailure;
     }
 
     unsigned char* buf = (unsigned char*)autoMal.get();
@@ -49,7 +49,7 @@
 #ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER
     // should we allow the Chooser (if present) to pick a config for us???
     if (!this->chooseFromOneChoice(kN32_SkColorType, width, height)) {
-        return false;
+        return kFailure;
     }
 #endif
 
@@ -60,18 +60,18 @@
     bm->setInfo(SkImageInfo::MakeN32(sampler.scaledWidth(), sampler.scaledHeight(),
                                      kOpaque_SkAlphaType));
     if (SkImageDecoder::kDecodeBounds_Mode == mode) {
-        return true;
+        return kSuccess;
     }
 
     if (!this->allocPixelRef(bm, NULL)) {
-        return false;
+        return kFailure;
     }
 
     // Lock the pixels, since we're about to write to them...
     SkAutoLockPixels alp(*bm);
 
     if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) {
-        return false;
+        return kFailure;
     }
 
     // Advance buffer past the header
@@ -84,7 +84,7 @@
 
     // Decode ETC1
     if (etc1_decode_image(buf, outRGBDataPtr, width, height, 3, width*3)) {
-        return false;
+        return kFailure;
     }
 
     // Set each of the pixels...
@@ -97,7 +97,7 @@
         srcRow += sampler.srcDY() * srcRowBytes;
     }
 
-    return true;
+    return kSuccess;
 }
 
 /////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/images/SkImageDecoder_wbmp.cpp b/src/images/SkImageDecoder_wbmp.cpp
index 0bf1389..259fc02 100644
--- a/src/images/SkImageDecoder_wbmp.cpp
+++ b/src/images/SkImageDecoder_wbmp.cpp
@@ -22,7 +22,7 @@
     }
 
 protected:
-    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
+    virtual Result onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
 
 private:
     typedef SkImageDecoder INHERITED;
@@ -99,13 +99,13 @@
     }
 }
 
-bool SkWBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap,
-                                  Mode mode)
+SkImageDecoder::Result SkWBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap,
+                                                    Mode mode)
 {
     wbmp_head   head;
 
     if (!head.init(stream)) {
-        return false;
+        return kFailure;
     }
 
     int width = head.fWidth;
@@ -115,15 +115,15 @@
                                              kIndex_8_SkColorType, kOpaque_SkAlphaType));
 
     if (SkImageDecoder::kDecodeBounds_Mode == mode) {
-        return true;
+        return kSuccess;
     }
 
     const SkPMColor colors[] = { SK_ColorBLACK, SK_ColorWHITE };
-    SkColorTable* ct = SkNEW_ARGS(SkColorTable, (colors, 2));
+    SkColorTable* ct = SkNEW_ARGS(SkColorTable, (colors, 2, kOpaque_SkAlphaType));
     SkAutoUnref   aur(ct);
 
     if (!this->allocPixelRef(decodedBitmap, ct)) {
-        return false;
+        return kFailure;
     }
 
     SkAutoLockPixels alp(*decodedBitmap);
@@ -135,7 +135,7 @@
     size_t srcSize = height * srcRB;
     uint8_t* src = dst + decodedBitmap->getSize() - srcSize;
     if (stream->read(src, srcSize) != srcSize) {
-        return false;
+        return kFailure;
     }
 
     for (int y = 0; y < height; y++)
@@ -145,7 +145,7 @@
         src += srcRB;
     }
 
-    return true;
+    return kSuccess;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/images/SkScaledBitmapSampler.cpp b/src/images/SkScaledBitmapSampler.cpp
index d78502d..fe425d5 100644
--- a/src/images/SkScaledBitmapSampler.cpp
+++ b/src/images/SkScaledBitmapSampler.cpp
@@ -835,8 +835,8 @@
 public:
     DummyDecoder() {}
 protected:
-    virtual bool onDecode(SkStream*, SkBitmap*, SkImageDecoder::Mode) SK_OVERRIDE {
-        return false;
+    virtual Result onDecode(SkStream*, SkBitmap*, SkImageDecoder::Mode) SK_OVERRIDE {
+        return kFailure;
     }
 };
 
diff --git a/src/ports/SkImageDecoder_CG.cpp b/src/ports/SkImageDecoder_CG.cpp
index 8545ac8..1109443 100644
--- a/src/ports/SkImageDecoder_CG.cpp
+++ b/src/ports/SkImageDecoder_CG.cpp
@@ -47,22 +47,22 @@
 
 class SkImageDecoder_CG : public SkImageDecoder {
 protected:
-    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
+    virtual Result onDecode(SkStream* stream, SkBitmap* bm, Mode);
 };
 
 #define BITMAP_INFO (kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast)
 
-bool SkImageDecoder_CG::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
+SkImageDecoder::Result SkImageDecoder_CG::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
     CGImageSourceRef imageSrc = SkStreamToCGImageSource(stream);
 
     if (NULL == imageSrc) {
-        return false;
+        return kFailure;
     }
     SkAutoTCallVProc<const void, CFRelease> arsrc(imageSrc);
 
     CGImageRef image = CGImageSourceCreateImageAtIndex(imageSrc, 0, NULL);
     if (NULL == image) {
-        return false;
+        return kFailure;
     }
     SkAutoTCallVProc<CGImage, CGImageRelease> arimage(image);
 
@@ -71,17 +71,17 @@
 
     bm->setInfo(SkImageInfo::MakeN32Premul(width, height));
     if (SkImageDecoder::kDecodeBounds_Mode == mode) {
-        return true;
+        return kSuccess;
     }
 
     if (!this->allocPixelRef(bm, NULL)) {
-        return false;
+        return kFailure;
     }
 
     SkAutoLockPixels alp(*bm);
 
     if (!SkCopyPixelsFromCGImage(bm->info(), bm->rowBytes(), bm->getPixels(), image)) {
-        return false;
+        return kFailure;
     }
 
     CGImageAlphaInfo info = CGImageGetAlphaInfo(image);
@@ -109,7 +109,7 @@
         }
         bm->setAlphaType(kUnpremul_SkAlphaType);
     }
-    return true;
+    return kSuccess;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/ports/SkImageDecoder_WIC.cpp b/src/ports/SkImageDecoder_WIC.cpp
index 3309af4..0c109a2 100644
--- a/src/ports/SkImageDecoder_WIC.cpp
+++ b/src/ports/SkImageDecoder_WIC.cpp
@@ -67,7 +67,7 @@
     bool decodeStream(SkStream* stream, SkBitmap* bm, WICModes wicMode, Format* format) const;
 
 protected:
-    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode) SK_OVERRIDE;
+    virtual Result onDecode(SkStream* stream, SkBitmap* bm, Mode mode) SK_OVERRIDE;
 };
 
 struct FormatConversion {
@@ -92,7 +92,7 @@
     return SkImageDecoder::kUnknown_Format;
 }
 
-bool SkImageDecoder_WIC::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
+SkImageDecoder::Result SkImageDecoder_WIC::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
     WICModes wicMode;
     switch (mode) {
         case SkImageDecoder::kDecodeBounds_Mode:
@@ -102,7 +102,7 @@
             wicMode = kDecodePixels_WICMode;
             break;
     }
-    return this->decodeStream(stream, bm, wicMode, NULL);
+    return this->decodeStream(stream, bm, wicMode, NULL) ? kSuccess : kFailure;
 }
 
 bool SkImageDecoder_WIC::decodeStream(SkStream* stream, SkBitmap* bm, WICModes wicMode,
diff --git a/src/ports/SkImageDecoder_empty.cpp b/src/ports/SkImageDecoder_empty.cpp
index 7824732..722b7d4 100644
--- a/src/ports/SkImageDecoder_empty.cpp
+++ b/src/ports/SkImageDecoder_empty.cpp
@@ -32,8 +32,8 @@
     return false;
 }
 
-bool SkImageDecoder::decode(SkStream*, SkBitmap*, SkColorType, Mode) {
-    return false;
+SkImageDecoder::Result SkImageDecoder::decode(SkStream*, SkBitmap*, SkColorType, Mode) {
+    return kFailure;
 }
 
 bool SkImageDecoder::DecodeStream(SkStreamRewindable*, SkBitmap*, SkColorType, Mode, Format*) {
diff --git a/src/utils/SkFrontBufferedStream.cpp b/src/utils/SkFrontBufferedStream.cpp
index 8cb3931..80a2bcf 100644
--- a/src/utils/SkFrontBufferedStream.cpp
+++ b/src/utils/SkFrontBufferedStream.cpp
@@ -175,7 +175,7 @@
 
     // Buffer any more data that should be buffered, and copy it to the
     // destination.
-    if (size > 0 && fBufferedSoFar < fBufferSize) {
+    if (size > 0 && fBufferedSoFar < fBufferSize && !fStream->isAtEnd()) {
         const size_t buffered = this->bufferAndWriteTo(dst, size);
 
         // Update the remaining number of bytes needed to read