Add gif-small-frame-interlaced.gif test
diff --git a/script/make-artificial.go b/script/make-artificial.go
index 23d37bb..0037f6e 100644
--- a/script/make-artificial.go
+++ b/script/make-artificial.go
@@ -796,10 +796,11 @@
 	imageHeight               uint32
 	imageBackgroundColorIndex uint32
 
-	frameLeft   uint32
-	frameTop    uint32
-	frameWidth  uint32
-	frameHeight uint32
+	frameInterlaced bool
+	frameLeft       uint32
+	frameTop        uint32
+	frameWidth      uint32
+	frameHeight     uint32
 
 	globalPalette [][4]uint8
 	localPalette  [][4]uint8
@@ -818,6 +819,11 @@
 		return stateGif, nil
 
 	case line == "frame {":
+		gifGlobals.frameInterlaced = false
+		gifGlobals.frameLeft = 0
+		gifGlobals.frameTop = 0
+		gifGlobals.frameWidth = 0
+		gifGlobals.frameHeight = 0
 		gifGlobals.localPalette = nil
 		out = append(out, 0x2C)
 		return stateGifFrame, nil
@@ -1011,12 +1017,16 @@
 		out = appendU16LE(out, uint16(g.frameTop))
 		out = appendU16LE(out, uint16(g.frameWidth))
 		out = appendU16LE(out, uint16(g.frameHeight))
+		flags := byte(0x00)
+		if g.frameInterlaced {
+			flags |= 0x40
+		}
 		if g.localPalette == nil {
-			out = append(out, 0x00)
+			out = append(out, flags)
 		} else if n := log2(uint32(len(g.localPalette))); n < 2 || 8 < n {
 			return nil, fmt.Errorf("bad len(g.localPalette): %d", len(g.localPalette))
 		} else {
-			out = append(out, 0x80|uint8(n-1))
+			out = append(out, flags|0x80|uint8(n-1))
 		}
 		for _, x := range g.localPalette {
 			out = append(out, x[0], x[1], x[2])
@@ -1029,6 +1039,10 @@
 		cmdP     = "palette {"
 	)
 	switch {
+	case line == "interlaced":
+		g.frameInterlaced = true
+		return stateGifFrame, nil
+
 	case strings.HasPrefix(line, cmdFLTWH):
 		s := line[len(cmdFLTWH):]
 		if l, s, ok := parseNum(s); ok {
diff --git a/test/c/std/gif.c b/test/c/std/gif.c
index 57763d6..1fae153 100644
--- a/test/c/std/gif.c
+++ b/test/c/std/gif.c
@@ -2024,6 +2024,76 @@
   return do_test_wuffs_gif_io_position(true);
 }
 
+const char* test_wuffs_gif_small_frame_interlaced() {
+  CHECK_FOCUS(__func__);
+
+  wuffs_base__io_buffer src = ((wuffs_base__io_buffer){
+      .data = global_src_slice,
+  });
+
+  const char* status =
+      read_file(&src, "test/data/artificial/gif-small-frame-interlaced.gif");
+  if (status) {
+    return status;
+  }
+
+  wuffs_gif__decoder dec;
+  status = wuffs_gif__decoder__initialize(
+      &dec, sizeof dec, WUFFS_VERSION,
+      WUFFS_INITIALIZE__LEAVE_INTERNAL_BUFFERS_UNINITIALIZED);
+  if (status) {
+    RETURN_FAIL("initialize: \"%s\"", status);
+  }
+
+  wuffs_base__image_config ic = ((wuffs_base__image_config){});
+  status = wuffs_gif__decoder__decode_image_config(&dec, &ic, &src);
+  if (status) {
+    RETURN_FAIL("decode_image_config: \"%s\"", status);
+  }
+  if (wuffs_base__pixel_config__width(&ic.pixcfg) != 5) {
+    RETURN_FAIL("width: got %" PRIu32 ", want 5",
+                wuffs_base__pixel_config__width(&ic.pixcfg));
+  }
+  if (wuffs_base__pixel_config__height(&ic.pixcfg) != 5) {
+    RETURN_FAIL("height: got %" PRIu32 ", want 5",
+                wuffs_base__pixel_config__height(&ic.pixcfg));
+  }
+
+  wuffs_base__pixel_buffer pb = ((wuffs_base__pixel_buffer){});
+  status = wuffs_base__pixel_buffer__set_from_slice(&pb, &ic.pixcfg,
+                                                    global_pixel_slice);
+  if (status) {
+    RETURN_FAIL("set_from_slice: \"%s\"", status);
+  }
+
+  wuffs_base__frame_config fc;
+  status = wuffs_gif__decoder__decode_frame_config(&dec, &fc, &src);
+  if (status) {
+    RETURN_FAIL("decode_frame_config: \"%s\"", status);
+  }
+
+  wuffs_base__rect_ie_u32 fr = wuffs_base__frame_config__bounds(&fc);
+  if (fr.max_excl_y != 3) {
+    RETURN_FAIL("frame rect max_excl_y: got %" PRIu32 ", want 3",
+                fr.max_excl_y);
+  }
+
+  status = wuffs_gif__decoder__decode_frame(&dec, &pb, &src, global_work_slice,
+                                            NULL);
+  if (status) {
+    RETURN_FAIL("decode_frame: \"%s\"", status);
+  }
+
+  wuffs_base__rect_ie_u32 dr = wuffs_gif__decoder__frame_dirty_rect(&dec);
+  // TODO: it's a bug that the frame rect doesn't contain the dirty rect.
+  if (dr.max_excl_y != 5) {
+    RETURN_FAIL("dirty rect max_excl_y: got %" PRIu32 ", want 5",
+                dr.max_excl_y);
+  }
+
+  return NULL;
+}
+
   // ---------------- Mimic Tests
 
 #ifdef WUFFS_MIMIC
@@ -2374,6 +2444,7 @@
     test_wuffs_gif_num_decoded_frames,                       //
     test_wuffs_gif_io_position_one_chunk,                    //
     test_wuffs_gif_io_position_two_chunks,                   //
+    test_wuffs_gif_small_frame_interlaced,                   //
 
 #ifdef WUFFS_MIMIC
 
diff --git a/test/data/artificial/gif-small-frame-interlaced.gif b/test/data/artificial/gif-small-frame-interlaced.gif
new file mode 100644
index 0000000..7023f29
--- /dev/null
+++ b/test/data/artificial/gif-small-frame-interlaced.gif
Binary files differ
diff --git a/test/data/artificial/gif-small-frame-interlaced.gif.make-artificial.txt b/test/data/artificial/gif-small-frame-interlaced.gif.make-artificial.txt
new file mode 100644
index 0000000..7918dcf
--- /dev/null
+++ b/test/data/artificial/gif-small-frame-interlaced.gif.make-artificial.txt
@@ -0,0 +1,27 @@
+# Feed this file to script/make-artificial.go
+
+# This GIF image has one frame, whose frame rect is smaller than the image
+# rect. The frame is also interlaced, but its frame rect (and dirty rect)
+# should still only be 1 row high.
+
+make gif
+
+header
+
+image {
+	imageWidthHeight 5 5
+	palette {
+		0x00 0x00 0xFF
+		0x11 0x00 0xFF
+		0x22 0x00 0xFF
+		0x33 0x00 0xFF
+	}
+}
+
+frame {
+	frameLeftTopWidthHeight 3 2 1 1
+	interlaced
+}
+lzw 2 0x00
+
+trailer