Upstream changes from Android

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

Author: djsollen@google.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk@13600 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/images/SkImageDecoder_libwebp.cpp b/src/images/SkImageDecoder_libwebp.cpp
index 05925d0..49d5bd1 100644
--- a/src/images/SkImageDecoder_libwebp.cpp
+++ b/src/images/SkImageDecoder_libwebp.cpp
@@ -444,6 +444,8 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
+#include "SkUnPreMultiply.h"
+
 typedef void (*ScanlineImporter)(const uint8_t* in, uint8_t* out, int width,
                                  const SkPMColor* SK_RESTRICT ctable);
 
@@ -459,6 +461,31 @@
   }
 }
 
+static void ARGB_8888_To_RGBA(const uint8_t* in, uint8_t* rgb, int width,
+                              const SkPMColor*) {
+  const uint32_t* SK_RESTRICT src = (const uint32_t*)in;
+  const SkUnPreMultiply::Scale* SK_RESTRICT table =
+      SkUnPreMultiply::GetScaleTable();
+  for (int i = 0; i < width; ++i) {
+      const uint32_t c = *src++;
+      uint8_t a = SkGetPackedA32(c);
+      uint8_t r = SkGetPackedR32(c);
+      uint8_t g = SkGetPackedG32(c);
+      uint8_t b = SkGetPackedB32(c);
+      if (0 != a && 255 != a) {
+        SkUnPreMultiply::Scale scale = table[a];
+        r = SkUnPreMultiply::ApplyScale(scale, r);
+        g = SkUnPreMultiply::ApplyScale(scale, g);
+        b = SkUnPreMultiply::ApplyScale(scale, b);
+      }
+      rgb[0] = r;
+      rgb[1] = g;
+      rgb[2] = b;
+      rgb[3] = a;
+      rgb += 4;
+  }
+}
+
 static void RGB_565_To_RGB(const uint8_t* in, uint8_t* rgb, int width,
                            const SkPMColor*) {
   const uint16_t* SK_RESTRICT src = (const uint16_t*)in;
@@ -483,6 +510,31 @@
   }
 }
 
+static void ARGB_4444_To_RGBA(const uint8_t* in, uint8_t* rgb, int width,
+                              const SkPMColor*) {
+  const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)in;
+  const SkUnPreMultiply::Scale* SK_RESTRICT table =
+      SkUnPreMultiply::GetScaleTable();
+  for (int i = 0; i < width; ++i) {
+      const SkPMColor16 c = *src++;
+      uint8_t a = SkPacked4444ToA32(c);
+      uint8_t r = SkPacked4444ToR32(c);
+      uint8_t g = SkPacked4444ToG32(c);
+      uint8_t b = SkPacked4444ToB32(c);
+      if (0 != a && 255 != a) {
+        SkUnPreMultiply::Scale scale = table[a];
+        r = SkUnPreMultiply::ApplyScale(scale, r);
+        g = SkUnPreMultiply::ApplyScale(scale, g);
+        b = SkUnPreMultiply::ApplyScale(scale, b);
+      }
+      rgb[0] = r;
+      rgb[1] = g;
+      rgb[2] = b;
+      rgb[3] = a;
+      rgb += 4;
+  }
+}
+
 static void Index8_To_RGB(const uint8_t* in, uint8_t* rgb, int width,
                           const SkPMColor* SK_RESTRICT ctable) {
   const uint8_t* SK_RESTRICT src = (const uint8_t*)in;
@@ -495,15 +547,31 @@
   }
 }
 
-static ScanlineImporter ChooseImporter(const SkBitmap::Config& config) {
+static ScanlineImporter ChooseImporter(const SkBitmap::Config& config,
+                                       bool  hasAlpha,
+                                       int*  bpp) {
     switch (config) {
         case SkBitmap::kARGB_8888_Config:
-            return ARGB_8888_To_RGB;
-        case SkBitmap::kRGB_565_Config:
-            return RGB_565_To_RGB;
+            if (hasAlpha) {
+                *bpp = 4;
+                return ARGB_8888_To_RGBA;
+            } else {
+                *bpp = 3;
+                return ARGB_8888_To_RGB;
+            }
         case SkBitmap::kARGB_4444_Config:
-            return ARGB_4444_To_RGB;
+            if (hasAlpha) {
+                *bpp = 4;
+                return ARGB_4444_To_RGBA;
+            } else {
+                *bpp = 3;
+                return ARGB_4444_To_RGB;
+            }
+        case SkBitmap::kRGB_565_Config:
+            *bpp = 3;
+            return RGB_565_To_RGB;
         case SkBitmap::kIndex8_Config:
+            *bpp = 3;
             return Index8_To_RGB;
         default:
             return NULL;
@@ -527,10 +595,16 @@
 bool SkWEBPImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bm,
                                   int quality) {
     const SkBitmap::Config config = bm.config();
-    const ScanlineImporter scanline_import = ChooseImporter(config);
+    const bool hasAlpha = !bm.isOpaque();
+    int bpp = -1;
+    const ScanlineImporter scanline_import = ChooseImporter(config, hasAlpha,
+                                                            &bpp);
     if (NULL == scanline_import) {
         return false;
     }
+    if (-1 == bpp) {
+        return false;
+    }
 
     SkAutoLockPixels alp(bm);
     SkAutoLockColors ctLocker;
@@ -552,7 +626,7 @@
 
     const SkPMColor* colors = ctLocker.lockColors(bm);
     const uint8_t* src = (uint8_t*)bm.getPixels();
-    const int rgbStride = pic.width * 3;
+    const int rgbStride = pic.width * bpp;
 
     // Import (for each scanline) the bit-map image (in appropriate color-space)
     // to RGB color space.
@@ -562,7 +636,12 @@
                         pic.width, colors);
     }
 
-    bool ok = SkToBool(WebPPictureImportRGB(&pic, rgb, rgbStride));
+    bool ok;
+    if (bpp == 3) {
+        ok = SkToBool(WebPPictureImportRGB(&pic, rgb, rgbStride));
+    } else {
+        ok = SkToBool(WebPPictureImportRGBA(&pic, rgb, rgbStride));
+    }
     delete[] rgb;
 
     ok = ok && WebPEncode(&webp_config, &pic);