Refactor pixel conversion: premul and unpremul

Just going for simpler and more code sharing.

BUG=skia:

Change-Id: I84c20cd4dbb6950f7b4d0bc659c4b3b5a2af201c
Reviewed-on: https://skia-review.googlesource.com/8287
Reviewed-by: Mike Klein <mtklein@chromium.org>
Commit-Queue: Matt Sarett <msarett@google.com>
diff --git a/src/core/SkConfig8888.cpp b/src/core/SkConfig8888.cpp
index cae2eef..59360e2 100644
--- a/src/core/SkConfig8888.cpp
+++ b/src/core/SkConfig8888.cpp
@@ -14,9 +14,10 @@
 #include "SkDither.h"
 #include "SkImageInfoPriv.h"
 #include "SkMathPriv.h"
+#include "SkOpts.h"
 #include "SkPM4fPriv.h"
 #include "SkRasterPipeline.h"
-#include "SkUnPreMultiply.h"
+#include "SkUnPreMultiplyPriv.h"
 
 // Fast Path 1: The memcpy() case.
 static inline bool can_memcpy(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) {
@@ -36,6 +37,53 @@
            SkColorSpace::Equals(dstInfo.colorSpace(), srcInfo.colorSpace());
 }
 
+enum AlphaVerb {
+    kNothing_AlphaVerb,
+    kPremul_AlphaVerb,
+    kUnpremul_AlphaVerb,
+};
+
+template <bool kSwapRB>
+static void wrap_unpremultiply(uint32_t* dst, const void* src, int count) {
+    SkUnpremultiplyRow<kSwapRB>(dst, (const uint32_t*) src, count);
+}
+
+// Fast Path 2: Simple swizzles and premuls.
+void swizzle_and_multiply(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
+                          const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB) {
+    void (*proc)(uint32_t* dst, const void* src, int count);
+    const bool swapRB = dstInfo.colorType() != srcInfo.colorType();
+    AlphaVerb alphaVerb = kNothing_AlphaVerb;
+    if (kPremul_SkAlphaType == dstInfo.alphaType() &&
+        kUnpremul_SkAlphaType == srcInfo.alphaType())
+    {
+        alphaVerb = kPremul_AlphaVerb;
+    } else if (kUnpremul_SkAlphaType == dstInfo.alphaType() &&
+               kPremul_SkAlphaType == srcInfo.alphaType()) {
+        alphaVerb = kUnpremul_AlphaVerb;
+    }
+
+    switch (alphaVerb) {
+        case kNothing_AlphaVerb:
+            // If we do not need to swap or multiply, we should hit the memcpy case.
+            SkASSERT(swapRB);
+            proc = SkOpts::RGBA_to_BGRA;
+            break;
+        case kPremul_AlphaVerb:
+            proc = swapRB ? SkOpts::RGBA_to_bgrA : SkOpts::RGBA_to_rgbA;
+            break;
+        case kUnpremul_AlphaVerb:
+            proc = swapRB ? wrap_unpremultiply<true> : wrap_unpremultiply<false>;
+            break;
+    }
+
+    for (int y = 0; y < dstInfo.height(); y++) {
+        proc((uint32_t*) dstPixels, srcPixels, dstInfo.width());
+        dstPixels = SkTAddOffset<void>(dstPixels, dstRB);
+        srcPixels = SkTAddOffset<const void>(srcPixels, srcRB);
+    }
+}
+
 // Default: Use the pipeline.
 static bool copy_pipeline_pixels(const SkImageInfo& dstInfo, void* dstRow, size_t dstRB,
                                  const SkImageInfo& srcInfo, const void* srcRow, size_t srcRB,
@@ -114,107 +162,6 @@
     return true;
 }
 
-enum AlphaVerb {
-    kNothing_AlphaVerb,
-    kPremul_AlphaVerb,
-    kUnpremul_AlphaVerb,
-};
-
-template <bool doSwapRB, AlphaVerb doAlpha> uint32_t convert32(uint32_t c) {
-    if (doSwapRB) {
-        c = SkSwizzle_RB(c);
-    }
-
-    // Lucky for us, in both RGBA and BGRA, the alpha component is always in the same place, so
-    // we can perform premul or unpremul the same way without knowing the swizzles for RGB.
-    switch (doAlpha) {
-        case kNothing_AlphaVerb:
-            // no change
-            break;
-        case kPremul_AlphaVerb:
-            c = SkPreMultiplyARGB(SkGetPackedA32(c), SkGetPackedR32(c),
-                                  SkGetPackedG32(c), SkGetPackedB32(c));
-            break;
-        case kUnpremul_AlphaVerb:
-            c = SkUnPreMultiply::UnPreMultiplyPreservingByteOrder(c);
-            break;
-    }
-    return c;
-}
-
-template <bool doSwapRB, AlphaVerb doAlpha>
-void convert32_row(uint32_t* dst, const uint32_t* src, int count) {
-    // This has to be correct if src == dst (but not partial overlap)
-    for (int i = 0; i < count; ++i) {
-        dst[i] = convert32<doSwapRB, doAlpha>(src[i]);
-    }
-}
-
-static bool is_32bit_colortype(SkColorType ct) {
-    return kRGBA_8888_SkColorType == ct || kBGRA_8888_SkColorType == ct;
-}
-
-static AlphaVerb compute_AlphaVerb(SkAlphaType src, SkAlphaType dst) {
-    SkASSERT(kUnknown_SkAlphaType != src);
-    SkASSERT(kUnknown_SkAlphaType != dst);
-
-    if (kOpaque_SkAlphaType == src || kOpaque_SkAlphaType == dst || src == dst) {
-        return kNothing_AlphaVerb;
-    }
-    if (kPremul_SkAlphaType == dst) {
-        SkASSERT(kUnpremul_SkAlphaType == src);
-        return kPremul_AlphaVerb;
-    } else {
-        SkASSERT(kPremul_SkAlphaType == src);
-        SkASSERT(kUnpremul_SkAlphaType == dst);
-        return kUnpremul_AlphaVerb;
-    }
-}
-
-bool SkSrcPixelInfo::convertPixelsTo(SkDstPixelInfo* dst, int width, int height) const {
-    SkASSERT(width > 0 && height > 0);
-
-    if (!is_32bit_colortype(fColorType) || !is_32bit_colortype(dst->fColorType)) {
-        return false;
-    }
-
-    void (*proc)(uint32_t* dst, const uint32_t* src, int count);
-    AlphaVerb doAlpha = compute_AlphaVerb(fAlphaType, dst->fAlphaType);
-    bool doSwapRB = fColorType != dst->fColorType;
-
-    switch (doAlpha) {
-        case kNothing_AlphaVerb:
-            SkASSERT(doSwapRB);
-            proc = convert32_row<true, kNothing_AlphaVerb>;
-            break;
-        case kPremul_AlphaVerb:
-            if (doSwapRB) {
-                proc = convert32_row<true, kPremul_AlphaVerb>;
-            } else {
-                proc = convert32_row<false, kPremul_AlphaVerb>;
-            }
-            break;
-        case kUnpremul_AlphaVerb:
-            if (doSwapRB) {
-                proc = convert32_row<true, kUnpremul_AlphaVerb>;
-            } else {
-                proc = convert32_row<false, kUnpremul_AlphaVerb>;
-            }
-            break;
-    }
-
-    uint32_t* dstP = static_cast<uint32_t*>(dst->fPixels);
-    const uint32_t* srcP = static_cast<const uint32_t*>(fPixels);
-    size_t srcInc = fRowBytes >> 2;
-    size_t dstInc = dst->fRowBytes >> 2;
-    for (int y = 0; y < height; ++y) {
-        proc(dstP, srcP, width);
-        dstP += dstInc;
-        srcP += srcInc;
-    }
-    return true;
-}
-
 static bool extract_alpha(void* dst, size_t dstRB, const void* src, size_t srcRB,
                           const SkImageInfo& srcInfo, SkColorTable* ctable) {
     uint8_t* SK_RESTRICT dst8 = (uint8_t*)dst;
@@ -358,21 +305,10 @@
     const bool isColorAware = dstInfo.colorSpace();
     SkASSERT(srcInfo.colorSpace() || !isColorAware);
 
-    // Handle fancy alpha swizzling if both are ARGB32
+    // Fast Path 2: Simple swizzles and premuls.
     if (4 == srcInfo.bytesPerPixel() && 4 == dstInfo.bytesPerPixel() && !isColorAware) {
-        SkDstPixelInfo dstPI;
-        dstPI.fColorType = dstInfo.colorType();
-        dstPI.fAlphaType = dstInfo.alphaType();
-        dstPI.fPixels = dstPixels;
-        dstPI.fRowBytes = dstRB;
-
-        SkSrcPixelInfo srcPI;
-        srcPI.fColorType = srcInfo.colorType();
-        srcPI.fAlphaType = srcInfo.alphaType();
-        srcPI.fPixels = srcPixels;
-        srcPI.fRowBytes = srcRB;
-
-        return srcPI.convertPixelsTo(&dstPI, width, height);
+        swizzle_and_multiply(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB);
+        return true;
     }
 
     if (isColorAware && optimized_color_xform(dstInfo, srcInfo)) {
diff --git a/src/core/SkConfig8888.h b/src/core/SkConfig8888.h
index 3544cbe..9c1ff4a 100644
--- a/src/core/SkConfig8888.h
+++ b/src/core/SkConfig8888.h
@@ -23,18 +23,6 @@
                            SkColorTable* srcCTable = nullptr);
 };
 
-struct SkDstPixelInfo : SkPixelInfo {
-    void* fPixels;
-};
-
-struct SkSrcPixelInfo : SkPixelInfo {
-    const void* fPixels;
-
-    // Guaranteed to work even if src.fPixels and dst.fPixels are the same
-    // (but not if they overlap partially)
-    bool convertPixelsTo(SkDstPixelInfo* dst, int width, int height) const;
-};
-
 static inline void SkRectMemcpy(void* dst, size_t dstRB, const void* src, size_t srcRB,
                                 size_t bytesPerRow, int rowCount) {
     SkASSERT(bytesPerRow <= dstRB);
diff --git a/src/core/SkUnPreMultiplyPriv.h b/src/core/SkUnPreMultiplyPriv.h
new file mode 100644
index 0000000..073e239
--- /dev/null
+++ b/src/core/SkUnPreMultiplyPriv.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkUnPreMultiplyPriv_DEFINED
+#define SkUnPreMultiplyPriv_DEFINED
+
+#include "SkColor.h"
+
+template <bool kSwapRB>
+void SkUnpremultiplyRow(uint32_t* dst, const uint32_t* src, int count) {
+    const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
+
+    for (int i = 0; i < count; i++) {
+        uint32_t c = *src++;
+        uint8_t r, g, b, a;
+        if (kSwapRB) {
+            r = (c >> 16) & 0xFF;
+            g = (c >>  8) & 0xFF;
+            b = (c >>  0) & 0xFF;
+            a = (c >> 24) & 0xFF;
+        } else {
+            r = (c >>  0) & 0xFF;
+            g = (c >>  8) & 0xFF;
+            b = (c >> 16) & 0xFF;
+            a = (c >> 24) & 0xFF;
+        }
+
+        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);
+        }
+
+        *dst++ = (r << 0) | (g << 8) | (b << 16) | (a << 24);
+    }
+}
+
+#endif
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index b5586b4..4b67d54 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -21,6 +21,7 @@
 
 #include "SkConfig8888.h"
 #include "SkGrPriv.h"
+#include "SkUnPreMultiplyPriv.h"
 
 #include "effects/GrConfigConversionEffect.h"
 #include "text/GrTextBlobCache.h"
@@ -226,21 +227,20 @@
 
 bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes,
                           const void* inPixels, size_t outRowBytes, void* outPixels) {
-    SkSrcPixelInfo srcPI;
-    if (!GrPixelConfigToColorType(srcConfig, &srcPI.fColorType)) {
+    SkColorType colorType;
+    if (!GrPixelConfigToColorType(srcConfig, &colorType) ||
+        4 != SkColorTypeBytesPerPixel(colorType))
+    {
         return false;
     }
-    srcPI.fAlphaType = kUnpremul_SkAlphaType;
-    srcPI.fPixels = inPixels;
-    srcPI.fRowBytes = inRowBytes;
 
-    SkDstPixelInfo dstPI;
-    dstPI.fColorType = srcPI.fColorType;
-    dstPI.fAlphaType = kPremul_SkAlphaType;
-    dstPI.fPixels = outPixels;
-    dstPI.fRowBytes = outRowBytes;
+    for (int y = 0; y < height; y++) {
+        SkOpts::RGBA_to_rgbA((uint32_t*) outPixels, inPixels, width);
+        outPixels = SkTAddOffset<void>(outPixels, outRowBytes);
+        inPixels = SkTAddOffset<const void>(inPixels, inRowBytes);
+    }
 
-    return srcPI.convertPixelsTo(&dstPI, width, height);
+    return true;
 }
 
 bool GrContext::writeSurfacePixels(GrSurface* surface, SkColorSpace* dstColorSpace,
@@ -522,21 +522,17 @@
 
     // Perform umpremul conversion if we weren't able to perform it as a draw.
     if (unpremul) {
-        SkDstPixelInfo dstPI;
-        if (!GrPixelConfigToColorType(dstConfig, &dstPI.fColorType)) {
+        SkColorType colorType;
+        if (!GrPixelConfigToColorType(dstConfig, &colorType) ||
+            4 != SkColorTypeBytesPerPixel(colorType))
+        {
             return false;
         }
-        dstPI.fAlphaType = kUnpremul_SkAlphaType;
-        dstPI.fPixels = buffer;
-        dstPI.fRowBytes = rowBytes;
 
-        SkSrcPixelInfo srcPI;
-        srcPI.fColorType = dstPI.fColorType;
-        srcPI.fAlphaType = kPremul_SkAlphaType;
-        srcPI.fPixels = buffer;
-        srcPI.fRowBytes = rowBytes;
-
-        return srcPI.convertPixelsTo(&dstPI, width, height);
+        for (int y = 0; y < height; y++) {
+            SkUnpremultiplyRow<false>((uint32_t*) buffer, (const uint32_t*) buffer, width);
+            buffer = SkTAddOffset<void>(buffer, rowBytes);
+        }
     }
     return true;
 }
diff --git a/src/images/transform_scanline.h b/src/images/transform_scanline.h
index 6bf3474..d855964 100644
--- a/src/images/transform_scanline.h
+++ b/src/images/transform_scanline.h
@@ -15,6 +15,7 @@
 #include "SkPreConfig.h"
 #include "SkRasterPipeline.h"
 #include "SkUnPreMultiply.h"
+#include "SkUnPreMultiplyPriv.h"
 
 /**
  * Function template for transforming scanlines.
@@ -128,46 +129,12 @@
     }
 }
 
-template <bool kIsRGBA>
-static inline void transform_scanline_unpremultiply(char* SK_RESTRICT dst,
-                                                    const char* SK_RESTRICT src, int width) {
-    const uint32_t* srcP = (const SkPMColor*)src;
-    const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
-
-    for (int i = 0; i < width; i++) {
-        uint32_t c = *srcP++;
-        unsigned r, g, b, a;
-        if (kIsRGBA) {
-            r = (c >>  0) & 0xFF;
-            g = (c >>  8) & 0xFF;
-            b = (c >> 16) & 0xFF;
-            a = (c >> 24) & 0xFF;
-        } else {
-            r = (c >> 16) & 0xFF;
-            g = (c >>  8) & 0xFF;
-            b = (c >>  0) & 0xFF;
-            a = (c >> 24) & 0xFF;
-        }
-
-        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);
-        }
-        *dst++ = r;
-        *dst++ = g;
-        *dst++ = b;
-        *dst++ = a;
-    }
-}
-
 /**
  * Transform from legacy kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
  */
 static inline void transform_scanline_rgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
                                            int width, int, const SkPMColor*) {
-    transform_scanline_unpremultiply<true>(dst, src, width);
+    SkUnpremultiplyRow<false>((uint32_t*) dst, (const uint32_t*) src, width);
 }
 
 /**
@@ -175,7 +142,7 @@
  */
 static inline void transform_scanline_bgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
                                            int width, int, const SkPMColor*) {
-    transform_scanline_unpremultiply<false>(dst, src, width);
+    SkUnpremultiplyRow<true>((uint32_t*) dst, (const uint32_t*) src, width);
 }
 
 template <bool kIsRGBA>