Have SkWuffsCodec speak kRGB_565_SkColorType

This takes the "one pass" code path more often, using less memory, as it
does not have to allocate an intermediate width*height pixel buffer.

Wuffs v0.2 did not support RGB 565 color but Wuffs v0.3 does.

The Codec_AnimatedTransparentGif test passes with skia_use_wuffs true or
false.

Change-Id: Id569fc0bf62e614fa881cb235a9a6a1ca340dcb0
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/329916
Commit-Queue: Leon Scroggins <scroggo@google.com>
Reviewed-by: Leon Scroggins <scroggo@google.com>
diff --git a/src/codec/SkWuffsCodec.cpp b/src/codec/SkWuffsCodec.cpp
index 7c966c3..2f0495c 100644
--- a/src/codec/SkWuffsCodec.cpp
+++ b/src/codec/SkWuffsCodec.cpp
@@ -461,9 +461,6 @@
     if (options.fSubset) {
         return SkCodec::kUnimplemented;
     }
-    if (options.fFrameIndex > 0 && SkColorTypeIsAlwaysOpaque(dstInfo.colorType())) {
-        return SkCodec::kInvalidConversion;
-    }
     SkCodec::Result result = this->seekFrame(WhichDecoder::kIncrDecode, options.fFrameIndex);
     if (result != SkCodec::kSuccess) {
         return result;
@@ -481,6 +478,10 @@
     size_t   bytesPerPixel = 0;
 
     switch (dstInfo.colorType()) {
+        case kRGB_565_SkColorType:
+            pixelFormat = WUFFS_BASE__PIXEL_FORMAT__BGR_565;
+            bytesPerPixel = 2;
+            break;
         case kBGRA_8888_SkColorType:
             pixelFormat = WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL;
             bytesPerPixel = 4;
diff --git a/tests/GifTest.cpp b/tests/GifTest.cpp
index a3541af..12d8108 100644
--- a/tests/GifTest.cpp
+++ b/tests/GifTest.cpp
@@ -535,32 +535,68 @@
         ERRORF(r, "Unexpected image info");
         return;
     }
-    SkBitmap bm;
-    bm.allocPixels(info);
 
-    for (int i = 0; i < 2; i++) {
-        SkColor expectedPixels[2][4] = {
-            { 0xFF800000, 0xFF900000, 0xFFA00000, 0xFFB00000 },
-            { 0xFFC00000, 0xFFD00000, 0xFFE00000, 0xFFF00000 },
-        };
-        if (i > 0) {
-            expectedPixels[1][1] = 0xFF0000FF;
-            expectedPixels[1][3] = 0xFF000055;
-        }
+    for (bool use565 : { false, true }) {
+        SkBitmap bm;
+        bm.allocPixels(use565 ? info.makeColorType(kRGB_565_SkColorType) : info);
 
-        SkCodec::Options options;
-        options.fFrameIndex = i;
-        options.fPriorFrame = (i > 0) ? (i - 1) : SkCodec::kNoFrame;
-        auto result = codec->getPixels(bm.pixmap(), &options);
-        REPORTER_ASSERT(r, result == SkCodec::kSuccess, "Failed to decode frame %i", i);
+        for (int i = 0; i < 2; i++) {
+            SkCodec::Options options;
+            options.fFrameIndex = i;
+            options.fPriorFrame = (i > 0) ? (i - 1) : SkCodec::kNoFrame;
+            auto result = codec->getPixels(bm.pixmap(), &options);
+#ifdef SK_HAS_WUFFS_LIBRARY
+            // No-op. Wuffs' GIF decoder supports animated 565.
+#else
+            if (use565 && i > 0) {
+                // Unsupported. Quoting libgifcodec/SkLibGifCodec.cpp:
+                //
+                // In theory, we might be able to support this, but it's not
+                // clear that it is necessary (Chromium does not decode to 565,
+                // and Android does not decode frames beyond the first).
+                REPORTER_ASSERT(r, result != SkCodec::kSuccess,
+                                "Unexpected success to decode frame %i", i);
+                continue;
+            }
+#endif
+            REPORTER_ASSERT(r, result == SkCodec::kSuccess, "Failed to decode frame %i", i);
 
-        for (int y = 0; y < 2; y++) {
-            for (int x = 0; x < 4; x++) {
-                auto expected = expectedPixels[y][x];
-                auto actual = bm.getColor(x, y);
-                REPORTER_ASSERT(r, actual == expected,
-                                "frame %i, pixel (%i,%i) mismatch! expected: %x actual: %x",
-                                i, x, y, expected, actual);
+            // Per above: the first frame is full of various red pixels.
+            SkColor expectedPixels[2][4] = {
+                { 0xFF800000, 0xFF900000, 0xFFA00000, 0xFFB00000 },
+                { 0xFFC00000, 0xFFD00000, 0xFFE00000, 0xFFF00000 },
+            };
+            if (use565) {
+                // For kRGB_565_SkColorType, copy the red channel's high 3 bits
+                // to its low 3 bits.
+                expectedPixels[0][0] = 0xFF840000;
+                expectedPixels[0][1] = 0xFF940000;
+                expectedPixels[0][2] = 0xFFA50000;
+                expectedPixels[0][3] = 0xFFB50000;
+                expectedPixels[1][0] = 0xFFC60000;
+                expectedPixels[1][1] = 0xFFD60000;
+                expectedPixels[1][2] = 0xFFE70000;
+                expectedPixels[1][3] = 0xFFF70000;
+            }
+            if (i > 0) {
+                // Per above: the second frame overlays a 3x1 rectangle at (1,
+                // 1): light blue, transparent, dark blue.
+                //
+                // Again, for kRGB_565_SkColorType, copy the blue channel's
+                // high 3 bits to its low 3 bits.
+                expectedPixels[1][1] = use565 ? 0xFF0000FF : 0xFF0000FF;
+                expectedPixels[1][3] = use565 ? 0xFF000052 : 0xFF000055;
+            }
+
+            for (int y = 0; y < 2; y++) {
+                for (int x = 0; x < 4; x++) {
+                    auto expected = expectedPixels[y][x];
+                    auto actual = bm.getColor(x, y);
+                    REPORTER_ASSERT(r, actual == expected,
+                                    "use565 %i, frame %i, pixel (%i,%i) "
+                                    "mismatch! expected: %x actual: %x",
+                                    (int)use565, i, x, y, expected, actual);
+                }
             }
         }
     }