SkDecodingImageGenerator now uses SkStreamRewindable

This makes sense since Android will be giving us a stream and the
decoders expect a stream.  This also removes some glue code,
DecodeMemoryToTarget, that works better using a SkImageGenerator.

Motivation: This is a necessary step to move from SkImageRef to
SkDiscardablePixelRef.

SkImageDecoder::DecodeMemoryToTarget function removed.

BUG=
R=reed@google.com, scroggo@google.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk@12560 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkImageDecoder.h b/include/core/SkImageDecoder.h
index 43950ad..7241458 100644
--- a/include/core/SkImageDecoder.h
+++ b/include/core/SkImageDecoder.h
@@ -349,33 +349,6 @@
         size_t fRowBytes;
     };
 
-    /**
-     *  Decode memory.
-     *  @param info Output parameter. Returns info about the encoded image.
-     *  @param target Contains the address of pixel memory to decode into
-     *         (which must be large enough to hold the width in info) and
-     *         the row bytes to use. If NULL, returns info and does not
-     *         decode pixels.
-     *  @return bool Whether the function succeeded.
-     *
-     *  Sample usage:
-     *  <code>
-     *      // Determine the image's info: width/height/config
-     *      SkImageInfo info;
-     *      bool success = DecodeMemoryToTarget(src, size, &info, NULL);
-     *      if (!success) return;
-     *      // Allocate space for the result:
-     *      SkBitmapFactory::Target target;
-     *      target.fAddr = malloc/other allocation
-     *      target.fRowBytes = ...
-     *      // Now decode the actual pixels into target. &info is optional,
-     *      // and could be NULL
-     *      success = DecodeMemoryToTarget(src, size, &info, &target);
-     *  </code>
-     */
-    static bool DecodeMemoryToTarget(const void* buffer, size_t size, SkImageInfo* info,
-                                     const Target* target);
-
     /** Decode the image stored in the specified SkStreamRewindable, and store the result
         in bitmap. Return true for success or false on failure.
 
diff --git a/src/images/SkDecodingImageGenerator.cpp b/src/images/SkDecodingImageGenerator.cpp
index 05651c7..2b80444 100644
--- a/src/images/SkDecodingImageGenerator.cpp
+++ b/src/images/SkDecodingImageGenerator.cpp
@@ -9,39 +9,184 @@
 #include "SkData.h"
 #include "SkDiscardablePixelRef.h"
 #include "SkImageDecoder.h"
+#include "SkImagePriv.h"
+#include "SkStream.h"
+
+
+namespace {
+/**
+ *  Special allocator used by getPixels(). Uses preallocated memory
+ *  provided.
+ */
+class TargetAllocator : public SkBitmap::Allocator {
+public:
+    TargetAllocator(void* target, size_t rowBytes, const SkImageInfo& info)
+        : fTarget(target)
+        , fRowBytes(rowBytes)
+        , fInfo(info) { }
+
+    virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) SK_OVERRIDE {
+        if ((SkImageInfoToBitmapConfig(fInfo) != bm->config())
+            || (bm->width() != fInfo.fWidth)
+            || (bm->height() != fInfo.fHeight)) {
+            return false;
+        }
+        bm->setConfig(bm->config(), bm->width(), bm->height(),
+                      fRowBytes, bm->alphaType());
+        bm->setPixels(fTarget, ct);
+        return true;
+    }
+
+private:
+    void* fTarget;
+    size_t fRowBytes;
+    SkImageInfo fInfo;
+    typedef SkBitmap::Allocator INHERITED;
+};
+}  // namespace
+////////////////////////////////////////////////////////////////////////////////
 
 SkDecodingImageGenerator::SkDecodingImageGenerator(SkData* data)
-    : fData(data) {
+    : fData(data)
+    , fHasInfo(false)
+    , fDoCopyTo(false) {
     SkASSERT(fData != NULL);
+    fStream = SkNEW_ARGS(SkMemoryStream, (fData));
+    SkASSERT(fStream != NULL);
+    SkASSERT(fStream->unique());
     fData->ref();
 }
 
+SkDecodingImageGenerator::SkDecodingImageGenerator(SkStreamRewindable* stream)
+    : fData(NULL)
+    , fStream(stream)
+    , fHasInfo(false)
+    , fDoCopyTo(false) {
+    SkASSERT(fStream != NULL);
+    SkASSERT(fStream->unique());
+}
+
 SkDecodingImageGenerator::~SkDecodingImageGenerator() {
-    fData->unref();
+    SkSafeUnref(fData);
+    fStream->unref();
 }
 
+// TODO(halcanary): Give this macro a better name and move it into SkTypes.h
+#ifdef SK_DEBUG
+    #define SkCheckResult(expr, value)  SkASSERT((value) == (expr))
+#else
+    #define SkCheckResult(expr, value)  (void)(expr)
+#endif
+
 SkData* SkDecodingImageGenerator::refEncodedData() {
     // This functionality is used in `gm --serialize`
-    fData->ref();
-    return fData;
+    if (fData != NULL) {
+        return SkSafeRef(fData);
+    }
+    // TODO(halcanary): SkStreamRewindable needs a refData() function
+    // which returns a cheap copy of the underlying data.
+    if (!fStream->rewind()) {
+        return NULL;
+    }
+    size_t length = fStream->getLength();
+    if (0 == length) {
+        return NULL;
+    }
+    void* buffer = sk_malloc_flags(length, 0);
+    SkCheckResult(fStream->read(buffer, length), length);
+    fData = SkData::NewFromMalloc(buffer, length);
+    return SkSafeRef(fData);
 }
 
 bool SkDecodingImageGenerator::getInfo(SkImageInfo* info) {
-    SkASSERT(info != NULL);
-    return SkImageDecoder::DecodeMemoryToTarget(fData->data(),
-                                                fData->size(),
-                                                info, NULL);
+    // info can be NULL.  If so, will update fInfo, fDoCopyTo, and fHasInfo.
+    if (fHasInfo) {
+        if (info != NULL) {
+            *info = fInfo;
+        }
+        return true;
+    }
+    SkAssertResult(fStream->rewind());
+    SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream));
+    if (NULL == decoder.get()) {
+        return false;
+    }
+    SkBitmap bitmap;
+    if (!decoder->decode(fStream, &bitmap,
+                         SkImageDecoder::kDecodeBounds_Mode)) {
+        return false;
+    }
+    if (bitmap.config() == SkBitmap::kNo_Config) {
+        return false;
+    }
+    if (!SkBitmapToImageInfo(bitmap, &fInfo)) {
+        // We can't use bitmap.config() as is.
+        // Must be kARGB_4444_Config.
+        if (!bitmap.canCopyTo(SkBitmap::kARGB_8888_Config)) {
+            // kARGB_4444_Config can copy to kARGB_8888.
+            SkDEBUGFAIL("!bitmap->canCopyTo(SkBitmap::kARGB_8888_Config)");
+            return false;
+        }
+        fDoCopyTo = true;
+        fInfo.fWidth = bitmap.width();
+        fInfo.fHeight = bitmap.height();
+        fInfo.fColorType = kPMColor_SkColorType;
+        fInfo.fAlphaType = bitmap.alphaType();
+    }
+    if (info != NULL) {
+        *info = fInfo;
+    }
+    fHasInfo = true;
+    return true;
 }
 
 bool SkDecodingImageGenerator::getPixels(const SkImageInfo& info,
                                          void* pixels,
                                          size_t rowBytes) {
-    SkASSERT(pixels != NULL);
-    SkImageDecoder::Target target = {pixels, rowBytes};
-    SkImageInfo tmpInfo = info;
-    return SkImageDecoder::DecodeMemoryToTarget(fData->data(),
-                                                fData->size(),
-                                                &tmpInfo, &target);
+    if (NULL == pixels) {
+        return false;
+    }
+    if (!this->getInfo(NULL)) {
+        return false;
+    }
+    if (SkImageInfoToBitmapConfig(info) == SkBitmap::kNo_Config) {
+        return false;  // Unsupported SkColorType.
+    }
+    SkAssertResult(fStream->rewind());
+    SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream));
+    if (NULL == decoder.get()) {
+        return false;
+    }
+    if (fInfo != info) {
+        // The caller has specified a different info.  For now, this
+        // is an error.  In the future, we will check to see if we can
+        // convert.
+        return false;
+    }
+    int bpp = SkBitmap::ComputeBytesPerPixel(SkImageInfoToBitmapConfig(info));
+    if (static_cast<size_t>(bpp * info.fWidth) > rowBytes) {
+        return false;
+    }
+    SkBitmap bitmap;
+    if (!bitmap.setConfig(info, rowBytes)) {
+        return false;
+    }
+
+    TargetAllocator allocator(pixels, rowBytes, info);
+    if (!fDoCopyTo) {
+        decoder->setAllocator(&allocator);
+    }
+    bool success = decoder->decode(fStream, &bitmap,
+                                   SkImageDecoder::kDecodePixels_Mode);
+    decoder->setAllocator(NULL);
+    if (!success) {
+        return false;
+    }
+    if (fDoCopyTo) {
+        SkBitmap bm8888;
+        bitmap.copyTo(&bm8888, SkBitmap::kARGB_8888_Config, &allocator);
+    }
+    return true;
 }
 bool SkDecodingImageGenerator::Install(SkData* data, SkBitmap* dst,
                                        SkDiscardableMemory::Factory* factory) {
@@ -50,3 +195,17 @@
     SkImageGenerator* gen(SkNEW_ARGS(SkDecodingImageGenerator, (data)));
     return SkDiscardablePixelRef::Install(gen, dst, factory);
 }
+
+bool SkDecodingImageGenerator::Install(SkStreamRewindable* stream,
+                                       SkBitmap* dst,
+                                       SkDiscardableMemory::Factory* factory) {
+    SkASSERT(stream != NULL);
+    SkASSERT(dst != NULL);
+    if ((stream == NULL) || !stream->unique()) {
+        SkSafeUnref(stream);
+        return false;
+    }
+    SkImageGenerator* gen(SkNEW_ARGS(SkDecodingImageGenerator, (stream)));
+    return SkDiscardablePixelRef::Install(gen, dst, factory);
+}
+
diff --git a/src/images/SkDecodingImageGenerator.h b/src/images/SkDecodingImageGenerator.h
index 49f1295..dba234b 100644
--- a/src/images/SkDecodingImageGenerator.h
+++ b/src/images/SkDecodingImageGenerator.h
@@ -10,8 +10,10 @@
 
 #include "SkDiscardableMemory.h"
 #include "SkImageGenerator.h"
+#include "SkImageInfo.h"
 
 class SkBitmap;
+class SkStreamRewindable;
 
 /**
  * Calls into SkImageDecoder::DecodeMemoryToTarget to implement a
@@ -23,7 +25,32 @@
      *  The constructor will take a reference to the SkData.  The
      *  destructor will unref() it.
      */
-    SkDecodingImageGenerator(SkData* data);
+    explicit SkDecodingImageGenerator(SkData* data);
+
+    /*
+     *  The SkData version of this constructor is preferred.  If the
+     *  stream has an underlying SkData (such as a SkMemoryStream)
+     *  pass that in.
+     *
+     *  This object will unref the stream when done.  Since streams
+     *  have internal state (position), the caller should not pass a
+     *  shared stream in.  Pass either a new duplicated stream in or
+     *  transfer ownership of the stream.  In the latter case, be sure
+     *  that there are no other consumers of the stream who will
+     *  modify the stream's position.  This constructor asserts
+     *  stream->unique().
+     *
+     *  For example:
+     *    SkStreamRewindable* stream;
+     *    ...
+     *    SkImageGenerator* gen
+     *        = SkNEW_ARGS(SkDecodingImageGenerator,
+     *                     (stream->duplicate()));
+     *    ...
+     *    SkDELETE(gen);
+     */
+    explicit SkDecodingImageGenerator(SkStreamRewindable* stream);
+
     virtual ~SkDecodingImageGenerator();
 
     virtual SkData* refEncodedData() SK_OVERRIDE;
@@ -52,8 +79,42 @@
      */
     static bool Install(SkData* data, SkBitmap* destination,
                         SkDiscardableMemory::Factory* factory = NULL);
+    /**
+     *  Install the stream into the destination bitmap, using a new
+     *  SkDiscardablePixelRef and a new SkDecodingImageGenerator.
+     *
+     *  The SkData version of this function is preferred.  If the
+     *  stream has an underlying SkData (such as a SkMemoryStream)
+     *  pass that in.
+     *
+     *  @param stream The source of encoded data that will be passed
+     *  to the decoder.  The installed SkDecodingImageGenerator will
+     *  unref the stream when done.  If false is returned, this
+     *  function will perform the unref.  Since streams have internal
+     *  state (position), the caller should not pass a shared stream
+     *  in.  Pass either a new duplicated stream in or transfer
+     *  ownership of the stream.  In the latter case, be sure that
+     *  there are no other consumers of the stream who will modify the
+     *  stream's position.  This function will fail if
+     *  (!stream->unique()).
+     *
+     *  @param destination Upon success, this bitmap will be
+     *  configured and have a pixelref installed.
+     *
+     *  @param factory If not NULL, this object will be used as a
+     *  source of discardable memory when decoding.  If NULL, then
+     *  SkDiscardableMemory::Create() will be called.
+     *
+     *  @return true iff successful.
+     */
+    static bool Install(SkStreamRewindable* stream, SkBitmap* destination,
+                        SkDiscardableMemory::Factory* factory = NULL);
 
 private:
-    SkData* fData;
+    SkData*             fData;
+    SkStreamRewindable* fStream;
+    SkImageInfo         fInfo;
+    bool                fHasInfo;
+    bool                fDoCopyTo;
 };
 #endif  // SkDecodingImageGenerator_DEFINED
diff --git a/src/images/SkImageDecoder.cpp b/src/images/SkImageDecoder.cpp
index ee7ad5e..32cf087 100644
--- a/src/images/SkImageDecoder.cpp
+++ b/src/images/SkImageDecoder.cpp
@@ -282,153 +282,6 @@
     return SkImageDecoder::DecodeStream(&stream, bm, pref, mode, format);
 }
 
-/**
- *  Special allocator used by DecodeMemoryToTarget. Uses preallocated memory
- *  provided if the bm is 8888. Otherwise, uses a heap allocator. The same
- *  allocator will be used again for a copy to 8888, when the preallocated
- *  memory will be used.
- */
-class TargetAllocator : public SkBitmap::HeapAllocator {
-
-public:
-    TargetAllocator(void* target)
-        : fTarget(target) {}
-
-    virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) SK_OVERRIDE {
-        // If the config is not 8888, allocate a pixelref using the heap.
-        // fTarget will be used to store the final pixels when copied to
-        // 8888.
-        if (bm->config() != SkBitmap::kARGB_8888_Config) {
-            return INHERITED::allocPixelRef(bm, ct);
-        }
-        // In kARGB_8888_Config, there is no colortable.
-        SkASSERT(NULL == ct);
-        bm->setPixels(fTarget);
-        return true;
-    }
-
-private:
-    void* fTarget;
-    typedef SkBitmap::HeapAllocator INHERITED;
-};
-
-/**
- *  Helper function for DecodeMemoryToTarget. DecodeMemoryToTarget wants
- *  8888, so set the config to it. All parameters must not be null.
- *  @param decoder Decoder appropriate for this stream.
- *  @param stream Rewound stream to the encoded data.
- *  @param bitmap On success, will have its bounds set to the bounds of the
- *      encoded data, and its config set to 8888.
- *  @return True if the bounds were decoded and the bitmap is 8888 or can be
- *      copied to 8888.
- */
-static bool decode_bounds_to_8888(SkImageDecoder* decoder, SkStream* stream,
-                                  SkBitmap* bitmap) {
-    SkASSERT(decoder != NULL);
-    SkASSERT(stream != NULL);
-    SkASSERT(bitmap != NULL);
-
-    if (!decoder->decode(stream, bitmap, SkImageDecoder::kDecodeBounds_Mode)) {
-        return false;
-    }
-
-    if (bitmap->config() == SkBitmap::kARGB_8888_Config) {
-        return true;
-    }
-
-    if (!bitmap->canCopyTo(SkBitmap::kARGB_8888_Config)) {
-        return false;
-    }
-
-    bitmap->setConfig(SkBitmap::kARGB_8888_Config, bitmap->width(), bitmap->height());
-    return true;
-}
-
-/**
- *  Helper function for DecodeMemoryToTarget. Decodes the stream into bitmap, and if
- *  the bitmap is not 8888, then it is copied to 8888. Either way, the end result has
- *  its pixels stored in target. All parameters must not be null.
- *  @param decoder Decoder appropriate for this stream.
- *  @param stream Rewound stream to the encoded data.
- *  @param bitmap On success, will contain the decoded image, with its pixels stored
- *      at target.
- *  @param target Preallocated memory for storing pixels.
- *  @return bool Whether the decode (and copy, if necessary) succeeded.
- */
-static bool decode_pixels_to_8888(SkImageDecoder* decoder, SkStream* stream,
-                                  SkBitmap* bitmap, void* target) {
-    SkASSERT(decoder != NULL);
-    SkASSERT(stream != NULL);
-    SkASSERT(bitmap != NULL);
-    SkASSERT(target != NULL);
-
-    TargetAllocator allocator(target);
-    decoder->setAllocator(&allocator);
-
-    bool success = decoder->decode(stream, bitmap, SkImageDecoder::kDecodePixels_Mode);
-    decoder->setAllocator(NULL);
-
-    if (!success) {
-        return false;
-    }
-
-    if (bitmap->config() == SkBitmap::kARGB_8888_Config) {
-        return true;
-    }
-
-    SkBitmap bm8888;
-    if (!bitmap->copyTo(&bm8888, SkBitmap::kARGB_8888_Config, &allocator)) {
-        return false;
-    }
-
-    bitmap->swap(bm8888);
-    return true;
-}
-
-bool SkImageDecoder::DecodeMemoryToTarget(const void* buffer, size_t size,
-                                          SkImageInfo* info,
-                                          const SkImageDecoder::Target* target) {
-    // FIXME: Just to get this working, implement in terms of existing
-    // ImageDecoder calls.
-    SkBitmap bm;
-    SkMemoryStream stream(buffer, size);
-    SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream));
-    if (NULL == decoder.get()) {
-        return false;
-    }
-
-    if (!decode_bounds_to_8888(decoder.get(), &stream, &bm)) {
-        return false;
-    }
-
-    SkASSERT(bm.config() == SkBitmap::kARGB_8888_Config);
-
-    // Now set info properly.
-    // Since Config is SkBitmap::kARGB_8888_Config, SkBitmapToImageInfo
-    // will always succeed.
-    if (info) {
-        SkAssertResult(SkBitmapToImageInfo(bm, info));
-    }
-
-    if (NULL == target) {
-        return true;
-    }
-
-    if (target->fRowBytes != SkToU32(bm.rowBytes())) {
-        size_t minRB = SkBitmap::ComputeRowBytes(bm.config(), bm.width());
-        if (target->fRowBytes < minRB) {
-            SkDEBUGFAIL("Desired row bytes is too small");
-            return false;
-        }
-        bm.setConfig(bm.config(), bm.width(), bm.height(), target->fRowBytes);
-    }
-
-    // SkMemoryStream.rewind() will always return true.
-    SkAssertResult(stream.rewind());
-    return decode_pixels_to_8888(decoder.get(), &stream, &bm, target->fAddr);
-}
-
-
 bool SkImageDecoder::DecodeStream(SkStreamRewindable* stream, SkBitmap* bm,
                                   SkBitmap::Config pref, Mode mode,
                                   Format* format) {
diff --git a/src/ports/SkImageDecoder_empty.cpp b/src/ports/SkImageDecoder_empty.cpp
index 6721497..ae0fc36 100644
--- a/src/ports/SkImageDecoder_empty.cpp
+++ b/src/ports/SkImageDecoder_empty.cpp
@@ -83,11 +83,6 @@
 
 void SkImageDecoder::setSampleSize(int) {}
 
-bool SkImageDecoder::DecodeMemoryToTarget(const void*, size_t, SkImageInfo*,
-                                          const SkImageDecoder::Target*) {
-    return false;
-}
-
 SkBitmap::Config SkImageDecoder::GetDeviceConfig() {
     return SkBitmap::kNo_Config;
 }