Add test_wuffs_png_decode_filters_round_trip
diff --git a/test/c/std/png.c b/test/c/std/png.c
index ebf0267..d9aafa0 100644
--- a/test/c/std/png.c
+++ b/test/c/std/png.c
@@ -137,7 +137,7 @@
 }
 
 const char*  //
-test_wuffs_png_decode_filters() {
+test_wuffs_png_decode_filters_golden() {
   CHECK_FOCUS(__func__);
 
   uint8_t src_rows[2][12] = {
@@ -243,6 +243,157 @@
   return NULL;
 }
 
+int32_t  //
+apply_png_abs(int32_t x) {
+  return (x < 0) ? -x : +x;
+}
+
+const char*  //
+apply_png_encode_filters(wuffs_base__slice_u8 dst_rows,
+                         size_t width,
+                         size_t height,
+                         size_t filter_distance,
+                         wuffs_base__slice_u8 src_rows) {
+  if ((((width + 1) * height) != dst_rows.len) ||
+      (((width + 1) * height) != src_rows.len)) {
+    return "apply_png_encode_filters: unexpected rows.len";
+  }
+  size_t y;
+  uint8_t* src_prev = NULL;
+  for (y = 0; y < height; y++) {
+    uint8_t filter = src_rows.ptr[(width + 1) * y];
+    dst_rows.ptr[(width + 1) * y] = filter;
+    uint8_t* dst_curr = &dst_rows.ptr[((width + 1) * y) + 1];
+    uint8_t* src_curr = &src_rows.ptr[((width + 1) * y) + 1];
+
+    size_t x;
+    for (x = 0; x < width; x++) {
+      int32_t fa = 0;
+      int32_t fb = 0;
+      int32_t fc = 0;
+      if (x >= filter_distance) {
+        fa = src_curr[x - filter_distance];
+        if (src_prev) {
+          fc = src_prev[x - filter_distance];
+        }
+      }
+      if (src_prev) {
+        fb = src_prev[x];
+      }
+
+      uint8_t prediction = 0;
+      switch (filter) {
+        case 1:
+          prediction = fa;
+          break;
+        case 2:
+          prediction = fb;
+          break;
+        case 3:
+          prediction = (uint8_t)((fa + fb) / 2);
+          break;
+        case 4: {
+          int32_t p = fa + fb - fc;
+          int32_t pa = apply_png_abs(p - fa);
+          int32_t pb = apply_png_abs(p - fb);
+          int32_t pc = apply_png_abs(p - fc);
+          if ((pa <= pb) && (pa <= pc)) {
+            prediction = fa;
+          } else if (pb <= pc) {
+            prediction = fb;
+          } else {
+            prediction = fc;
+          }
+          break;
+        }
+      }
+      dst_curr[x] = src_curr[x] - prediction;
+    }
+    src_prev = src_curr;
+  }
+  return NULL;
+}
+
+const char*  //
+test_wuffs_png_decode_filters_round_trip() {
+  CHECK_FOCUS(__func__);
+
+  uint8_t src_rows[2][96] = {
+      // "ThoughYouMightHearLaughingSpinningSwingingMadlyA"
+      // "crossTheSun/ItsNotAimedAtAnyone/ItsJustEscapingO"
+      {0x54, 0x68, 0x6F, 0x75, 0x67, 0x68, 0x59, 0x6F, 0x75, 0x4D, 0x69, 0x67,
+       0x68, 0x74, 0x48, 0x65, 0x61, 0x72, 0x4C, 0x61, 0x75, 0x67, 0x68, 0x69,
+       0x6E, 0x67, 0x53, 0x70, 0x69, 0x6E, 0x6E, 0x69, 0x6E, 0x67, 0x53, 0x77,
+       0x69, 0x6E, 0x67, 0x69, 0x6E, 0x67, 0x4D, 0x61, 0x64, 0x6C, 0x79, 0x41,
+       0x63, 0x72, 0x6F, 0x73, 0x73, 0x54, 0x68, 0x65, 0x53, 0x75, 0x6E, 0x2F,
+       0x49, 0x74, 0x73, 0x4E, 0x6F, 0x74, 0x41, 0x69, 0x6D, 0x65, 0x64, 0x41,
+       0x74, 0x41, 0x6E, 0x79, 0x6F, 0x6E, 0x65, 0x2F, 0x49, 0x74, 0x73, 0x4A,
+       0x75, 0x73, 0x74, 0x45, 0x73, 0x63, 0x61, 0x70, 0x69, 0x6E, 0x67, 0x4F},
+      // "YesToDanceBeneathTheDiamondSky/WithOneHandWaving"
+      // "Free/SilhouettedByTheSea/CircledByTheCircusSands"
+      {0x59, 0x65, 0x73, 0x54, 0x6F, 0x44, 0x61, 0x6E, 0x63, 0x65, 0x42, 0x65,
+       0x6E, 0x65, 0x61, 0x74, 0x68, 0x54, 0x68, 0x65, 0x44, 0x69, 0x61, 0x6D,
+       0x6F, 0x6E, 0x64, 0x53, 0x6B, 0x79, 0x2F, 0x57, 0x69, 0x74, 0x68, 0x4F,
+       0x6E, 0x65, 0x48, 0x61, 0x6E, 0x64, 0x57, 0x61, 0x76, 0x69, 0x6E, 0x67,
+       0x46, 0x72, 0x65, 0x65, 0x2F, 0x53, 0x69, 0x6C, 0x68, 0x6F, 0x75, 0x65,
+       0x74, 0x74, 0x65, 0x64, 0x42, 0x79, 0x54, 0x68, 0x65, 0x53, 0x65, 0x61,
+       0x2F, 0x43, 0x69, 0x72, 0x63, 0x6C, 0x65, 0x64, 0x42, 0x79, 0x54, 0x68,
+       0x65, 0x43, 0x69, 0x72, 0x63, 0x75, 0x73, 0x53, 0x61, 0x6E, 0x64, 0x73},
+  };
+
+  wuffs_png__decoder dec;
+  CHECK_STATUS("initialize", wuffs_png__decoder__initialize(
+                                 &dec, sizeof dec, WUFFS_VERSION,
+                                 WUFFS_INITIALIZE__DEFAULT_OPTIONS));
+
+  memcpy(g_src_slice_u8.ptr + (97 * 0) + 1, src_rows[0], 96);
+  memcpy(g_src_slice_u8.ptr + (97 * 1) + 1, src_rows[1], 96);
+
+  int filter;
+  for (filter = 1; filter <= 4; filter++) {
+    int filter_distance;
+    for (filter_distance = 1; filter_distance <= 8; filter_distance++) {
+      if ((filter_distance == 5) || (filter_distance == 7)) {
+        continue;
+      }
+      // For the top row, the Paeth filter (4) is equivalent to the Sub filter
+      // (1), but the Paeth implementation is simpler if it can assume that
+      // there is a previous row.
+      uint8_t top_row_filter = (filter != 4) ? filter : 1;
+
+      g_src_slice_u8.ptr[97 * 0] = top_row_filter;
+      g_src_slice_u8.ptr[97 * 1] = filter;
+
+      CHECK_STRING(apply_png_encode_filters(
+          wuffs_base__make_slice_u8(g_work_slice_u8.ptr, 97 * 2), 96, 2,
+          filter_distance,
+          wuffs_base__make_slice_u8(g_src_slice_u8.ptr, 97 * 2)));
+
+      CHECK_STRING(do_wuffs_png_swizzle(
+          &dec, 96, 2, filter_distance, g_have_slice_u8,
+          wuffs_base__make_slice_u8(g_work_slice_u8.ptr, 97 * 2)));
+
+      wuffs_base__io_buffer have =
+          wuffs_base__ptr_u8__reader(g_have_slice_u8.ptr, 96 * 2, true);
+      have.meta.ri = have.meta.wi;
+
+      memcpy(g_want_slice_u8.ptr + (96 * 0), src_rows[0], 96);
+      memcpy(g_want_slice_u8.ptr + (96 * 1), src_rows[1], 96);
+
+      wuffs_base__io_buffer want =
+          wuffs_base__ptr_u8__reader(g_want_slice_u8.ptr, 96 * 2, true);
+      want.meta.ri = want.meta.wi;
+
+      char prefix_buf[256];
+      sprintf(prefix_buf, "filter=%d, filter_distance=%d ", filter,
+              filter_distance);
+      CHECK_STRING(check_io_buffers_equal(prefix_buf, &have, &want));
+    }
+  }
+
+  return NULL;
+}
+
 const char*  //
 test_wuffs_png_decode_frame_config() {
   CHECK_FOCUS(__func__);
@@ -538,7 +689,8 @@
 
 proc g_tests[] = {
 
-    test_wuffs_png_decode_filters,
+    test_wuffs_png_decode_filters_golden,
+    test_wuffs_png_decode_filters_round_trip,
     test_wuffs_png_decode_frame_config,
     test_wuffs_png_decode_interface,