Add wuffs_gif__quirk_reject_empty_frame
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index 28854b1..1cb3e28 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -3286,6 +3286,7 @@
 
 extern const char* wuffs_gif__error__bad_block;
 extern const char* wuffs_gif__error__bad_extension_label;
+extern const char* wuffs_gif__error__bad_frame_size;
 extern const char* wuffs_gif__error__bad_graphic_control;
 extern const char* wuffs_gif__error__bad_header;
 extern const char* wuffs_gif__error__bad_literal_width;
@@ -3323,6 +3324,12 @@
     wuffs_gif__quirk_background_is_opaque  //
         WUFFS_BASE__POTENTIALLY_UNUSED = 1041635331;
 
+#define WUFFS_GIF__QUIRK_REJECT_EMPTY_FRAME 1041635333
+
+static const uint32_t                    //
+    wuffs_gif__quirk_reject_empty_frame  //
+        WUFFS_BASE__POTENTIALLY_UNUSED = 1041635333;
+
 #define WUFFS_GIF__QUIRK_REJECT_EMPTY_PALETTE 1041635332
 
 static const uint32_t                      //
@@ -3445,6 +3452,7 @@
     bool f_quirk_enabled_ignore_too_much_pixel_data;
     bool f_quirk_enabled_image_bounds_are_strict;
     bool f_quirk_enabled_background_is_opaque;
+    bool f_quirk_enabled_reject_empty_frame;
     bool f_quirk_enabled_reject_empty_palette;
     bool f_delayed_num_decoded_frames;
     bool f_end_of_data;
@@ -8560,6 +8568,7 @@
 
 const char* wuffs_gif__error__bad_block = "#gif: bad block";
 const char* wuffs_gif__error__bad_extension_label = "#gif: bad extension label";
+const char* wuffs_gif__error__bad_frame_size = "#gif: bad frame size";
 const char* wuffs_gif__error__bad_graphic_control = "#gif: bad graphic control";
 const char* wuffs_gif__error__bad_header = "#gif: bad header";
 const char* wuffs_gif__error__bad_literal_width = "#gif: bad literal width";
@@ -8747,6 +8756,8 @@
     self->private_impl.f_quirk_enabled_image_bounds_are_strict = a_enabled;
   } else if (a_quirk == 1041635331) {
     self->private_impl.f_quirk_enabled_background_is_opaque = a_enabled;
+  } else if (a_quirk == 1041635333) {
+    self->private_impl.f_quirk_enabled_reject_empty_frame = a_enabled;
   } else if (a_quirk == 1041635332) {
     self->private_impl.f_quirk_enabled_reject_empty_palette = a_enabled;
   }
@@ -10592,6 +10603,14 @@
     self->private_impl.f_frame_rect_y1 += self->private_impl.f_frame_rect_y0;
     self->private_impl.f_dst_x = self->private_impl.f_frame_rect_x0;
     self->private_impl.f_dst_y = self->private_impl.f_frame_rect_y0;
+    if (self->private_impl.f_quirk_enabled_reject_empty_frame &&
+        ((self->private_impl.f_frame_rect_x0 ==
+          self->private_impl.f_frame_rect_x1) ||
+         (self->private_impl.f_frame_rect_y0 ==
+          self->private_impl.f_frame_rect_y1))) {
+      status = wuffs_gif__error__bad_frame_size;
+      goto exit;
+    }
     if ((self->private_impl.f_call_sequence == 0) &&
         !self->private_impl.f_quirk_enabled_image_bounds_are_strict) {
       self->private_impl.f_width = wuffs_base__u32__max(
diff --git a/std/gif/decode_gif.wuffs b/std/gif/decode_gif.wuffs
index 9251162..76c94fa 100644
--- a/std/gif/decode_gif.wuffs
+++ b/std/gif/decode_gif.wuffs
@@ -16,6 +16,7 @@
 
 pub status "#bad block"
 pub status "#bad extension label"
+pub status "#bad frame size"
 pub status "#bad graphic control"
 pub status "#bad header"
 pub status "#bad literal width"
@@ -100,6 +101,9 @@
 // buffer with that color.
 pub const quirk_background_is_opaque base.u32 = (0xF8586 << 10) | 3
 
+// When this quirk is enabled, a frame with zero width or height is rejected.
+pub const quirk_reject_empty_frame base.u32 = (0xF8586 << 10) | 5
+
 // When this quirk is enabled, a frame with no explicit palette is rejected,
 // instead of implicitly having a palette with every entry being opaque black.
 pub const quirk_reject_empty_palette base.u32 = (0xF8586 << 10) | 4
@@ -174,6 +178,7 @@
 	quirk_enabled_ignore_too_much_pixel_data base.bool,
 	quirk_enabled_image_bounds_are_strict    base.bool,
 	quirk_enabled_background_is_opaque       base.bool,
+	quirk_enabled_reject_empty_frame         base.bool,
 	quirk_enabled_reject_empty_palette       base.bool,
 
 	delayed_num_decoded_frames         base.bool,
@@ -239,6 +244,8 @@
 		this.quirk_enabled_image_bounds_are_strict = args.enabled
 	} else if args.quirk == quirk_background_is_opaque {
 		this.quirk_enabled_background_is_opaque = args.enabled
+	} else if args.quirk == quirk_reject_empty_frame {
+		this.quirk_enabled_reject_empty_frame = args.enabled
 	} else if args.quirk == quirk_reject_empty_palette {
 		this.quirk_enabled_reject_empty_palette = args.enabled
 	}
@@ -825,6 +832,12 @@
 	this.dst_x = this.frame_rect_x0
 	this.dst_y = this.frame_rect_y0
 
+	if this.quirk_enabled_reject_empty_frame and
+		((this.frame_rect_x0 == this.frame_rect_x1) or
+		(this.frame_rect_y0 == this.frame_rect_y1)) {
+		return "#bad frame size"
+	}
+
 	// Set the image's overall width and height to be the maximum of the
 	// nominal image width and height (given in the Logical Screen Descriptor)
 	// and the bottom right extent of the first frame. See
diff --git a/test/c/std/gif.c b/test/c/std/gif.c
index 7457045..ee1d94b 100644
--- a/test/c/std/gif.c
+++ b/test/c/std/gif.c
@@ -1096,7 +1096,7 @@
     return status;
   }
   int q;
-  for (q = 0; q < 2; q++) {
+  for (q = 0; q < 3; q++) {
     src.meta.ri = 0;
 
     wuffs_gif__decoder dec;
@@ -1106,13 +1106,35 @@
     if (status) {
       RETURN_FAIL("q=%d: initialize: \"%s\"", q, status);
     }
-    wuffs_gif__decoder__set_quirk_enabled(
-        &dec, wuffs_gif__quirk_ignore_too_much_pixel_data, q);
+
+    const char* want = NULL;
+    switch (q) {
+      case 0:
+        want = wuffs_base__error__too_much_data;
+        break;
+      case 1:
+        want = NULL;
+        wuffs_gif__decoder__set_quirk_enabled(
+            &dec, wuffs_gif__quirk_ignore_too_much_pixel_data, true);
+        break;
+      case 2:
+        want = wuffs_gif__error__bad_frame_size;
+        wuffs_gif__decoder__set_quirk_enabled(
+            &dec, wuffs_gif__quirk_reject_empty_frame, true);
+        break;
+    }
 
     wuffs_base__image_config ic = ((wuffs_base__image_config){});
     status = wuffs_gif__decoder__decode_image_config(
         &dec, &ic, wuffs_base__io_buffer__reader(&src));
     if (status) {
+      if (q == 2) {
+        if (status != want) {
+          RETURN_FAIL("q=%d: decode_image_config: got \"%s\", want \"%s\"", q,
+                      status, want);
+        }
+        continue;
+      }
       RETURN_FAIL("q=%d: decode_image_config: \"%s\"", q, status);
     }
 
@@ -1123,12 +1145,12 @@
       RETURN_FAIL("q=%d: set_from_slice: \"%s\"", q, status);
     }
 
-    const char* got = wuffs_gif__decoder__decode_frame(
+    status = wuffs_gif__decoder__decode_frame(
         &dec, &pb, wuffs_base__io_buffer__reader(&src), global_work_slice,
         NULL);
-    const char* want = q ? NULL : wuffs_base__error__too_much_data;
-    if (got != want) {
-      RETURN_FAIL("q=%d: decode_frame: got \"%s\", want \"%s\"", q, got, want);
+    if (status != want) {
+      RETURN_FAIL("q=%d: decode_frame: got \"%s\", want \"%s\"", q, status,
+                  want);
     }
   }
   return NULL;