Spin out std/png/decode_filter_fallback.wuffs
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index a81ed39..ab9770c 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -29825,17 +29825,6 @@
 
 // ---------------- Private Function Prototypes
 
-static wuffs_base__status
-wuffs_png__decoder__decode_plte(
-    wuffs_png__decoder* self,
-    wuffs_base__io_buffer* a_src);
-
-static wuffs_base__status
-wuffs_png__decoder__filter_and_swizzle(
-    wuffs_png__decoder* self,
-    wuffs_base__pixel_buffer* a_dst,
-    wuffs_base__slice_u8 a_workbuf);
-
 static wuffs_base__empty_struct
 wuffs_png__decoder__filter_1(
     wuffs_png__decoder* self,
@@ -29859,6 +29848,17 @@
     wuffs_base__slice_u8 a_curr,
     wuffs_base__slice_u8 a_prev);
 
+static wuffs_base__status
+wuffs_png__decoder__decode_plte(
+    wuffs_png__decoder* self,
+    wuffs_base__io_buffer* a_src);
+
+static wuffs_base__status
+wuffs_png__decoder__filter_and_swizzle(
+    wuffs_png__decoder* self,
+    wuffs_base__pixel_buffer* a_dst,
+    wuffs_base__slice_u8 a_workbuf);
+
 // ---------------- VTables
 
 const wuffs_base__image_decoder__func_ptrs
@@ -29980,6 +29980,140 @@
 
 // ---------------- Function Implementations
 
+// -------- func png.decoder.filter_1
+
+static wuffs_base__empty_struct
+wuffs_png__decoder__filter_1(
+    wuffs_png__decoder* self,
+    wuffs_base__slice_u8 a_curr) {
+  uint64_t v_filter_distance = 0;
+  uint8_t v_fa = 0;
+  uint64_t v_i_start = 0;
+  uint64_t v_i = 0;
+
+  v_filter_distance = ((uint64_t)(self->private_impl.f_filter_distance));
+  v_i_start = 0;
+  while (v_i_start < v_filter_distance) {
+    v_fa = 0;
+    v_i = v_i_start;
+    while (v_i < ((uint64_t)(a_curr.len))) {
+      a_curr.ptr[v_i] += v_fa;
+      v_fa = a_curr.ptr[v_i];
+      v_i += v_filter_distance;
+    }
+    v_i_start += 1;
+  }
+  return wuffs_base__make_empty_struct();
+}
+
+// -------- func png.decoder.filter_2
+
+static wuffs_base__empty_struct
+wuffs_png__decoder__filter_2(
+    wuffs_png__decoder* self,
+    wuffs_base__slice_u8 a_curr,
+    wuffs_base__slice_u8 a_prev) {
+  uint64_t v_i = 0;
+
+  v_i = 0;
+  while ((v_i < ((uint64_t)(a_curr.len))) && (v_i < ((uint64_t)(a_prev.len)))) {
+    a_curr.ptr[v_i] += a_prev.ptr[v_i];
+    v_i += 1;
+  }
+  return wuffs_base__make_empty_struct();
+}
+
+// -------- func png.decoder.filter_3
+
+static wuffs_base__empty_struct
+wuffs_png__decoder__filter_3(
+    wuffs_png__decoder* self,
+    wuffs_base__slice_u8 a_curr,
+    wuffs_base__slice_u8 a_prev) {
+  uint64_t v_filter_distance = 0;
+  uint64_t v_i = 0;
+
+  v_filter_distance = ((uint64_t)(self->private_impl.f_filter_distance));
+  if (((uint64_t)(a_prev.len)) == 0) {
+    v_i = v_filter_distance;
+    while (v_i < ((uint64_t)(a_curr.len))) {
+      if (v_i >= v_filter_distance) {
+        if ((v_i - v_filter_distance) < ((uint64_t)(a_curr.len))) {
+          a_curr.ptr[v_i] += (a_curr.ptr[(v_i - v_filter_distance)] / 2);
+        }
+      }
+      v_i += 1;
+    }
+  } else {
+    v_i = 0;
+    while ((v_i < ((uint64_t)(a_curr.len))) && (v_i < ((uint64_t)(a_prev.len)))) {
+      if (v_i >= v_filter_distance) {
+        if ((v_i - v_filter_distance) < ((uint64_t)(a_curr.len))) {
+          a_curr.ptr[v_i] += ((uint8_t)(((((uint32_t)(a_curr.ptr[(v_i - v_filter_distance)])) + ((uint32_t)(a_prev.ptr[v_i]))) / 2)));
+        }
+      } else {
+        a_curr.ptr[v_i] += (a_prev.ptr[v_i] / 2);
+      }
+      v_i += 1;
+    }
+  }
+  return wuffs_base__make_empty_struct();
+}
+
+// -------- func png.decoder.filter_4
+
+static wuffs_base__empty_struct
+wuffs_png__decoder__filter_4(
+    wuffs_png__decoder* self,
+    wuffs_base__slice_u8 a_curr,
+    wuffs_base__slice_u8 a_prev) {
+  uint64_t v_filter_distance = 0;
+  uint64_t v_i = 0;
+  uint32_t v_fa = 0;
+  uint32_t v_fb = 0;
+  uint32_t v_fc = 0;
+  uint32_t v_pp = 0;
+  uint32_t v_pa = 0;
+  uint32_t v_pb = 0;
+  uint32_t v_pc = 0;
+
+  v_filter_distance = ((uint64_t)(self->private_impl.f_filter_distance));
+  v_i = 0;
+  while ((v_i < ((uint64_t)(a_curr.len))) && (v_i < ((uint64_t)(a_prev.len)))) {
+    if (v_i < v_filter_distance) {
+      a_curr.ptr[v_i] += a_prev.ptr[v_i];
+    } else {
+      if (((v_i - v_filter_distance) < ((uint64_t)(a_curr.len))) && ((v_i - v_filter_distance) < ((uint64_t)(a_prev.len)))) {
+        v_fa = ((uint32_t)(a_curr.ptr[(v_i - v_filter_distance)]));
+        v_fb = ((uint32_t)(a_prev.ptr[v_i]));
+        v_fc = ((uint32_t)(a_prev.ptr[(v_i - v_filter_distance)]));
+        v_pp = ((v_fa + v_fb) - v_fc);
+        v_pa = (v_pp - v_fa);
+        if (v_pa >= 2147483648) {
+          v_pa = (0 - v_pa);
+        }
+        v_pb = (v_pp - v_fb);
+        if (v_pb >= 2147483648) {
+          v_pb = (0 - v_pb);
+        }
+        v_pc = (v_pp - v_fc);
+        if (v_pc >= 2147483648) {
+          v_pc = (0 - v_pc);
+        }
+        if ((v_pa <= v_pb) && (v_pa <= v_pc)) {
+          a_curr.ptr[v_i] += ((uint8_t)((v_fa & 255)));
+        } else if (v_pb <= v_pc) {
+          a_curr.ptr[v_i] += ((uint8_t)((v_fb & 255)));
+        } else {
+          a_curr.ptr[v_i] += ((uint8_t)((v_fc & 255)));
+        }
+      }
+    }
+    v_i += 1;
+  }
+  return wuffs_base__make_empty_struct();
+}
+
 // -------- func png.decoder.set_quirk_enabled
 
 WUFFS_BASE__MAYBE_STATIC wuffs_base__empty_struct
@@ -31014,140 +31148,6 @@
   return wuffs_base__make_status(NULL);
 }
 
-// -------- func png.decoder.filter_1
-
-static wuffs_base__empty_struct
-wuffs_png__decoder__filter_1(
-    wuffs_png__decoder* self,
-    wuffs_base__slice_u8 a_curr) {
-  uint64_t v_filter_distance = 0;
-  uint8_t v_fa = 0;
-  uint64_t v_i_start = 0;
-  uint64_t v_i = 0;
-
-  v_filter_distance = ((uint64_t)(self->private_impl.f_filter_distance));
-  v_i_start = 0;
-  while (v_i_start < v_filter_distance) {
-    v_fa = 0;
-    v_i = v_i_start;
-    while (v_i < ((uint64_t)(a_curr.len))) {
-      a_curr.ptr[v_i] += v_fa;
-      v_fa = a_curr.ptr[v_i];
-      v_i += v_filter_distance;
-    }
-    v_i_start += 1;
-  }
-  return wuffs_base__make_empty_struct();
-}
-
-// -------- func png.decoder.filter_2
-
-static wuffs_base__empty_struct
-wuffs_png__decoder__filter_2(
-    wuffs_png__decoder* self,
-    wuffs_base__slice_u8 a_curr,
-    wuffs_base__slice_u8 a_prev) {
-  uint64_t v_i = 0;
-
-  v_i = 0;
-  while ((v_i < ((uint64_t)(a_curr.len))) && (v_i < ((uint64_t)(a_prev.len)))) {
-    a_curr.ptr[v_i] += a_prev.ptr[v_i];
-    v_i += 1;
-  }
-  return wuffs_base__make_empty_struct();
-}
-
-// -------- func png.decoder.filter_3
-
-static wuffs_base__empty_struct
-wuffs_png__decoder__filter_3(
-    wuffs_png__decoder* self,
-    wuffs_base__slice_u8 a_curr,
-    wuffs_base__slice_u8 a_prev) {
-  uint64_t v_filter_distance = 0;
-  uint64_t v_i = 0;
-
-  v_filter_distance = ((uint64_t)(self->private_impl.f_filter_distance));
-  if (((uint64_t)(a_prev.len)) == 0) {
-    v_i = v_filter_distance;
-    while (v_i < ((uint64_t)(a_curr.len))) {
-      if (v_i >= v_filter_distance) {
-        if ((v_i - v_filter_distance) < ((uint64_t)(a_curr.len))) {
-          a_curr.ptr[v_i] += (a_curr.ptr[(v_i - v_filter_distance)] / 2);
-        }
-      }
-      v_i += 1;
-    }
-  } else {
-    v_i = 0;
-    while ((v_i < ((uint64_t)(a_curr.len))) && (v_i < ((uint64_t)(a_prev.len)))) {
-      if (v_i >= v_filter_distance) {
-        if ((v_i - v_filter_distance) < ((uint64_t)(a_curr.len))) {
-          a_curr.ptr[v_i] += ((uint8_t)(((((uint32_t)(a_curr.ptr[(v_i - v_filter_distance)])) + ((uint32_t)(a_prev.ptr[v_i]))) / 2)));
-        }
-      } else {
-        a_curr.ptr[v_i] += (a_prev.ptr[v_i] / 2);
-      }
-      v_i += 1;
-    }
-  }
-  return wuffs_base__make_empty_struct();
-}
-
-// -------- func png.decoder.filter_4
-
-static wuffs_base__empty_struct
-wuffs_png__decoder__filter_4(
-    wuffs_png__decoder* self,
-    wuffs_base__slice_u8 a_curr,
-    wuffs_base__slice_u8 a_prev) {
-  uint64_t v_filter_distance = 0;
-  uint64_t v_i = 0;
-  uint32_t v_fa = 0;
-  uint32_t v_fb = 0;
-  uint32_t v_fc = 0;
-  uint32_t v_pp = 0;
-  uint32_t v_pa = 0;
-  uint32_t v_pb = 0;
-  uint32_t v_pc = 0;
-
-  v_filter_distance = ((uint64_t)(self->private_impl.f_filter_distance));
-  v_i = 0;
-  while ((v_i < ((uint64_t)(a_curr.len))) && (v_i < ((uint64_t)(a_prev.len)))) {
-    if (v_i < v_filter_distance) {
-      a_curr.ptr[v_i] += a_prev.ptr[v_i];
-    } else {
-      if (((v_i - v_filter_distance) < ((uint64_t)(a_curr.len))) && ((v_i - v_filter_distance) < ((uint64_t)(a_prev.len)))) {
-        v_fa = ((uint32_t)(a_curr.ptr[(v_i - v_filter_distance)]));
-        v_fb = ((uint32_t)(a_prev.ptr[v_i]));
-        v_fc = ((uint32_t)(a_prev.ptr[(v_i - v_filter_distance)]));
-        v_pp = ((v_fa + v_fb) - v_fc);
-        v_pa = (v_pp - v_fa);
-        if (v_pa >= 2147483648) {
-          v_pa = (0 - v_pa);
-        }
-        v_pb = (v_pp - v_fb);
-        if (v_pb >= 2147483648) {
-          v_pb = (0 - v_pb);
-        }
-        v_pc = (v_pp - v_fc);
-        if (v_pc >= 2147483648) {
-          v_pc = (0 - v_pc);
-        }
-        if ((v_pa <= v_pb) && (v_pa <= v_pc)) {
-          a_curr.ptr[v_i] += ((uint8_t)((v_fa & 255)));
-        } else if (v_pb <= v_pc) {
-          a_curr.ptr[v_i] += ((uint8_t)((v_fb & 255)));
-        } else {
-          a_curr.ptr[v_i] += ((uint8_t)((v_fc & 255)));
-        }
-      }
-    }
-    v_i += 1;
-  }
-  return wuffs_base__make_empty_struct();
-}
-
 // -------- func png.decoder.frame_dirty_rect
 
 WUFFS_BASE__MAYBE_STATIC wuffs_base__rect_ie_u32
diff --git a/std/png/decode_filter_fallback.wuffs b/std/png/decode_filter_fallback.wuffs
new file mode 100644
index 0000000..4236475
--- /dev/null
+++ b/std/png/decode_filter_fallback.wuffs
@@ -0,0 +1,131 @@
+// Copyright 2020 The Wuffs Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+pri func decoder.filter_1!(curr: slice base.u8) {
+	var filter_distance : base.u64[..= 8]
+	var fa              : base.u8
+	var i_start         : base.u64
+	var i               : base.u64
+
+	filter_distance = this.filter_distance as base.u64
+	i_start = 0
+	while i_start < filter_distance {
+		assert i_start < 8 via "a < b: a < c; c <= b"(c: filter_distance)
+		fa = 0
+		i = i_start
+		while i < args.curr.length(),
+			inv i_start < 8,
+		{
+			args.curr[i] ~mod+= fa
+			fa = args.curr[i]
+			i ~mod+= filter_distance
+		} endwhile
+		i_start += 1
+	} endwhile
+}
+
+pri func decoder.filter_2!(curr: slice base.u8, prev: slice base.u8) {
+	var i : base.u64
+
+	i = 0
+	while (i < args.curr.length()) and (i < args.prev.length()) {
+		assert i < 0xFFFF_FFFF_FFFF_FFFF via "a < b: a < c; c <= b"(c: args.curr.length())
+		args.curr[i] ~mod+= args.prev[i]
+		i += 1
+	} endwhile
+}
+
+pri func decoder.filter_3!(curr: slice base.u8, prev: slice base.u8) {
+	var filter_distance : base.u64[..= 8]
+	var i               : base.u64
+
+	filter_distance = this.filter_distance as base.u64
+	if args.prev.length() == 0 {
+		i = filter_distance
+		while i < args.curr.length() {
+			assert i < 0xFFFF_FFFF_FFFF_FFFF via "a < b: a < c; c <= b"(c: args.curr.length())
+			if i >= filter_distance {
+				if (i - filter_distance) < args.curr.length() {
+					args.curr[i] ~mod+= args.curr[i - filter_distance] / 2
+				}
+			}
+			i += 1
+		} endwhile
+	} else {
+		i = 0
+		while (i < args.curr.length()) and (i < args.prev.length()) {
+			assert i < 0xFFFF_FFFF_FFFF_FFFF via "a < b: a < c; c <= b"(c: args.curr.length())
+			if i >= filter_distance {
+				if (i - filter_distance) < args.curr.length() {
+					args.curr[i] ~mod+= ((
+						(args.curr[i - filter_distance] as base.u32) +
+						(args.prev[i] as base.u32)) / 2) as base.u8
+				}
+			} else {
+				args.curr[i] ~mod+= args.prev[i] / 2
+			}
+			i += 1
+		} endwhile
+	}
+}
+
+pri func decoder.filter_4!(curr: slice base.u8, prev: slice base.u8) {
+	var filter_distance : base.u64[..= 8]
+	var i               : base.u64
+
+	var fa : base.u32
+	var fb : base.u32
+	var fc : base.u32
+	var pp : base.u32
+	var pa : base.u32
+	var pb : base.u32
+	var pc : base.u32
+
+	filter_distance = this.filter_distance as base.u64
+	i = 0
+	while (i < args.curr.length()) and (i < args.prev.length()) {
+		assert i < 0xFFFF_FFFF_FFFF_FFFF via "a < b: a < c; c <= b"(c: args.curr.length())
+		if i < filter_distance {
+			args.curr[i] ~mod+= args.prev[i]
+		} else {
+			if ((i - filter_distance) < args.curr.length()) and
+				((i - filter_distance) < args.prev.length()) {
+				fa = args.curr[i - filter_distance] as base.u32
+				fb = args.prev[i] as base.u32
+				fc = args.prev[i - filter_distance] as base.u32
+				pp = (fa ~mod+ fb) ~mod- fc
+				pa = pp ~mod- fa
+				if pa >= 0x8000_0000 {
+					pa = 0 ~mod- pa
+				}
+				pb = pp ~mod- fb
+				if pb >= 0x8000_0000 {
+					pb = 0 ~mod- pb
+				}
+				pc = pp ~mod- fc
+				if pc >= 0x8000_0000 {
+					pc = 0 ~mod- pc
+				}
+				if (pa <= pb) and (pa <= pc) {
+					args.curr[i] ~mod+= (fa & 0xFF) as base.u8
+				} else if pb <= pc {
+					args.curr[i] ~mod+= (fb & 0xFF) as base.u8
+				} else {
+					args.curr[i] ~mod+= (fc & 0xFF) as base.u8
+				}
+			}
+		}
+		i += 1
+	} endwhile
+}
diff --git a/std/png/decode_png.wuffs b/std/png/decode_png.wuffs
index 5c1e6a4..882baf5 100644
--- a/std/png/decode_png.wuffs
+++ b/std/png/decode_png.wuffs
@@ -461,124 +461,6 @@
 	return ok
 }
 
-pri func decoder.filter_1!(curr: slice base.u8) {
-	var filter_distance : base.u64[..= 8]
-	var fa              : base.u8
-	var i_start         : base.u64
-	var i               : base.u64
-
-	filter_distance = this.filter_distance as base.u64
-	i_start = 0
-	while i_start < filter_distance {
-		assert i_start < 8 via "a < b: a < c; c <= b"(c: filter_distance)
-		fa = 0
-		i = i_start
-		while i < args.curr.length(),
-			inv i_start < 8,
-		{
-			args.curr[i] ~mod+= fa
-			fa = args.curr[i]
-			i ~mod+= filter_distance
-		} endwhile
-		i_start += 1
-	} endwhile
-}
-
-pri func decoder.filter_2!(curr: slice base.u8, prev: slice base.u8) {
-	var i : base.u64
-
-	i = 0
-	while (i < args.curr.length()) and (i < args.prev.length()) {
-		assert i < 0xFFFF_FFFF_FFFF_FFFF via "a < b: a < c; c <= b"(c: args.curr.length())
-		args.curr[i] ~mod+= args.prev[i]
-		i += 1
-	} endwhile
-}
-
-pri func decoder.filter_3!(curr: slice base.u8, prev: slice base.u8) {
-	var filter_distance : base.u64[..= 8]
-	var i               : base.u64
-
-	filter_distance = this.filter_distance as base.u64
-	if args.prev.length() == 0 {
-		i = filter_distance
-		while i < args.curr.length() {
-			assert i < 0xFFFF_FFFF_FFFF_FFFF via "a < b: a < c; c <= b"(c: args.curr.length())
-			if i >= filter_distance {
-				if (i - filter_distance) < args.curr.length() {
-					args.curr[i] ~mod+= args.curr[i - filter_distance] / 2
-				}
-			}
-			i += 1
-		} endwhile
-	} else {
-		i = 0
-		while (i < args.curr.length()) and (i < args.prev.length()) {
-			assert i < 0xFFFF_FFFF_FFFF_FFFF via "a < b: a < c; c <= b"(c: args.curr.length())
-			if i >= filter_distance {
-				if (i - filter_distance) < args.curr.length() {
-					args.curr[i] ~mod+= ((
-						(args.curr[i - filter_distance] as base.u32) +
-						(args.prev[i] as base.u32)) / 2) as base.u8
-				}
-			} else {
-				args.curr[i] ~mod+= args.prev[i] / 2
-			}
-			i += 1
-		} endwhile
-	}
-}
-
-pri func decoder.filter_4!(curr: slice base.u8, prev: slice base.u8) {
-	var filter_distance : base.u64[..= 8]
-	var i               : base.u64
-
-	var fa : base.u32
-	var fb : base.u32
-	var fc : base.u32
-	var pp : base.u32
-	var pa : base.u32
-	var pb : base.u32
-	var pc : base.u32
-
-	filter_distance = this.filter_distance as base.u64
-	i = 0
-	while (i < args.curr.length()) and (i < args.prev.length()) {
-		assert i < 0xFFFF_FFFF_FFFF_FFFF via "a < b: a < c; c <= b"(c: args.curr.length())
-		if i < filter_distance {
-			args.curr[i] ~mod+= args.prev[i]
-		} else {
-			if ((i - filter_distance) < args.curr.length()) and
-				((i - filter_distance) < args.prev.length()) {
-				fa = args.curr[i - filter_distance] as base.u32
-				fb = args.prev[i] as base.u32
-				fc = args.prev[i - filter_distance] as base.u32
-				pp = (fa ~mod+ fb) ~mod- fc
-				pa = pp ~mod- fa
-				if pa >= 0x8000_0000 {
-					pa = 0 ~mod- pa
-				}
-				pb = pp ~mod- fb
-				if pb >= 0x8000_0000 {
-					pb = 0 ~mod- pb
-				}
-				pc = pp ~mod- fc
-				if pc >= 0x8000_0000 {
-					pc = 0 ~mod- pc
-				}
-				if (pa <= pb) and (pa <= pc) {
-					args.curr[i] ~mod+= (fa & 0xFF) as base.u8
-				} else if pb <= pc {
-					args.curr[i] ~mod+= (fb & 0xFF) as base.u8
-				} else {
-					args.curr[i] ~mod+= (fc & 0xFF) as base.u8
-				}
-			}
-		}
-		i += 1
-	} endwhile
-}
-
 pub func decoder.frame_dirty_rect() base.rect_ie_u32 {
 	return this.util.make_rect_ie_u32(
 		min_incl_x: 0,