Fix dirty rect for interlaced GIFs
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index fea15d5..24a46ec 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -11179,6 +11179,18 @@
                                                 v_replicate_src);
           v_replicate_count -= 1;
         }
+        v_replicate_count =
+            (((uint32_t)(
+                 wuffs_gif__interlace_count[self->private_impl.f_interlace])) +
+             1);
+        v_replicate_count = wuffs_base__u32__sat_add(
+            v_replicate_count, self->private_impl.f_dst_y);
+        v_replicate_count = wuffs_base__u32__min(
+            v_replicate_count, self->private_impl.f_frame_rect_y1);
+        self->private_impl.f_dirty_y = wuffs_base__range_ie_u32__unite(
+            &self->private_impl.f_dirty_y,
+            wuffs_base__utility__make_range_ie_u32(self->private_impl.f_dst_y,
+                                                   v_replicate_count));
       }
       wuffs_base__u32__sat_add_indirect(
           &self->private_impl.f_dst_y,
diff --git a/std/gif/decode_gif.wuffs b/std/gif/decode_gif.wuffs
index 377db62..b414c3f 100644
--- a/std/gif/decode_gif.wuffs
+++ b/std/gif/decode_gif.wuffs
@@ -1189,6 +1189,13 @@
 					replicate_dst.copy_from_slice!(s:replicate_src)
 					replicate_count -= 1
 				}
+
+				replicate_count = (interlace_count[this.interlace] as base.u32) + 1
+				replicate_count = replicate_count ~sat+ this.dst_y
+				replicate_count = replicate_count.min(x:this.frame_rect_y1)
+				this.dirty_y = this.dirty_y.unite(r:this.util.make_range_ie_u32(
+					min_incl:this.dst_y,
+					max_excl:replicate_count))
 			}
 
 			this.dst_y ~sat+= interlace_delta[this.interlace] as base.u32
diff --git a/test/c/std/gif.c b/test/c/std/gif.c
index a8f0bd9..e30c3c2 100644
--- a/test/c/std/gif.c
+++ b/test/c/std/gif.c
@@ -1324,6 +1324,12 @@
     RETURN_FAIL("final pixel index, after: got 0x%02X, want not 0x%02X",
                 pixel_ptr[num_pixel_indexes - 1], 0xEE);
   }
+
+  wuffs_base__rect_ie_u32 r = wuffs_gif__decoder__frame_dirty_rect(&dec);
+  if (r.max_excl_y != 28) {
+    RETURN_FAIL("frame_dirty_rect max_excl_y: got %" PRIu32 ", want 28",
+                r.max_excl_y);
+  }
   return NULL;
 }
 
@@ -1719,9 +1725,10 @@
   // The hippopotamus.interlaced.gif image is 28 pixels high. As we decode rows
   // of pixels, interlacing means that we decode rows 0, 8, 16, 24, 4, 12, 20,
   // 2, 6, 10, ..., 22, 26, 1, 3, 5, ..., 25, 27. As we progress, the dirty
-  // rect's max_excl_y should be one more than the highest decoded row so far.
-  // If we haven't decoded any rows yet, max_excl_y should be zero.
-  uint32_t wants[7] = {0, 1, 9, 17, 25, 27, 28};
+  // rect's max_excl_y should be one more than the highest decoded row so far,
+  // until the row is complete, when it is replicated (to a multiple of 8). If
+  // we haven't decoded any rows yet, max_excl_y should be zero.
+  uint32_t wants[9] = {0, 1, 8, 9, 16, 17, 24, 25, 28};
   int i = 0;
 
   while (true) {