Revert of Delete SkImageDecoder (patchset #8 id:130001 of https://codereview.chromium.org/1820503002/ )

Reason for revert:
Testing the roll - it's still failing

Original issue's description:
> Delete SkImageDecoder
>
> This image decoding implementation has been replaced
> by SkCodec in Android.
>
> Additionally, we have replaced uses of SkImageDecoder
> in Skia and Google3 with uses of SkCodec.
>
> Now we can delete SkImageDecoder :).
>
> BUG=skia:
> GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1820503002
> CQ_EXTRA_TRYBOTS=client.skia.compile:Build-Ubuntu-GCC-x86_64-Release-CMake-Trybot,Build-Mac-Clang-x86_64-Release-CMake-Trybot
>
> Committed: https://skia.googlesource.com/skia/+/f799706656f2581c5bf5510d94df3fa17cce1607
>
> Committed: https://skia.googlesource.com/skia/+/5b6e73e0c8282c4d85accbfbcecc6dee84f8a1eb

TBR=scroggo@google.com,djsollen@google.com
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=skia:

Review URL: https://codereview.chromium.org/1828433004
diff --git a/src/images/SkImageDecoder_libwebp.cpp b/src/images/SkImageDecoder_libwebp.cpp
index 116608a..2db08ce 100644
--- a/src/images/SkImageDecoder_libwebp.cpp
+++ b/src/images/SkImageDecoder_libwebp.cpp
@@ -14,9 +14,10 @@
  * limitations under the License.
  */
 
-#include "SkBitmap.h"
+#include "SkImageDecoder.h"
 #include "SkImageEncoder.h"
 #include "SkColorPriv.h"
+#include "SkScaledBitmapSampler.h"
 #include "SkStream.h"
 #include "SkTemplates.h"
 #include "SkUtils.h"
@@ -31,9 +32,299 @@
 extern "C" {
 // If moving libwebp out of skia source tree, path for webp headers must be
 // updated accordingly. Here, we enforce using local copy in webp sub-directory.
+#include "webp/decode.h"
 #include "webp/encode.h"
 }
 
+// this enables timing code to report milliseconds for a decode
+//#define TIME_DECODE
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+// Define VP8 I/O on top of Skia stream
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+static const size_t WEBP_VP8_HEADER_SIZE = 64;
+static const size_t WEBP_IDECODE_BUFFER_SZ = (1 << 16);
+
+// Parse headers of RIFF container, and check for valid Webp (VP8) content.
+static bool webp_parse_header(SkStream* stream, int* width, int* height, int* alpha) {
+    unsigned char buffer[WEBP_VP8_HEADER_SIZE];
+    size_t bytesToRead = WEBP_VP8_HEADER_SIZE;
+    size_t totalBytesRead = 0;
+    do {
+        unsigned char* dst = buffer + totalBytesRead;
+        const size_t bytesRead = stream->read(dst, bytesToRead);
+        if (0 == bytesRead) {
+            SkASSERT(stream->isAtEnd());
+            break;
+        }
+        bytesToRead -= bytesRead;
+        totalBytesRead += bytesRead;
+        SkASSERT(bytesToRead + totalBytesRead == WEBP_VP8_HEADER_SIZE);
+    } while (!stream->isAtEnd() && bytesToRead > 0);
+
+    WebPBitstreamFeatures features;
+    VP8StatusCode status = WebPGetFeatures(buffer, totalBytesRead, &features);
+    if (VP8_STATUS_OK != status) {
+        return false; // Invalid WebP file.
+    }
+    *width = features.width;
+    *height = features.height;
+    *alpha = features.has_alpha;
+
+    // sanity check for image size that's about to be decoded.
+    {
+        int64_t size = sk_64_mul(*width, *height);
+        if (!sk_64_isS32(size)) {
+            return false;
+        }
+        // now check that if we are 4-bytes per pixel, we also don't overflow
+        if (sk_64_asS32(size) > (0x7FFFFFFF >> 2)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+class SkWEBPImageDecoder: public SkImageDecoder {
+public:
+    SkWEBPImageDecoder() {
+        fOrigWidth = 0;
+        fOrigHeight = 0;
+        fHasAlpha = 0;
+    }
+
+    Format getFormat() const override {
+        return kWEBP_Format;
+    }
+
+protected:
+    Result onDecode(SkStream* stream, SkBitmap* bm, Mode) override;
+
+private:
+    /**
+     *  Called when determining the output config to request to webp.
+     *  If the image does not have alpha, there is no need to premultiply.
+     *  If the caller wants unpremultiplied colors, that is respected.
+     */
+    bool shouldPremultiply() const {
+        return SkToBool(fHasAlpha) && !this->getRequireUnpremultipliedColors();
+    }
+
+    bool setDecodeConfig(SkBitmap* decodedBitmap, int width, int height);
+
+    SkAutoTDelete<SkStream> fInputStream;
+    int fOrigWidth;
+    int fOrigHeight;
+    int fHasAlpha;
+
+    typedef SkImageDecoder INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+#ifdef TIME_DECODE
+
+#include "SkTime.h"
+
+class AutoTimeMillis {
+public:
+    AutoTimeMillis(const char label[]) :
+        fLabel(label) {
+        if (nullptr == fLabel) {
+            fLabel = "";
+        }
+        fNow = SkTime::GetMSecs();
+    }
+    ~AutoTimeMillis() {
+        SkDebugf("---- Time (ms): %s %d\n", fLabel, SkTime::GetMSecs() - fNow);
+    }
+private:
+    const char* fLabel;
+    SkMSec fNow;
+};
+
+#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 void print_webp_error(const SkBitmap& bm, const char msg[]) {
+    SkDEBUGF(("libwebp error %s [%d %d]", msg, bm.width(), bm.height()));
+}
+
+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();
+
+    if (ct == kN32_SkColorType) {
+        #if SK_PMCOLOR_BYTE_ORDER(B,G,R,A)
+            mode = premultiply ? MODE_bgrA : MODE_BGRA;
+        #elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A)
+            mode = premultiply ? MODE_rgbA : MODE_RGBA;
+        #else
+            #error "Skia uses BGRA or RGBA byte order"
+        #endif
+    } else if (ct == kARGB_4444_SkColorType) {
+        mode = premultiply ? MODE_rgbA_4444 : MODE_RGBA_4444;
+    } else if (ct == kRGB_565_SkColorType) {
+        mode = MODE_RGB_565;
+    }
+    SkASSERT(MODE_LAST != mode);
+    return mode;
+}
+
+// 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(nullptr, 0, config);
+    if (nullptr == idec) {
+        WebPFreeDecBuffer(&config->output);
+        return false;
+    }
+
+    if (!stream->rewind()) {
+        SkDebugf("Failed to rewind webp stream!");
+        return false;
+    }
+    const size_t readBufferSize = stream->hasLength() ?
+            SkTMin(stream->getLength(), WEBP_IDECODE_BUFFER_SZ) : WEBP_IDECODE_BUFFER_SZ;
+    SkAutoTMalloc<unsigned char> srcStorage(readBufferSize);
+    unsigned char* input = srcStorage.get();
+    if (nullptr == input) {
+        WebPIDelete(idec);
+        WebPFreeDecBuffer(&config->output);
+        return false;
+    }
+
+    bool success = true;
+    VP8StatusCode status = VP8_STATUS_SUSPENDED;
+    do {
+        const size_t bytesRead = stream->read(input, readBufferSize);
+        if (0 == bytesRead) {
+            success = false;
+            break;
+        }
+
+        status = WebPIAppend(idec, input, bytesRead);
+        if (VP8_STATUS_OK != status && VP8_STATUS_SUSPENDED != status) {
+            success = false;
+            break;
+        }
+    } while (VP8_STATUS_OK != status);
+    srcStorage.reset();
+    WebPIDelete(idec);
+    WebPFreeDecBuffer(&config->output);
+
+    return success;
+}
+
+static bool webp_get_config_resize(WebPDecoderConfig* config,
+                                   SkBitmap* decodedBitmap,
+                                   int width, int height, bool premultiply) {
+    WEBP_CSP_MODE mode = webp_decode_mode(decodedBitmap, premultiply);
+    if (MODE_LAST == mode) {
+        return false;
+    }
+
+    if (0 == WebPInitDecoderConfig(config)) {
+        return false;
+    }
+
+    config->output.colorspace = mode;
+    config->output.u.RGBA.rgba = (uint8_t*)decodedBitmap->getPixels();
+    config->output.u.RGBA.stride = (int) decodedBitmap->rowBytes();
+    config->output.u.RGBA.size = decodedBitmap->getSize();
+    config->output.is_external_memory = 1;
+
+    if (width != decodedBitmap->width() || height != decodedBitmap->height()) {
+        config->options.use_scaling = 1;
+        config->options.scaled_width = decodedBitmap->width();
+        config->options.scaled_height = decodedBitmap->height();
+    }
+
+    return true;
+}
+
+bool SkWEBPImageDecoder::setDecodeConfig(SkBitmap* decodedBitmap, int width, int height) {
+    SkColorType colorType = this->getPrefColorType(k32Bit_SrcDepth, SkToBool(fHasAlpha));
+
+    // YUV converter supports output in RGB565, RGBA4444 and RGBA8888 formats.
+    if (fHasAlpha) {
+        if (colorType != kARGB_4444_SkColorType) {
+            colorType = kN32_SkColorType;
+        }
+    } else {
+        if (colorType != kRGB_565_SkColorType && colorType != kARGB_4444_SkColorType) {
+            colorType = kN32_SkColorType;
+        }
+    }
+
+    SkAlphaType alphaType = kOpaque_SkAlphaType;
+    if (SkToBool(fHasAlpha)) {
+        if (this->getRequireUnpremultipliedColors()) {
+            alphaType = kUnpremul_SkAlphaType;
+        } else {
+            alphaType = kPremul_SkAlphaType;
+        }
+    }
+    return decodedBitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType));
+}
+
+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 kFailure;
+    }
+    this->fHasAlpha = hasAlpha;
+
+    const int sampleSize = this->getSampleSize();
+    SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize);
+    if (!setDecodeConfig(decodedBitmap, sampler.scaledWidth(),
+                         sampler.scaledHeight())) {
+        return kFailure;
+    }
+
+    // If only bounds are requested, done
+    if (SkImageDecoder::kDecodeBounds_Mode == mode) {
+        return kSuccess;
+    }
+
+    if (!this->allocPixelRef(decodedBitmap, nullptr)) {
+        return return_failure(*decodedBitmap, "allocPixelRef");
+    }
+
+    SkAutoLockPixels alp(*decodedBitmap);
+
+    WebPDecoderConfig config;
+    if (!webp_get_config_resize(&config, decodedBitmap, origWidth, origHeight,
+                                this->shouldPremultiply())) {
+        return kFailure;
+    }
+
+    // Decode the WebP image data stream using WebP incremental decoding.
+    return webp_idecode(stream, &config) ? kSuccess : kFailure;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
 #include "SkUnPreMultiply.h"
 
 typedef void (*ScanlineImporter)(const uint8_t* in, uint8_t* out, int width,
@@ -237,11 +528,32 @@
 
 
 ///////////////////////////////////////////////////////////////////////////////
+DEFINE_DECODER_CREATOR(WEBPImageDecoder);
 DEFINE_ENCODER_CREATOR(WEBPImageEncoder);
 ///////////////////////////////////////////////////////////////////////////////
 
+static SkImageDecoder* sk_libwebp_dfactory(SkStreamRewindable* stream) {
+    int width, height, hasAlpha;
+    if (!webp_parse_header(stream, &width, &height, &hasAlpha)) {
+        return nullptr;
+    }
+
+    // Magic matches, call decoder
+    return new SkWEBPImageDecoder;
+}
+
+static SkImageDecoder::Format get_format_webp(SkStreamRewindable* stream) {
+    int width, height, hasAlpha;
+    if (webp_parse_header(stream, &width, &height, &hasAlpha)) {
+        return SkImageDecoder::kWEBP_Format;
+    }
+    return SkImageDecoder::kUnknown_Format;
+}
+
 static SkImageEncoder* sk_libwebp_efactory(SkImageEncoder::Type t) {
     return (SkImageEncoder::kWEBP_Type == t) ? new SkWEBPImageEncoder : nullptr;
 }
 
+static SkImageDecoder_DecodeReg gDReg(sk_libwebp_dfactory);
+static SkImageDecoder_FormatReg gFormatReg(get_format_webp);
 static SkImageEncoder_EncodeReg gEReg(sk_libwebp_efactory);