base: allow swizzling WebP Lossless to gray
diff --git a/internal/cgen/base/pixconv-submodule-regular.c b/internal/cgen/base/pixconv-submodule-regular.c
index f8b5891..87dc56d 100644
--- a/internal/cgen/base/pixconv-submodule-regular.c
+++ b/internal/cgen/base/pixconv-submodule-regular.c
@@ -4681,6 +4681,87 @@
 // --------
 
 static uint64_t  //
+wuffs_private_impl__swizzle_y__bgra_nonpremul__src(uint8_t* dst_ptr,
+                                                   size_t dst_len,
+                                                   uint8_t* dst_palette_ptr,
+                                                   size_t dst_palette_len,
+                                                   const uint8_t* src_ptr,
+                                                   size_t src_len) {
+  size_t src_len4 = src_len / 4;
+  size_t len = (dst_len < src_len4) ? dst_len : src_len4;
+  uint8_t* d = dst_ptr;
+  const uint8_t* s = src_ptr;
+  size_t n = len;
+
+  while (n >= 1) {
+    uint32_t s0 =
+        wuffs_base__color_u32_argb_nonpremul__as__color_u32_argb_premul(
+            wuffs_base__peek_u32le__no_bounds_check(s + (0 * 4)));
+    d[0] = wuffs_base__color_u32_argb_premul__as__color_u8_gray(s0);
+
+    s += 1 * 4;
+    d += 1 * 1;
+    n -= 1;
+  }
+
+  return len;
+}
+
+static uint64_t  //
+wuffs_private_impl__swizzle_y__bgra_nonpremul__src_over(
+    uint8_t* dst_ptr,
+    size_t dst_len,
+    uint8_t* dst_palette_ptr,
+    size_t dst_palette_len,
+    const uint8_t* src_ptr,
+    size_t src_len) {
+  size_t src_len4 = src_len / 4;
+  size_t len = (dst_len < src_len4) ? dst_len : src_len4;
+  uint8_t* d = dst_ptr;
+  const uint8_t* s = src_ptr;
+  size_t n = len;
+
+  while (n >= 1) {
+    uint32_t d0 = 0xFF000000 | (0x00010101 * ((uint32_t)(d[0])));
+    uint32_t s0 = wuffs_base__peek_u32le__no_bounds_check(s + (0 * 4));
+    d[0] = wuffs_base__color_u32_argb_premul__as__color_u8_gray(
+        wuffs_private_impl__composite_premul_nonpremul_u32_axxx(d0, s0));
+
+    s += 1 * 4;
+    d += 1 * 1;
+    n -= 1;
+  }
+
+  return len;
+}
+
+static uint64_t  //
+wuffs_private_impl__swizzle_y__bgrx(uint8_t* dst_ptr,
+                                    size_t dst_len,
+                                    uint8_t* dst_palette_ptr,
+                                    size_t dst_palette_len,
+                                    const uint8_t* src_ptr,
+                                    size_t src_len) {
+  size_t src_len4 = src_len / 4;
+  size_t len = (dst_len < src_len4) ? dst_len : src_len4;
+  uint8_t* d = dst_ptr;
+  const uint8_t* s = src_ptr;
+  size_t n = len;
+
+  while (n >= 1) {
+    uint32_t s0 =
+        0xFF000000 | wuffs_base__peek_u32le__no_bounds_check(s + (0 * 4));
+    d[0] = wuffs_base__color_u32_argb_premul__as__color_u8_gray(s0);
+
+    s += 1 * 4;
+    d += 1 * 1;
+    n -= 1;
+  }
+
+  return len;
+}
+
+static uint64_t  //
 wuffs_private_impl__swizzle_y__y_16be(uint8_t* dst_ptr,
                                       size_t dst_len,
                                       uint8_t* dst_palette_ptr,
@@ -5332,6 +5413,15 @@
     wuffs_base__slice_u8 src_palette,
     wuffs_base__pixel_blend blend) {
   switch (dst_pixfmt.repr) {
+    case WUFFS_BASE__PIXEL_FORMAT__Y:
+      switch (blend) {
+        case WUFFS_BASE__PIXEL_BLEND__SRC:
+          return wuffs_private_impl__swizzle_y__bgra_nonpremul__src;
+        case WUFFS_BASE__PIXEL_BLEND__SRC_OVER:
+          return wuffs_private_impl__swizzle_y__bgra_nonpremul__src_over;
+      }
+      return NULL;
+
     case WUFFS_BASE__PIXEL_FORMAT__BGR_565:
       switch (blend) {
         case WUFFS_BASE__PIXEL_BLEND__SRC:
@@ -5611,6 +5701,9 @@
     wuffs_base__slice_u8 src_palette,
     wuffs_base__pixel_blend blend) {
   switch (dst_pixfmt.repr) {
+    case WUFFS_BASE__PIXEL_FORMAT__Y:
+      return wuffs_private_impl__swizzle_y__bgrx;
+
     case WUFFS_BASE__PIXEL_FORMAT__BGR_565:
       return wuffs_private_impl__swizzle_bgr_565__bgrx;
 
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index af4b9b1..da96b1d 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -26302,6 +26302,87 @@
 // --------
 
 static uint64_t  //
+wuffs_private_impl__swizzle_y__bgra_nonpremul__src(uint8_t* dst_ptr,
+                                                   size_t dst_len,
+                                                   uint8_t* dst_palette_ptr,
+                                                   size_t dst_palette_len,
+                                                   const uint8_t* src_ptr,
+                                                   size_t src_len) {
+  size_t src_len4 = src_len / 4;
+  size_t len = (dst_len < src_len4) ? dst_len : src_len4;
+  uint8_t* d = dst_ptr;
+  const uint8_t* s = src_ptr;
+  size_t n = len;
+
+  while (n >= 1) {
+    uint32_t s0 =
+        wuffs_base__color_u32_argb_nonpremul__as__color_u32_argb_premul(
+            wuffs_base__peek_u32le__no_bounds_check(s + (0 * 4)));
+    d[0] = wuffs_base__color_u32_argb_premul__as__color_u8_gray(s0);
+
+    s += 1 * 4;
+    d += 1 * 1;
+    n -= 1;
+  }
+
+  return len;
+}
+
+static uint64_t  //
+wuffs_private_impl__swizzle_y__bgra_nonpremul__src_over(
+    uint8_t* dst_ptr,
+    size_t dst_len,
+    uint8_t* dst_palette_ptr,
+    size_t dst_palette_len,
+    const uint8_t* src_ptr,
+    size_t src_len) {
+  size_t src_len4 = src_len / 4;
+  size_t len = (dst_len < src_len4) ? dst_len : src_len4;
+  uint8_t* d = dst_ptr;
+  const uint8_t* s = src_ptr;
+  size_t n = len;
+
+  while (n >= 1) {
+    uint32_t d0 = 0xFF000000 | (0x00010101 * ((uint32_t)(d[0])));
+    uint32_t s0 = wuffs_base__peek_u32le__no_bounds_check(s + (0 * 4));
+    d[0] = wuffs_base__color_u32_argb_premul__as__color_u8_gray(
+        wuffs_private_impl__composite_premul_nonpremul_u32_axxx(d0, s0));
+
+    s += 1 * 4;
+    d += 1 * 1;
+    n -= 1;
+  }
+
+  return len;
+}
+
+static uint64_t  //
+wuffs_private_impl__swizzle_y__bgrx(uint8_t* dst_ptr,
+                                    size_t dst_len,
+                                    uint8_t* dst_palette_ptr,
+                                    size_t dst_palette_len,
+                                    const uint8_t* src_ptr,
+                                    size_t src_len) {
+  size_t src_len4 = src_len / 4;
+  size_t len = (dst_len < src_len4) ? dst_len : src_len4;
+  uint8_t* d = dst_ptr;
+  const uint8_t* s = src_ptr;
+  size_t n = len;
+
+  while (n >= 1) {
+    uint32_t s0 =
+        0xFF000000 | wuffs_base__peek_u32le__no_bounds_check(s + (0 * 4));
+    d[0] = wuffs_base__color_u32_argb_premul__as__color_u8_gray(s0);
+
+    s += 1 * 4;
+    d += 1 * 1;
+    n -= 1;
+  }
+
+  return len;
+}
+
+static uint64_t  //
 wuffs_private_impl__swizzle_y__y_16be(uint8_t* dst_ptr,
                                       size_t dst_len,
                                       uint8_t* dst_palette_ptr,
@@ -26953,6 +27034,15 @@
     wuffs_base__slice_u8 src_palette,
     wuffs_base__pixel_blend blend) {
   switch (dst_pixfmt.repr) {
+    case WUFFS_BASE__PIXEL_FORMAT__Y:
+      switch (blend) {
+        case WUFFS_BASE__PIXEL_BLEND__SRC:
+          return wuffs_private_impl__swizzle_y__bgra_nonpremul__src;
+        case WUFFS_BASE__PIXEL_BLEND__SRC_OVER:
+          return wuffs_private_impl__swizzle_y__bgra_nonpremul__src_over;
+      }
+      return NULL;
+
     case WUFFS_BASE__PIXEL_FORMAT__BGR_565:
       switch (blend) {
         case WUFFS_BASE__PIXEL_BLEND__SRC:
@@ -27232,6 +27322,9 @@
     wuffs_base__slice_u8 src_palette,
     wuffs_base__pixel_blend blend) {
   switch (dst_pixfmt.repr) {
+    case WUFFS_BASE__PIXEL_FORMAT__Y:
+      return wuffs_private_impl__swizzle_y__bgrx;
+
     case WUFFS_BASE__PIXEL_FORMAT__BGR_565:
       return wuffs_private_impl__swizzle_bgr_565__bgrx;
 
diff --git a/test/c/std/wbmp.c b/test/c/std/wbmp.c
index 0e93f14..1570b6e 100644
--- a/test/c/std/wbmp.c
+++ b/test/c/std/wbmp.c
@@ -374,6 +374,10 @@
       // When updating this list, also consider updating the pixel formats that
       // fuzz/c/std/pixel_swizzler_fuzzer.c exercises and those that
       // wuffs_aux::DecodeImageCallbacks::SelectPixfmt accepts.
+      //
+      // SelectPixfmt excludes WUFFS_BASE__PIXEL_FORMAT__Y, even though we test
+      // it here, since it doesn't support every source pixel format in the
+      // srcs array. See "dst WUFFS_BASE__PIXEL_FORMAT__Y allow-list" below.
       {
           .color = 0xFF000010,
           .pixfmt_repr = WUFFS_BASE__PIXEL_FORMAT__BGR_565,
@@ -406,6 +410,10 @@
           .color = 0x33002233,
           .pixfmt_repr = WUFFS_BASE__PIXEL_FORMAT__RGBA_PREMUL,
       },
+      {
+          .color = 0xFF999999,
+          .pixfmt_repr = WUFFS_BASE__PIXEL_FORMAT__Y,
+      },
   };
 
   const wuffs_base__pixel_blend blends[] = {
@@ -443,6 +451,19 @@
     }
 
     for (size_t d = 0; d < WUFFS_TESTLIB_ARRAY_SIZE(dsts); d++) {
+      // See "dst WUFFS_BASE__PIXEL_FORMAT__Y allow-list" above.
+      if (dsts[d].pixfmt_repr == WUFFS_BASE__PIXEL_FORMAT__Y) {
+        switch (srcs[s].pixfmt_repr) {
+          case WUFFS_BASE__PIXEL_FORMAT__Y:
+          case WUFFS_BASE__PIXEL_FORMAT__Y_16BE:
+          case WUFFS_BASE__PIXEL_FORMAT__BGRX:
+          case WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL:
+            break;
+          default:
+            continue;
+        }
+      }
+
       // Allocate the dst_pixbuf.
       wuffs_base__pixel_config dst_pixcfg = ((wuffs_base__pixel_config){});
       wuffs_base__pixel_config__set(&dst_pixcfg, dsts[d].pixfmt_repr,
@@ -502,6 +523,13 @@
         if (dst_transparency == WUFFS_BASE__PIXEL_ALPHA_TRANSPARENCY__OPAQUE) {
           want_dst_pixel |= 0xFF000000;
         }
+        if (dsts[d].pixfmt_repr == WUFFS_BASE__PIXEL_FORMAT__Y) {
+          want_dst_pixel =
+              0xFF000000 |
+              (0x00010101 *
+               wuffs_base__color_u32_argb_premul__as__color_u8_gray(
+                   want_dst_pixel));
+        }
         wuffs_base__color_u32_argb_premul have_dst_pixel =
             wuffs_base__pixel_buffer__color_u32_at(&dst_pixbuf, width / 2,
                                                    height / 2);