Reland "Respect full precision for RGB16 PNGs" (part 3)

This lands the rest of the original CL.
It fixes some flawed logic in SkSwizzler handling Gray8
images.

Original CL:
https://skia-review.googlesource.com/c/7085/

BUG=skia:

CQ_INCLUDE_TRYBOTS=skia.primary:Test-Ubuntu-Clang-GCE-CPU-AVX2-x86_64-Debug-MSAN,Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Release-SKNX_NO_SIMD,Build-Ubuntu-Clang-x86_64-Release-Fast

Change-Id: Ie2f0c545ea474f1872f284dfb286987b6eadf03d
Reviewed-on: https://skia-review.googlesource.com/7320
Reviewed-by: Matt Sarett <msarett@google.com>
Commit-Queue: Matt Sarett <msarett@google.com>
diff --git a/src/codec/SkPngCodec.cpp b/src/codec/SkPngCodec.cpp
index 9f5c8e6..468b0b8 100644
--- a/src/codec/SkPngCodec.cpp
+++ b/src/codec/SkPngCodec.cpp
@@ -420,8 +420,12 @@
             // be created later if we are sampling.  We'll go ahead and allocate
             // enough memory to swizzle if necessary.
         case kSwizzleColor_XformMode: {
-            const size_t bpp = (this->getEncodedInfo().bitsPerPixel() > 32) ? 8 : 4;
-            const size_t colorXformBytes = dstInfo.width() * bpp;
+            const int bitsPerPixel = this->getEncodedInfo().bitsPerPixel();
+
+            // If we have more than 8-bits (per component) of precision, we will keep that
+            // extra precision.  Otherwise, we will swizzle to RGBA_8888 before transforming.
+            const size_t bytesPerPixel = (bitsPerPixel > 32) ? bitsPerPixel / 8 : 4;
+            const size_t colorXformBytes = dstInfo.width() * bytesPerPixel;
             fStorage.reset(colorXformBytes);
             fColorXformSrcRow = fStorage.get();
             break;
@@ -430,10 +434,13 @@
 }
 
 static SkColorSpaceXform::ColorFormat png_select_xform_format(const SkEncodedInfo& info) {
-    // We always use kRGBA because color PNGs are always RGB or RGBA.
-    // TODO (msarett): Support kRGB_U16 inputs as well.
-    if (16 == info.bitsPerComponent() && SkEncodedInfo::kRGBA_Color == info.color()) {
-        return SkColorSpaceXform::kRGBA_U16_BE_ColorFormat;
+    // We use kRGB and kRGBA formats because color PNGs are always RGB or RGBA.
+    if (16 == info.bitsPerComponent()) {
+        if (SkEncodedInfo::kRGBA_Color == info.color()) {
+            return SkColorSpaceXform::kRGBA_U16_BE_ColorFormat;
+        } else if (SkEncodedInfo::kRGB_Color == info.color()) {
+            return SkColorSpaceXform::kRGB_U16_BE_ColorFormat;
+        }
     }
 
     return SkColorSpaceXform::kRGBA_8888_ColorFormat;
@@ -1090,9 +1097,22 @@
         return false;
     }
 
-    // If the image is RGBA and we have a color xform, we can skip the swizzler.
-    const bool skipFormatConversion = this->colorXform() &&
-            SkEncodedInfo::kRGBA_Color == this->getEncodedInfo().color();
+    // If SkColorSpaceXform directly supports the encoded PNG format, we should skip format
+    // conversion in the swizzler (or skip swizzling altogether).
+    bool skipFormatConversion = false;
+    switch (this->getEncodedInfo().color()) {
+        case SkEncodedInfo::kRGB_Color:
+            if (this->getEncodedInfo().bitsPerComponent() != 16) {
+                break;
+            }
+
+            // Fall through
+        case SkEncodedInfo::kRGBA_Color:
+            skipFormatConversion = this->colorXform();
+            break;
+        default:
+            break;
+    }
     if (skipFormatConversion && !options.fSubset) {
         fXformMode = kColorOnly_XformMode;
         return true;