Repository: linebender/vello (2025-07-15T08:30:10Z)

Issue:
Panic in clipping
The following test case produces a panic:

```
#[vello_test(no_ref, width = 595, height = 841)]
fn new_panic(ctx: &mut impl Renderer) {
    ctx.push_clip_layer(&Rect::new(31., 219., 564., 186.).to_path(0.1));
    ctx.push_clip_layer(&Rect::new(29., 899., 558., 832.).to_path(0.1));
    ctx.pop_layer();
    ctx.pop_layer();
}
```

```
---- clip::new_panic_cpu_f32_scalar stdout ----

thread 'clip::new_panic_cpu_f32_scalar' panicked at sparse_strips/vello_common/src/coarse.rs:933:9:
attempt to subtract with overflow
```
Crash "called `Option::unwrap()` on a `None` value"
Tested with https://github.com/linebender/vello/pull/1078 (single-threaded)

```
called `Option::unwrap()` on a `None` value
Panicked at /Users/nico/code/oss/vello/sparse_strips/vello_cpu/src/fine/mod.rs:604:45
```



Discussion:
Slightly simplified:
```rs
#[vello_test(no_ref, width = 10, height = 16)]
fn new_panic(ctx: &mut impl Renderer) {
    ctx.push_clip_layer(&Rect::new(0., 0., 4., 4.).to_path(0.1));
    ctx.push_clip_layer(&Rect::new(0., 8., 260., 16.).to_path(0.1));
    ctx.pop_layer();
    ctx.pop_layer();
}
```

This could be the same as https://github.com/linebender/vello/issues/1072 (if you run in debug mode, you might get the same error message). There's definitely still at least one issue with the current clipping code.
@nicoburns Do you still remember how this panic was triggered (i.e. which test case)?
I did run in debug mode, and got the same error as #1072. So that repro might count. Otherwise there are ~60 WPT tests cases failing in the "css" subset.



Patch:
diff --git a/sparse_strips/vello_common/src/coarse.rs b/sparse_strips/vello_common/src/coarse.rs
index ced1a4c7e..cbbc58f2f 100644
--- a/sparse_strips/vello_common/src/coarse.rs
+++ b/sparse_strips/vello_common/src/coarse.rs
@@ -475,8 +475,10 @@ impl Wide {
                 cur_wtile_y += 1;
             }
 
-            // If we've reached the bottom of the clip bounding box, stop processing
-            if cur_wtile_y == clip_bbox.y1() {
+            // If we've reached the bottom of the clip bounding box, stop processing.
+            // Note that we are explicitly checking >= instead of ==, so that we abort if the clipping box
+            // is zero-area (see issue 1072).
+            if cur_wtile_y >= clip_bbox.y1() {
                 break;
             }
 
@@ -597,7 +599,9 @@ impl Wide {
             }
 
             // If we've reached the bottom of the clip bounding box, stop processing
-            if cur_wtile_y == clip_bbox.y1() {
+            // Note that we are explicitly checking >= instead of ==, so that we abort if the clipping box
+            // is zero-area (see issue 1072).
+            if cur_wtile_y >= clip_bbox.y1() {
                 break;
             }
 


Test patch:
diff --git a/sparse_strips/vello_sparse_tests/tests/issues.rs b/sparse_strips/vello_sparse_tests/tests/issues.rs
index b0ad0c121..4de3b3665 100644
--- a/sparse_strips/vello_sparse_tests/tests/issues.rs
+++ b/sparse_strips/vello_sparse_tests/tests/issues.rs
@@ -275,3 +275,12 @@ fn nested_clip_path_panic_2(ctx: &mut impl Renderer) {
     ctx.pop_layer();
     ctx.pop_layer();
 }
+
+#[vello_test(no_ref, width = 10, height = 16)]
+// https://github.com/linebender/vello/issues/1072
+fn intersected_clip_bbox_with_x0_gt_x1(ctx: &mut impl Renderer) {
+    ctx.push_clip_layer(&Rect::new(0., 0., 4., 4.).to_path(0.1));
+    ctx.push_clip_layer(&Rect::new(0., 8., 260., 16.).to_path(0.1));
+    ctx.pop_layer();
+    ctx.pop_layer();
+}