guido 0.12.0

A reactive Rust GUI library using wgpu for Wayland layer shell widgets
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
//! The rectangles a `wl_region` is made of, and how a rounded shape becomes
//! them.
//!
//! Two regions travel from a frame to the compositor: the backdrop blur's, and
//! the surface's input region. Both are `wl_region`s, both are read off the
//! flattened frame, and both need the same thing from a rounded container —
//! the axis-aligned rectangles that stand in for a shape the protocol has no
//! way to describe. That translation lives here so there is one of it.

use crate::renderer::{ClipChains, CornerRadii, DrawCommand, FlattenedCommand};
use crate::shape::{Outline, PlacedShape, Spans};
use smallvec::SmallVec;

use crate::widgets::Rect;

/// An axis-aligned rectangle of a region, in logical surface pixels.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct RegionRect {
    pub x: i32,
    pub y: i32,
    pub width: i32,
    pub height: i32,
}

impl RegionRect {
    /// Whether this rectangle holds `(x, y)`, half-open on the far edges as
    /// [`Rect::contains`] is: the pixel a rectangle ends at belongs to the next
    /// one.
    ///
    /// Nothing the library does asks this — it is how a test reads back the
    /// region the compositor was handed, here and in `Headless::input_reaches`.
    #[cfg(any(test, feature = "testing"))]
    pub(crate) fn contains(&self, x: i32, y: i32) -> bool {
        x >= self.x && y >= self.y && x < self.x + self.width && y < self.y + self.height
    }

    /// A whole-pixel rectangle covering all of `r`.
    ///
    /// Outward, because a region is a claim about where something is: a
    /// fractional bound rounded inward leaves a dead line along an edge
    /// somebody drew. It is the rule the surface's own declared rectangles
    /// have always taken to the compositor.
    pub(crate) fn covering(r: Rect) -> Option<Self> {
        let x = r.x.floor() as i32;
        let y = r.y.floor() as i32;
        let width = (r.x + r.width).ceil() as i32 - x;
        let height = (r.y + r.height).ceil() as i32 - y;
        (width > 0 && height > 0).then_some(Self {
            x,
            y,
            width,
            height,
        })
    }
}

/// Approximate a placed rounded rectangle as a union of axis-aligned rects that
/// **inscribe** the shape, narrowed to `clip`.
///
/// A band per pixel, because that is what the output can tell apart: adjacent
/// bands that round to the same span merge back into one rectangle, so the
/// straight parts collapse and a curve — moving about a pixel a band — does
/// not. The merging is what keeps an upright panel at a handful of rectangles
/// instead of one per band.
///
/// **The clips are shapes too** — every one a command is cut by, the first
/// and each down its chain. At any scanline the overlap is the overlap of all
/// their spans — which is exact, turned clips or not, and gets the corners
/// right for free. A card filling a rounded scroller is cornered by
/// the scroller: publishing the scroller's square box instead blurs the
/// desktop in the four corners where the panel is not drawn, and squaring off
/// the card's own corners along a cut edge is the same mistake the other way.
///
/// **A span is a list, because a scoop is not convex.** Every other curvature
/// bounds a convex region, and a horizontal line meets one of those in a
/// single interval. A scoop is the box minus a disc at each corner, so once
/// something turns it a line can enter the shape, cross into a bite and come
/// out into the shape again. Both promises below turn on that: claiming the
/// gap between the two halves sends clicks to a surface that did not draw
/// there, and claiming only the wider half gives up 5.5% of the shape at 45
/// degrees — past the budget the whole tessellation is held to (#410).
///
/// The coordinates are logical surface pixels, which is what `wl_region`
/// expects.
pub(crate) fn placed_shape_to_rects(shape: PlacedShape, clips: &[PlacedShape]) -> Vec<RegionRect> {
    if shape.rect.width <= 0.0 || shape.rect.height <= 0.0 {
        return Vec::new();
    }

    let (mut top, mut bottom) = shape.y_bounds();
    for clip in clips {
        let (clip_top, clip_bottom) = clip.y_bounds();
        top = top.max(clip_top);
        bottom = bottom.min(clip_bottom);
    }
    let height = bottom - top;
    if height <= 0.0 {
        return Vec::new();
    }

    // A square upright shape is its own rectangle, and a square upright clip
    // cuts it to another one.
    //
    // The band loop below would arrive at the same answer — it merges bands
    // that round alike, and for a square shape that is all of them — but it
    // would take about six microseconds to do it, against twenty nanoseconds
    // here. That is per region, per frame, and a bar of thirty pills declaring
    // input regions pays it thirty times. Worth a branch.
    if shape.is_a_box() && clips.iter().all(PlacedShape::is_a_box) {
        let boxed = clips.iter().try_fold(shape.world_aabb(), |boxed, clip| {
            boxed.intersection(&clip.world_aabb())
        });
        return boxed.and_then(to_region_rect).into_iter().collect();
    }

    let outline = shape.outline();
    let clip_outlines: SmallVec<[Outline; 2]> = clips.iter().map(PlacedShape::outline).collect();
    // Whether anything is subtracted from a span, which only a scoop does.
    // Asked once, because the answer decides the shape of every band below:
    // an unbitten shape puts out one rectangle per band, and the band above
    // it is therefore the last one out. A bitten one can split, and then it
    // is not.
    let bitten = outline.is_bitten() || clip_outlines.iter().any(Outline::is_bitten);

    // The outer bounds at a scanline: where the shape is before any bite is
    // taken out, narrowed to where every clip is. Convex, so one interval.
    let bounds = |y: f32| -> Option<(f32, f32)> {
        let (mut left, mut right) = outline.bounds_at(y)?;
        for clip in &clip_outlines {
            let (clip_left, clip_right) = clip.bounds_at(y)?;
            left = left.max(clip_left);
            right = right.min(clip_right);
        }
        (left < right).then_some((left, right))
    };

    // One band per pixel: `to_region_rect` rounds each band's edges to whole
    // numbers, so a band finer than a pixel cannot produce a row the output can
    // tell apart — it only tightens the inscribed span by a fraction. Half-pixel
    // bands cost twice the spans for that fraction, which on a small shape is
    // the whole of the work.
    let bands = (height.ceil() as usize).clamp(4, 512);
    let band_h = height / bands as f32;

    let mut out: Vec<RegionRect> = Vec::new();
    // Where the previous band put its rectangles, so this one can grow them
    // rather than stack another row on top. A band emits more than one only
    // where a bite has split it, so this is one entry almost always — and
    // inline, because a heap allocation per band is one per output pixel row
    // and this runs per input region per frame.
    let mut previous: SmallVec<[usize; 2]> = SmallVec::new();
    // Every interior boundary is shared by the band above and the band below,
    // so each is computed once and carried forward.
    let mut upper = bounds(top);
    for i in 0..bands {
        let y0 = top + i as f32 * band_h;
        let y1 = y0 + band_h;
        let lower = bounds(y1);
        let (Some((a0, b0)), Some((a1, b1))) = (upper, lower) else {
            upper = lower;
            previous.clear();
            continue;
        };
        upper = lower;
        // The tighter of the band's two edges keeps the slab inside the curve:
        // the outer boundary is convex, so between them neither is narrower.
        let band = (a0.max(a1), b0.min(b1));
        // The two boundaries may not overlap at all, and everything below
        // takes a band that is a real interval: `subtract` keeps whatever it
        // is given in order, so an inverted seed would travel as far as the
        // rounding before anything noticed.
        if band.0 >= band.1 {
            previous.clear();
            continue;
        }
        // Then each shape takes its bites out, at their widest across the
        // band. A bite is a disc, whose widest chord can sit strictly between
        // two scanlines, so this cannot be read off the two edges the way the
        // convex part can.
        if !bitten {
            // Every curvature but the scoop, which is almost every region
            // there is. One span, and the rectangle it grows is the last one
            // out — the path this loop had before a span became a list, kept
            // because the list costs about a third again per band and these
            // shapes have nothing to spend it on.
            place(&mut out, band, y0, band_h, None);
            continue;
        }

        let mut spans = Spans::new();
        spans.push(band);
        outline.take_bites_from(&mut spans, y0, y1);
        for clip in &clip_outlines {
            clip.take_bites_from(&mut spans, y0, y1);
        }

        let mut current: SmallVec<[usize; 2]> = SmallVec::new();
        for span in spans {
            current.extend(place(&mut out, span, y0, band_h, Some(&previous)));
        }
        previous = current;
    }
    out
}

/// Put one band's span out as a rectangle, growing the one above it where the
/// two line up rather than stacking a second row on it. That merging is what
/// keeps the straight middle of an upright shape at one rectangle instead of
/// one per band.
///
/// `above` is where the previous band put *its* rectangles, and `None` says
/// there is only ever one of them — so the one to grow, if any, is the last
/// one out. Only a bitten shape needs the list, and only because a bite can
/// split a band in two.
///
/// Returns where the span ended up, which is what the next band needs and
/// only a bitten one keeps, or `None` where the rounding leaves no rectangle
/// at all. Every span reaching here is a real interval — the band loop drops
/// an empty band before it splits one, and `subtract` cannot make an empty
/// span out of a real one.
#[inline]
fn place(
    out: &mut Vec<RegionRect>,
    (left, right): (f32, f32),
    y0: f32,
    band_h: f32,
    above: Option<&SmallVec<[usize; 2]>>,
) -> Option<usize> {
    let rect = to_region_rect(Rect::new(left, y0, right - left, band_h))?;
    let grows = |prev: &RegionRect| {
        prev.x == rect.x && prev.width == rect.width && prev.y + prev.height == rect.y
    };
    let existing = match above {
        Some(above) => above.iter().copied().find(|&i| grows(&out[i])),
        None => out.last().is_some_and(grows).then(|| out.len() - 1),
    };
    Some(match existing {
        Some(i) => {
            out[i].height += rect.height;
            i
        }
        None => {
            out.push(rect);
            out.len() - 1
        }
    })
}

/// Round-to-nearest on all four edges so adjacent slabs tile without gaps
/// (inward rounding would drop sub-pixel slabs). `None` when the rounding
/// collapses the rectangle to nothing.
fn to_region_rect(b: Rect) -> Option<RegionRect> {
    let x0 = b.x.round() as i32;
    let y0 = b.y.round() as i32;
    let x1 = (b.x + b.width).round() as i32;
    let y1 = (b.y + b.height).round() as i32;
    (x1 > x0 && y1 > y0).then_some(RegionRect {
        x: x0,
        y: y0,
        width: x1 - x0,
        height: y1 - y0,
    })
}

/// One declaration of where input reaches a surface, in the order it was
/// painted.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct InputRegionOp {
    /// Whether input reaches this rectangle. `false` cuts it out of whatever
    /// came before.
    pub takes: bool,
    pub rect: RegionRect,
}

/// What a surface asks the compositor about where input reaches it: the area
/// it takes before any container has spoken, and the declarations that came
/// out of the frame.
///
/// Two fields rather than one resolved list, because a rounded hole cut out of
/// a surface is not a union of rectangles anyone should have to compute:
/// `wl_region` subtracts, and this is that program in the order it is applied.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub(crate) struct InputRegionRequest {
    pub base: Vec<RegionRect>,
    pub ops: Vec<InputRegionOp>,
}

/// The input declarations of the frame that was just drawn, in paint order.
///
/// Read off the flattened commands for the reason
/// [`crate::blur::regions_from_commands`] gives at length: a container that did
/// not paint has no command here, so a hidden, culled or replaced declaration
/// takes itself back without anyone having to remember it.
///
/// Not sorted, unlike a blur region: these compose, and the order they compose
/// in is the order they were painted in.
pub(crate) fn input_ops_from_commands(
    commands: &[FlattenedCommand],
    chains: &ClipChains,
) -> Vec<InputRegionOp> {
    let mut out = Vec::new();
    for cmd in commands {
        let DrawCommand::InputRegion {
            rect,
            corner_radii,
            curvature,
            takes,
        } = &*cmd.command
        else {
            continue;
        };
        out.extend(
            shape_of(cmd, chains, *rect, *corner_radii, *curvature)
                .into_iter()
                .map(|rect| InputRegionOp {
                    takes: *takes,
                    rect,
                }),
        );
    }
    out
}

/// The rectangles one command's rounded rect becomes, cut to what the command
/// is allowed to show.
///
/// **The shape, turned.** A command carries the transform it is drawn through,
/// so the region is tessellated from the placed shape rather than from the box
/// around it — a rotated container takes clicks where it is, and blurs the
/// desktop where it is, rather than over the square it happens to sit inside.
///
/// The clips are shapes here too, every one of them, and intersected scanline
/// by scanline rather than as boxes — so a card inside a rounded scroller is
/// cornered by the scroller, a turned clip cuts what it actually covers, and a
/// clip that could not be merged with the ones above it is met by each of them
/// in turn. `chains` is the frame's, which the command's clip hangs from.
pub(crate) fn shape_of(
    cmd: &FlattenedCommand,
    chains: &ClipChains,
    rect: Rect,
    corner_radii: CornerRadii,
    curvature: f32,
) -> Vec<RegionRect> {
    let clips: SmallVec<[PlacedShape; 2]> = match cmd.clip() {
        Some(clip) => chains.shapes(&clip).copied().collect(),
        None => SmallVec::new(),
    };
    placed_shape_to_rects(
        PlacedShape::placed(rect, corner_radii, curvature, cmd.world_transform),
        &clips,
    )
}

/// The area a surface takes input in before any container has spoken: the
/// whole of it, or whatever the surface itself declared, at creation or since.
///
/// A surface that says nothing takes input everywhere, which is what the
/// protocol's null region means. `click_through` is the same declaration with
/// nothing in it, and a declaration cuts the base down to the rectangles it
/// names.
pub(crate) fn base_rects(declared: Option<&[Rect]>, width: f32, height: f32) -> Vec<RegionRect> {
    match declared {
        None => Vec::from_iter(RegionRect::covering(Rect::new(0.0, 0.0, width, height))),
        Some(rects) => rects
            .iter()
            .copied()
            .filter_map(RegionRect::covering)
            .collect(),
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::transform::Transform;

    fn covers(rects: &[RegionRect], x: i32, y: i32) -> bool {
        rects.iter().any(|r| r.contains(x, y))
    }

    /// The commonest shape there is: no transform at all.
    fn upright(rect: Rect, radii: CornerRadii) -> Vec<RegionRect> {
        placed_shape_to_rects(shape(rect, radii, Transform::IDENTITY), &[])
    }

    fn shape(rect: Rect, radii: CornerRadii, placement: Transform) -> PlacedShape {
        PlacedShape::placed(rect, radii, 1.0, placement)
    }

    fn round(radius: f32) -> CornerRadii {
        CornerRadii::uniform(radius)
    }

    #[test]
    fn zero_radius_is_bounding_box() {
        let rects = upright(Rect::new(10.0, 20.0, 100.0, 50.0), round(0.0));
        assert_eq!(
            rects,
            vec![RegionRect {
                x: 10,
                y: 20,
                width: 100,
                height: 50
            }]
        );
    }

    #[test]
    fn degenerate_rect_is_empty() {
        assert!(upright(Rect::new(0.0, 0.0, 0.0, 40.0), round(8.0)).is_empty());
        assert!(upright(Rect::new(0.0, 0.0, 40.0, -1.0), round(8.0)).is_empty());
    }

    #[test]
    fn rounded_corners_are_cut() {
        let rects = upright(Rect::new(0.0, 0.0, 100.0, 60.0), round(20.0));
        // Corner pixels outside the curve are not covered…
        assert!(!covers(&rects, 0, 0));
        assert!(!covers(&rects, 99, 0));
        assert!(!covers(&rects, 0, 59));
        assert!(!covers(&rects, 99, 59));
        // …while the center and edge midpoints are.
        assert!(covers(&rects, 50, 30));
        assert!(covers(&rects, 0, 30));
        assert!(covers(&rects, 99, 30));
        assert!(covers(&rects, 50, 0));
        assert!(covers(&rects, 50, 59));
    }

    #[test]
    fn slabs_stay_inside_the_curve() {
        let r = 16.0f32;
        let rects = upright(Rect::new(0.0, 0.0, 80.0, 80.0), round(r));
        for rect in &rects {
            // Every rect corner must be inside (or on) the rounded shape,
            // with half-pixel tolerance for edge rounding.
            for (px, py) in [
                (rect.x, rect.y),
                (rect.x + rect.width, rect.y),
                (rect.x, rect.y + rect.height),
                (rect.x + rect.width, rect.y + rect.height),
            ] {
                let (px, py) = (px as f32, py as f32);
                let cx = px.clamp(r, 80.0 - r);
                let cy = py.clamp(r, 80.0 - r);
                let dist = ((px - cx).powi(2) + (py - cy).powi(2)).sqrt();
                assert!(
                    dist <= r + 0.75,
                    "corner ({px}, {py}) is {dist} from the curve center, radius {r}"
                );
            }
        }
    }

    #[test]
    fn radius_clamped_to_half_size() {
        // Radius larger than half the shape: a circle-ish region, still non-empty
        let rects = upright(Rect::new(0.0, 0.0, 40.0, 40.0), round(100.0));
        assert!(!rects.is_empty());
        assert!(covers(&rects, 20, 20), "the middle is covered");
        assert!(!covers(&rects, 0, 0), "the corner is not");
    }

    /// Two corners on one edge meet and do not cross, however large they are
    /// asked to be.
    ///
    /// This is what lets the tessellator take the shader's per-corner clamp
    /// instead of the proportional factor it used to (#417). Each clamped
    /// radius is at most half the *smaller* side, so two sharing an edge sum
    /// to at most the whole of that edge — the straight run between them
    /// shrinks to nothing and never runs backwards. An edge that ran
    /// backwards would put the outline's own points out of order, and
    /// `span_at` takes a min and a max over them, so it would answer with a
    /// span reaching past the shape rather than failing.
    ///
    /// Asked here at the limit and well past it, on a square and on both
    /// oblong shapes, because the clamp is by the smaller side and the wrong
    /// one is easy to write.
    #[test]
    fn two_corners_on_one_edge_meet_rather_than_cross() {
        use crate::widgets::Corners;

        for (w, h) in [(40.0_f32, 40.0_f32), (120.0, 40.0), (40.0, 120.0)] {
            for r in [(w.min(h)) / 2.0, w.min(h), 500.0] {
                let shape = PlacedShape::placed(
                    Rect::new(0.0, 0.0, w, h),
                    round(r),
                    1.0,
                    Transform::IDENTITY,
                );
                let rects = placed_shape_to_rects(shape, &[]);
                assert!(
                    !rects.is_empty(),
                    "{w}x{h} r={r}: the shape has an area and the region has none"
                );

                // Nothing published may be outside what the shader draws —
                // the promise a crossed edge would break silently.
                let corners = Corners {
                    radii: round(r),
                    curvature: 1.0,
                };
                let local = Rect::new(0.0, 0.0, w, h);
                for rect in &rects {
                    for y in rect.y..rect.y + rect.height {
                        for x in rect.x..rect.x + rect.width {
                            assert!(
                                local.contains_shape(x as f32 + 0.5, y as f32 + 0.5, corners),
                                "{w}x{h} r={r}: ({x}, {y}) is published and not drawn"
                            );
                        }
                    }
                }
            }
        }
    }

    /// A square corner is square. This is the seam the region used to be lost
    /// at: a clip squared off two corners, the caller collapsed the four radii
    /// with `.max()`, and the shape arrived here as though all four were round —
    /// so the region gave back a wedge the size of the radius along the cut,
    /// which is the artefact the clipping exists to prevent.
    #[test]
    fn a_square_corner_is_not_rounded_because_another_one_is() {
        let rects = upright(
            Rect::new(0.0, 0.0, 40.0, 100.0),
            CornerRadii {
                top_left: 16.0,
                top_right: 0.0,
                bottom_right: 0.0,
                bottom_left: 16.0,
            },
        );

        assert!(
            covers(&rects, 39, 0) && covers(&rects, 39, 99),
            "the cut edge is straight, so its corners reach the edge"
        );
        assert!(
            !covers(&rects, 0, 0) && !covers(&rects, 0, 99),
            "and the round ones are still cut"
        );
    }

    /// Only the corner that has a radius is cut. A list row rounding its top
    /// corners and butting against the next one keeps its full bottom edge.
    #[test]
    fn corners_are_cut_one_by_one() {
        let rects = upright(Rect::new(0.0, 0.0, 100.0, 60.0), CornerRadii::top(20.0));

        assert!(!covers(&rects, 0, 0) && !covers(&rects, 99, 0), "top cut");
        assert!(
            covers(&rects, 0, 59) && covers(&rects, 99, 59),
            "bottom square"
        );
    }

    /// An unevenly scaled corner is an ellipse: a circle of 16 under a 2×1
    /// scale is 32 wide and 16 tall, and reaches the left edge 16 down where a
    /// circle of either radius would not.
    ///
    /// The ellipse now comes from the transform rather than from a radius pair
    /// carried alongside it, which is the only place it ever came from: the
    /// renderer scaled all four corners by one `(sx, sy)`, so four corners with
    /// four different axis ratios was a shape nothing could draw.
    #[test]
    fn an_elliptical_corner_is_cut_on_both_of_its_axes() {
        let rects = placed_shape_to_rects(
            shape(
                Rect::new(0.0, 0.0, 100.0, 100.0),
                round(16.0),
                Transform::scale_xy(2.0, 1.0),
            ),
            &[],
        );

        assert!(!covers(&rects, 0, 0), "the corner itself is outside");
        assert!(
            covers(&rects, 0, 20),
            "the curve is 16 tall, so the left edge is reached by 20 down"
        );
        assert!(
            !covers(&rects, 5, 1),
            "and 32 wide, so it is still outside 5 in at the top"
        );
    }

    /// Every emitted rect stays inside the ellipse it approximates, for radii
    /// that differ per corner under a scale that differs per axis — the
    /// property the whole tessellation exists to have, checked where the shape
    /// is least uniform.
    #[test]
    fn slabs_stay_inside_a_shape_with_four_different_corners() {
        let declared = CornerRadii {
            top_left: 30.0,
            top_right: 10.0,
            bottom_right: 0.0,
            bottom_left: 20.0,
        };
        let (sx, sy) = (1.2f32, 2.0f32);
        let (w, h) = (100.0f32, 50.0f32);
        // What the *shader* draws, which is what the region has to stay
        // inside: each corner at most half the smaller side, so the 30 is cut
        // to 25 on a box this shape. The expectations below used the declared
        // 30 and passed only because the tessellator used to clamp by a
        // proportional factor, which for these four radii is 1 — it agreed
        // with the old region rather than with the pixels (#417).
        let half = (w * 0.5).min(h * 0.5);
        let radii = CornerRadii {
            top_left: declared.top_left.min(half),
            top_right: declared.top_right.min(half),
            bottom_right: declared.bottom_right.min(half),
            bottom_left: declared.bottom_left.min(half),
        };
        let rects = placed_shape_to_rects(
            PlacedShape::placed(
                Rect::new(0.0, 0.0, w, h),
                declared,
                1.0,
                Transform::scale_xy(sx, sy),
            ),
            &[],
        );
        assert!(!rects.is_empty());

        // Each corner's ellipse centre and semi-axes, in surface pixels.
        let (ww, hh) = (w * sx, h * sy);
        let corners = [
            (
                radii.top_left * sx,
                radii.top_left * sy,
                radii.top_left * sx,
                radii.top_left * sy,
                true,
                true,
            ),
            (
                ww - radii.top_right * sx,
                radii.top_right * sy,
                radii.top_right * sx,
                radii.top_right * sy,
                false,
                true,
            ),
            (
                radii.bottom_left * sx,
                hh - radii.bottom_left * sy,
                radii.bottom_left * sx,
                radii.bottom_left * sy,
                true,
                false,
            ),
        ];
        for rect in &rects {
            for (px, py) in [
                (rect.x, rect.y),
                (rect.x + rect.width, rect.y),
                (rect.x, rect.y + rect.height),
                (rect.x + rect.width, rect.y + rect.height),
            ] {
                let (px, py) = (px as f32, py as f32);
                for (cx, cy, rx, ry, left, top) in corners {
                    let in_x = if left { px < cx } else { px > cx };
                    let in_y = if top { py < cy } else { py > cy };
                    if !in_x || !in_y {
                        continue;
                    }
                    let d = ((px - cx) / rx).powi(2) + ((py - cy) / ry).powi(2);
                    assert!(
                        d <= 1.0 + 0.1,
                        "({px}, {py}) is outside the {rx}x{ry} corner at ({cx}, {cy}): {d}"
                    );
                }
            }
        }
    }

    /// Each side runs between the two corners that are actually on it.
    ///
    /// Asked of `span_at` directly, at the exact scanline of the bottom edge,
    /// because the tessellation cannot see this: a band is evaluated at both of
    /// its ends and takes the narrower, so the bottom edge's own scanline is
    /// always paired with one above it and the narrower one wins. The bottom
    /// edge ran from `x1 - bottom_left` — the wrong corner, and `bottom_right`
    /// appeared nowhere in it — which is invisible while all four radii agree
    /// and produces a side that overshoots its corner when they do not.
    #[test]
    fn a_side_ends_where_its_own_corners_begin() {
        let shape = PlacedShape {
            rect: Rect::new(0.0, 0.0, 100.0, 100.0),
            radii: CornerRadii {
                top_left: 0.0,
                top_right: 0.0,
                bottom_right: 30.0,
                bottom_left: 0.0,
            },
            curvature: 1.0,
            placement: Transform::IDENTITY,
        };

        // Within a thousandth: the corner's own end of the side comes back
        // through the arc solve, which is trigonometry and not arithmetic.
        let close = |a: f32, b: f32| (a - b).abs() < 1e-3;

        let (left, right) = shape.span_at(100.0).expect("the bottom edge is there");
        assert!(
            close(left, 0.0),
            "square at the bottom left, so the side reaches — got {left}"
        );
        assert!(
            close(right, 70.0),
            "and stops where the 30-radius bottom-right corner starts — got {right}"
        );

        // The opposite corner, so a fix that swaps the two is not a fix.
        let mirrored = PlacedShape {
            radii: CornerRadii {
                bottom_right: 0.0,
                bottom_left: 30.0,
                ..shape.radii
            },
            ..shape
        };
        let (left, right) = mirrored.span_at(100.0).expect("the bottom edge is there");
        assert!(
            close(left, 30.0) && close(right, 100.0),
            "got ({left}, {right})"
        );
    }

    /// The single-rectangle shortcut asks whether a corner is small *on the
    /// surface*, not in the space the widget wrote it in.
    ///
    /// A radius of 0.4 under a `scale(8.0)` is three pixels of curve. Measured
    /// where it was declared it looks like nothing and the whole box is
    /// published, corners and all.
    #[test]
    fn a_corner_is_small_enough_to_ignore_only_once_it_is_on_screen() {
        let scaled = placed_shape_to_rects(
            PlacedShape::placed(
                Rect::new(0.0, 0.0, 20.0, 20.0),
                round(0.4),
                1.0,
                Transform::scale(8.0),
            ),
            &[],
        );
        assert!(
            !covers(&scaled, 0, 0),
            "3 pixels of curve is a cut corner, not a rounding error"
        );

        // And the shortcut still fires where it should, or every upright panel
        // pays for a stack of bands.
        let tiny = placed_shape_to_rects(
            PlacedShape::placed(
                Rect::new(0.0, 0.0, 100.0, 50.0),
                round(0.4),
                1.0,
                Transform::IDENTITY,
            ),
            &[],
        );
        assert_eq!(tiny.len(), 1, "one rectangle, as it has always been");
    }

    /// A bigger corner is sampled at more points, so the accuracy holds as the
    /// shape grows.
    ///
    /// `samples_per_corner` is the one number the whole argument rests on — the
    /// sag of a chord across an angle is `r·θ²/8`, so the count has to rise
    /// with the square root of the radius *as it lands on the surface*, not as
    /// it was declared. Nothing watched it: replacing the body with a constant
    /// 2 passed the entire suite, including the coverage test above, because a
    /// small corner needs about two points anyway.
    ///
    /// This is the same shape twice, once scaled eight times, and the second
    /// one is where a fixed count runs out.
    #[test]
    fn a_corner_is_sampled_finely_enough_at_the_size_it_is_drawn() {
        use crate::widgets::Corners;

        let coverage = |scale: f32| {
            let placement = Transform::scale(scale);
            let shape = PlacedShape::placed(
                Rect::new(0.0, 0.0, 120.0, 120.0),
                round(40.0),
                2.0,
                placement,
            );
            let rects = placed_shape_to_rects(shape, &[]);
            let local = Rect::new(0.0, 0.0, 120.0, 120.0);
            let corners = Corners::superellipse(40.0, 2.0);
            let to_local = placement.inverse().expect("invertible");
            let inside = |x: i32, y: i32| {
                let (lx, ly) = to_local.transform_point(x as f32 + 0.5, y as f32 + 0.5);
                local.contains_shape(lx, ly, corners)
            };

            let covered: i64 = rects.iter().map(|r| r.width as i64 * r.height as i64).sum();
            let side = (120.0 * scale) as i32 + 4;
            let mut drawn = 0i64;
            for y in -2..side {
                for x in -2..side {
                    if inside(x, y) {
                        drawn += 1;
                    }
                }
            }
            (covered, drawn)
        };

        // A corner eight times the size gets more points, so it is cut *more*
        // accurately, not less. A fixed count goes the other way and flattens
        // out: measured, 98.85% then 99.75% with the count as written, against
        // 97.71% and 98.16% with it replaced by a constant 2. The bar at scale
        // 8 is what tells the two apart.
        let (covered, drawn) = coverage(1.0);
        assert!(
            covered * 1000 >= drawn * 985,
            "at scale 1 the region covers {covered} of {drawn}"
        );
        let (covered, drawn) = coverage(8.0);
        assert!(
            covered * 1000 >= drawn * 995,
            "at scale 8 the region covers {covered} of {drawn} — a corner eight \
             times the size needs more points, not the same number spread \
             further apart"
        );
    }

    /// What sampling a corner costs the compositor, in rectangles.
    ///
    /// A region is a list `wl_region` receives and the compositor diffs, so the
    /// count is the price of the accuracy above. A circle keeps its closed form
    /// and is unchanged; the sampled curvatures pay for the bands their extra
    /// vertices introduce.
    #[test]
    fn sampling_a_corner_does_not_multiply_the_rectangles() {
        let count = |k: f32| {
            placed_shape_to_rects(
                PlacedShape::placed(
                    Rect::new(0.0, 0.0, 300.0, 120.0),
                    round(40.0),
                    k,
                    Transform::IDENTITY,
                ),
                &[],
            )
            .len()
        };
        let circle = count(1.0);
        for k in [0.5_f32, 2.0] {
            assert!(
                count(k) <= circle * 2,
                "k={k} publishes {} rectangles against the circle's {circle}",
                count(k)
            );
        }
    }

    /// The region is inside the shape, and nearly all of it.
    ///
    /// Two promises, and they pull opposite ways. A region that claims a pixel
    /// the shape does not cover sends a click to a surface that did not draw
    /// there — so every published rectangle has to be inside. A region that
    /// gives up pixels the shape does cover drops clicks on painted pixels, and
    /// they fall through to whatever is behind — so it has to give up almost
    /// none.
    ///
    /// Checked against the same signed distance the shader draws with, over
    /// every curvature the public API names, one between them, and two above
    /// the ledge where the norm used to overflow — the region and the shape
    /// disagreeing is exactly what #411 would have looked like from here, and
    /// nothing was asking.
    ///
    /// #400 was the second promise broken at k > 1: the corner was published
    /// as the circle inscribed in the squircle, 14% of each corner box short.
    /// #410 was the scoop breaking it by more: its corner was cut by a chord
    /// tangent to the bite rather than by the bite, which gave up 17% of the
    /// whole shape. Every curvature is held to both promises now, at 45
    /// degrees as well as 20 — the angle where a bite is most likely to split
    /// a scanline in two, and where keeping only the wider half of a split
    /// gives up 512 of the shape's 9392 pixels, 5.5%.
    ///
    /// And sheared, which is not the same as turned: a rotation maps a disc to
    /// a disc, and a rotation with a non-uniform scale after it maps one to a
    /// tilted ellipse. Nothing else here can tell those apart, and the bite
    /// arithmetic is the one thing that has to.
    #[test]
    fn a_region_is_inside_its_shape_and_almost_all_of_it() {
        use crate::widgets::Corners;

        let size = 120.0;
        // A turn, and a turn with a non-uniform scale after it — which is
        // what `container().rotate(20.0).scale(Scale::new(2.0, 1.0))`
        // composes. The second is not a rotation: it shears, and a sheared
        // circle is a tilted ellipse whose horizontal chord *slides* sideways
        // as it grows. Nothing else here can tell the two apart.
        let placements = [
            ("turned", Transform::rotate_degrees(0.0)),
            ("turned", Transform::rotate_degrees(20.0)),
            ("turned", Transform::rotate_degrees(45.0)),
            (
                "sheared",
                Transform::rotate_degrees(20.0).then(&Transform::scale_xy(2.0, 1.0)),
            ),
            (
                "sheared",
                Transform::rotate_degrees(45.0).then(&Transform::scale_xy(4.0, 1.0)),
            ),
        ];
        for k in [0.0_f32, 0.5, 1.0, 2.0, 5.0, 8.0, -1.0] {
            for (degrees, placement) in placements {
                let shape =
                    PlacedShape::placed(Rect::new(0.0, 0.0, size, size), round(40.0), k, placement);
                let rects = placed_shape_to_rects(shape, &[]);
                let local = Rect::new(0.0, 0.0, size, size);
                let corners = Corners::superellipse(40.0, k);
                let to_local = placement.inverse().expect("invertible");

                let inside = |x: i32, y: i32| {
                    let (lx, ly) = to_local.transform_point(x as f32 + 0.5, y as f32 + 0.5);
                    local.contains_shape(lx, ly, corners)
                };

                let mut claimed_outside = 0;
                let mut covered = 0;
                for rect in &rects {
                    for y in rect.y..rect.y + rect.height {
                        for x in rect.x..rect.x + rect.width {
                            covered += 1;
                            if !inside(x, y) {
                                claimed_outside += 1;
                            }
                        }
                    }
                }

                let mut drawn = 0;
                for y in -200..260 {
                    for x in -200..260 {
                        if inside(x, y) {
                            drawn += 1;
                        }
                    }
                }

                // Zero, not a tolerance. This is the promise that sends a
                // click to a surface which did not draw there, and it is zero
                // in every configuration here — a bound set near the observed
                // value is the one that notices it breaking.
                assert_eq!(
                    claimed_outside, 0,
                    "k={k} at {degrees}°: {claimed_outside} of {covered} published \
                     pixels are outside the shape, which has {drawn}"
                );
                assert!(
                    covered * 100 >= drawn * 97,
                    "k={k} at {degrees}°: the region covers {covered} of \
                     the shape's {drawn} pixels, and has given up too many"
                );
            }
        }
    }

    /// An unequal pair of corners is clamped the way the *shader* clamps it.
    ///
    /// There are two rules and they are not the same one. `clamp_radii`
    /// shrinks all four corners by a single factor so no two sharing an edge
    /// can overlap — the rule CSS `border-radius` uses. The shader, and
    /// `Rect::shape_distance` with it, clamps each corner on its own:
    /// `min(radius, min(half_w, half_h))`. They agree whenever the four radii
    /// agree, which is every other test here, and diverge as soon as they do
    /// not — so the region was a claim about a shape nobody drew.
    ///
    /// Measured before the tessellator moved onto the shader's rule: at
    /// `tl = 100, tr = 40` on a 120x120 box the proportional factor scaled
    /// `tr` down to 34.3 where the shader keeps 40, and the region claimed 74
    /// pixels the shape does not cover. `top(50.0)` on a 120x60 box was the
    /// same divergence the other way — 89.2% covered for a round corner, and
    /// 55.7% for a scoop.
    ///
    /// **Two of them cannot cross, which is the whole of what the
    /// proportional rule was there to prevent.** Each clamped radius is at
    /// most half the *smaller* side, so two on one edge sum to at most the
    /// whole of it: they can meet exactly, leaving a straight run of zero
    /// length, and never overlap. A scoop reached this first in #410, where
    /// it was easier to argue because a bite is subtracted and two
    /// overlapping bites would have been harmless anyway. The traced corners
    /// are #417 and needed the argument above.
    #[test]
    fn an_unequal_pair_of_corners_is_clamped_the_way_the_shader_clamps_it() {
        use crate::widgets::{Corners, Rect as WRect};

        for (w, h, radii) in [
            (
                120.0_f32,
                60.0_f32,
                CornerRadii {
                    top_left: 50.0,
                    top_right: 50.0,
                    bottom_right: 0.0,
                    bottom_left: 0.0,
                },
            ),
            (
                120.0,
                120.0,
                CornerRadii {
                    top_left: 100.0,
                    top_right: 40.0,
                    bottom_right: 0.0,
                    bottom_left: 0.0,
                },
            ),
            // The same shape on its side. The shader's clamp is
            // `min(r, min(half_w, half_h))`, and a box that is only ever
            // limited by its height leaves the width half of that untested —
            // both shapes above are, so mutating `width * 0.5` changed
            // nothing and nothing objected.
            (
                60.0,
                120.0,
                CornerRadii {
                    top_left: 50.0,
                    top_right: 0.0,
                    bottom_right: 0.0,
                    bottom_left: 50.0,
                },
            ),
        ] {
            for k in [-1.0_f32, 0.0, 0.5, 1.0, 2.0] {
                let shape =
                    PlacedShape::placed(WRect::new(0.0, 0.0, w, h), radii, k, Transform::IDENTITY);
                let rects = placed_shape_to_rects(shape, &[]);
                let local = WRect::new(0.0, 0.0, w, h);
                let corners = Corners {
                    radii,
                    curvature: k,
                };
                let inside =
                    |x: i32, y: i32| local.contains_shape(x as f32 + 0.5, y as f32 + 0.5, corners);

                let (mut covered, mut outside) = (0, 0);
                for r in &rects {
                    for y in r.y..r.y + r.height {
                        for x in r.x..r.x + r.width {
                            covered += 1;
                            if !inside(x, y) {
                                outside += 1;
                            }
                        }
                    }
                }
                let mut drawn = 0;
                for y in -50..250 {
                    for x in -50..250 {
                        if inside(x, y) {
                            drawn += 1;
                        }
                    }
                }

                assert_eq!(
                    outside, 0,
                    "k={k} {w}x{h} {radii:?}: {outside} of {covered} published \
                 pixels are outside a shape with {drawn}"
                );
                assert!(
                    covered * 100 >= drawn * 97,
                    "k={k} {w}x{h} {radii:?}: the region covers {covered} of the shape's \
                 {drawn} pixels — the corner is not the one the shader cuts"
                );
            }
        }
    }

    /// Each curvature is cut as itself, and the two that are not sampled are
    /// the two that need no sampling.
    ///
    /// `Corners::bevel` is K = 0 — a straight diagonal across the corner. The
    /// chord between the arc's ends is not an approximation of it, it *is* it,
    /// and cutting a circle there would have a bevelled container blur the
    /// desktop past its own cut and take clicks there. A circle is K = 1 and
    /// keeps the closed-form solve. Everything between and above them is
    /// sampled, which is where #400 lived: a squircle was cut as the circle
    /// inscribed in it.
    #[test]
    fn each_curvature_is_cut_as_the_curve_it_is() {
        let corner = |curvature: f32| {
            placed_shape_to_rects(
                PlacedShape::placed(
                    Rect::new(0.0, 0.0, 100.0, 100.0),
                    round(40.0),
                    curvature,
                    Transform::IDENTITY,
                ),
                &[],
            )
        };

        // 12 in from the left, 12 down: inside a 40 circle (√2·12 = 17 < 40 of
        // inset), outside the bevel, whose chord runs from (0,40) to (40,0).
        assert!(
            covers(&corner(1.0), 12, 12),
            "the circle reaches this pixel"
        );
        assert!(
            !covers(&corner(0.0), 12, 12),
            "and the bevel does not, because the chord has already cut it"
        );

        // A squircle is larger than the circle drawn inside it, so a point the
        // circle reaches is one the squircle reaches too.
        assert!(covers(&corner(2.0), 12, 12));

        // The other way round is what #400 was. 9 in and 9 down sits inside the
        // squircle — 2·31^4 is 1,847,042 against 40^4 of 2,560,000 — and
        // outside the circle, since 31·√2 is 43.8 and the radius is 40. The
        // region published the circle, so the compositor was told the surface
        // stops 7.6 pixels short of where it is drawn, along each corner
        // diagonal. For the blur that is a corner slightly under-blurred; for
        // the input region it is a wedge where a click falls through to
        // whatever is behind.
        assert!(
            covers(&corner(2.0), 9, 9),
            "a squircle reaches past the circle inscribed in it, and the \
             region has to reach with it"
        );

        let area = |rects: Vec<RegionRect>| -> i64 {
            rects.iter().map(|r| r.width as i64 * r.height as i64).sum()
        };
        assert!(
            area(corner(0.0)) < area(corner(1.0)),
            "a bevel takes more off the corner than a circle does"
        );

        // And the chord runs between the two points where the corner meets its
        // sides — (0, 40) and (40, 0) for a radius of 40 — so `x + y = 40` is
        // the cut. A chord that starts from the wrong end of either side still
        // removes *a* triangle, and every assertion above is satisfied by the
        // wrong one; only the line itself says which.
        let bevel = corner(0.0);
        assert!(
            !covers(&bevel, 18, 18),
            "18 + 18 is short of the cut at 40, so the bevel has taken it"
        );
        assert!(
            covers(&bevel, 25, 25),
            "25 + 25 clears it, so the shape holds this one — a chord hung off \
             the wrong end of either side does not run through x + y = 40 and \
             gets one of these two wrong"
        );
        assert!(
            covers(&bevel, 2, 45) && covers(&bevel, 45, 2),
            "and just past each end of the chord the straight sides take over"
        );
    }

    /// A concave corner is cut outside the bite, not through it.
    ///
    /// `Corners::scoop` is K = -1, and the shader draws it as the square corner
    /// **minus a disc** of the same radius centred on that corner — so the
    /// shape reaches nearly to the corner along each edge and is bitten away
    /// around the diagonal. It is the one corner that is *not* a subset of the
    /// square, and the chord that makes a bevel safe runs straight through the
    /// bite: at `r/√2` from the corner, well inside a disc of `r`.
    ///
    /// So the chord retreats to where it is tangent, `r·√2` along each axis,
    /// and the straight edges retreat with it — an edge that stopped at `r`
    /// would cover the bite on its own.
    ///
    /// Checked against what the shader actually draws rather than against a
    /// radius: in the box, and no nearer any corner than its own radius.
    #[test]
    fn a_scooped_corner_is_cut_outside_the_bite() {
        let (w, h, r) = (120.0f32, 90.0f32, 28.0f32);
        let rects = placed_shape_to_rects(
            PlacedShape::placed(
                Rect::new(0.0, 0.0, w, h),
                round(r),
                -1.0,
                Transform::IDENTITY,
            ),
            &[],
        );
        assert!(!rects.is_empty(), "a scooped box is not empty");

        for rect in &rects {
            for (px, py) in [
                (rect.x, rect.y),
                (rect.x + rect.width, rect.y),
                (rect.x, rect.y + rect.height),
                (rect.x + rect.width, rect.y + rect.height),
            ] {
                let (px, py) = (px as f32, py as f32);
                assert!(
                    (-0.5..=w + 0.5).contains(&px) && (-0.5..=h + 0.5).contains(&py),
                    "({px}, {py}) is outside the box"
                );
                for (cx, cy) in [(0.0, 0.0), (w, 0.0), (0.0, h), (w, h)] {
                    let d = ((px - cx).powi(2) + (py - cy).powi(2)).sqrt();
                    assert!(
                        d >= r - 0.75,
                        "({px}, {py}) is {d} from the scooped corner ({cx}, {cy}), \
                         inside a bite of {r}"
                    );
                }
            }
        }

        // And it still publishes the middle, rather than retreating to nothing.
        assert!(covers(&rects, 60, 45));
    }

    /// Adjacent bands that round to the same span are one rectangle.
    ///
    /// **This is what keeps a region small.** A band is computed per pixel, so
    /// an upright 900-tall panel produces nine hundred of them and all but the
    /// corner ones are identical; merged, it publishes about fifteen
    /// rectangles. Without the merge it publishes nine hundred, every frame,
    /// down a socket — and every test here would still pass, because each of
    /// those rectangles is inside the shape and together they cover it.
    ///
    /// So the count is the assertion. It cannot be exact — it depends on how
    /// the corner curve rounds — but "tens, not hundreds" is the whole property
    /// and a broken merge misses it by two orders of magnitude.
    #[test]
    fn bands_that_round_alike_are_published_as_one_rectangle() {
        let tall = placed_shape_to_rects(
            PlacedShape::placed(
                Rect::new(0.0, 0.0, 200.0, 900.0),
                round(24.0),
                1.0,
                Transform::IDENTITY,
            ),
            &[],
        );
        assert!(
            tall.len() < 80,
            "a 900-tall panel is tens of rectangles, not one per band — got {}",
            tall.len()
        );
        assert!(covers(&tall, 100, 450), "and it still covers its middle");
        assert!(!covers(&tall, 1, 1), "with its corners cut");

        // The straight middle is the part that merges: the same panel with no
        // corners at all is a single rectangle by that route.
        let square = placed_shape_to_rects(
            PlacedShape::placed(
                Rect::new(0.0, 0.0, 200.0, 900.0),
                round(24.0),
                1.0,
                // A turn keeps it off the single-rectangle shortcut, so the
                // merge is what is being asked about rather than the fast path.
                Transform::rotate_degrees(90.0).center_at(100.0, 450.0),
            ),
            &[],
        );
        assert!(
            square.len() < 80,
            "a quarter turn is still an upright shape — got {}",
            square.len()
        );
    }

    /// Two boxes are cut to their overlap, and boxes that miss leave nothing.
    ///
    /// The single-rectangle shortcut does this intersection itself rather than
    /// through the band loop, so it is the one path where an edge comparison
    /// going the wrong way produces a rectangle nobody checked.
    #[test]
    fn two_boxes_are_cut_to_what_they_share() {
        let boxed = |x: f32, y: f32, w: f32, h: f32| {
            PlacedShape::placed(Rect::new(x, y, w, h), round(0.0), 1.0, Transform::IDENTITY)
        };

        assert_eq!(
            placed_shape_to_rects(
                boxed(0.0, 0.0, 100.0, 100.0),
                &[boxed(40.0, 30.0, 200.0, 200.0)]
            ),
            vec![RegionRect {
                x: 40,
                y: 30,
                width: 60,
                height: 70
            }],
            "the overlap, on both axes at once"
        );

        assert!(
            placed_shape_to_rects(boxed(0.0, 0.0, 50.0, 50.0), &[boxed(50.0, 0.0, 50.0, 50.0)])
                .is_empty(),
            "boxes that touch along an edge share no area"
        );
        assert!(
            placed_shape_to_rects(
                boxed(0.0, 0.0, 50.0, 50.0),
                &[boxed(500.0, 0.0, 50.0, 50.0)]
            )
            .is_empty(),
            "and ones that miss entirely leave nothing"
        );
    }

    /// A corner asked for more than the shape has is cut to half the *smaller*
    /// side, and the silhouette moves the way that implies.
    ///
    /// Each case puts a radius of 60 on a side of 60, so it halves to 30 —
    /// which the proportional rule and the shader's per-corner one both give,
    /// and that is why these four cases survived #417 unchanged. What they
    /// pin is the direction: which side is the smaller one decides how far
    /// the curve reaches, and reading the wrong extent turns the silhouette
    /// inside out.
    ///
    /// A pill is the everyday shape this protects: `corners(999)` on a bar is
    /// exactly the case where the clamp decides the whole outline.
    #[test]
    fn a_corner_over_budget_is_cut_to_half_the_smaller_side() {
        let cut = |w: f32, h: f32, radii: CornerRadii| {
            placed_shape_to_rects(
                PlacedShape::placed(Rect::new(0.0, 0.0, w, h), radii, 1.0, Transform::IDENTITY),
                &[],
            )
        };
        let pair = |a: f32, b: f32, c: f32, d: f32| CornerRadii {
            top_left: a,
            top_right: b,
            bottom_right: c,
            bottom_left: d,
        };

        // Each case puts 60 on a side of 60, so the radius is cut to 30.
        // Which way the silhouette moves depends on which side is the smaller
        // one: corners on the *short* side pull their curves inward and the
        // shape narrows, corners on the long one reach further along it and
        // the shape swells. So each case names a pixel and whether the shape
        // should hold it.
        for (label, rects, (x, y), inside) in [
            (
                "top pair, across the width",
                cut(60.0, 200.0, pair(60.0, 60.0, 0.0, 0.0)),
                (15, 5),
                true,
            ),
            (
                "bottom pair, across the width",
                cut(60.0, 200.0, pair(0.0, 0.0, 60.0, 60.0)),
                (15, 195),
                true,
            ),
            (
                "left pair, down the height",
                cut(200.0, 60.0, pair(60.0, 0.0, 0.0, 60.0)),
                (2, 15),
                false,
            ),
            (
                "right pair, down the height",
                cut(200.0, 60.0, pair(0.0, 60.0, 60.0, 0.0)),
                (197, 15),
                false,
            ),
        ] {
            assert_eq!(
                covers(&rects, x, y),
                inside,
                "{label}: the radius is cut to 30, and ({x}, {y}) is on the \
                 {} of the curve that leaves",
                if inside { "inside" } else { "outside" }
            );
        }
    }

    // -- clipped shapes -------------------------------------------------

    /// A card filling a rounded scroller is cornered by the scroller.
    ///
    /// The clip is intersected scanline by scanline rather than as a box, so
    /// its curve shows. Published as the scroller's square bounding box — which
    /// is what a box intersection gives — the compositor blurs the desktop in
    /// the four corners where the panel is not drawn, and on a click-through
    /// surface those corners swallow clicks.
    #[test]
    fn a_corner_the_clip_supplies_belongs_to_the_clip() {
        let square_card = PlacedShape::placed(
            Rect::new(-10.0, -10.0, 120.0, 120.0),
            round(0.0),
            1.0,
            Transform::IDENTITY,
        );
        let rounded_scroller = PlacedShape::placed(
            Rect::new(0.0, 0.0, 100.0, 100.0),
            round(24.0),
            1.0,
            Transform::IDENTITY,
        );

        let rects = placed_shape_to_rects(square_card, &[rounded_scroller]);
        assert!(
            !covers(&rects, 0, 0) && !covers(&rects, 99, 99),
            "the card declares square corners and the scroller cuts them anyway"
        );
        assert!(covers(&rects, 50, 50), "and the middle is still published");
    }

    /// A cut edge is straight, and only the corners along it are squared.
    ///
    /// A card scrolled half out of a viewport has a straight edge where the cut
    /// is. Published as though that side were still round, the region loses a
    /// wedge the size of the radius at each of its two corners.
    #[test]
    fn a_clip_squares_off_only_the_corners_it_cuts() {
        let card = PlacedShape::placed(
            Rect::new(0.0, 0.0, 100.0, 100.0),
            round(20.0),
            1.0,
            Transform::IDENTITY,
        );
        let cuts_the_right = PlacedShape::placed(
            Rect::new(-50.0, -50.0, 90.0, 200.0),
            round(0.0),
            1.0,
            Transform::IDENTITY,
        );

        let rects = placed_shape_to_rects(card, &[cuts_the_right]);
        assert!(
            covers(&rects, 39, 0) && covers(&rects, 39, 99),
            "the cut edge is straight, so its corners reach it"
        );
        assert!(
            !covers(&rects, 0, 0) && !covers(&rects, 0, 99),
            "and the card's own corners are still round"
        );
    }

    /// The tighter of the two curves is the one that shows, whichever shape it
    /// belongs to.
    #[test]
    fn two_curves_over_one_another_leave_the_tighter() {
        let same = Rect::new(0.0, 0.0, 100.0, 100.0);
        let rounded = |r: f32| PlacedShape::placed(same, round(r), 1.0, Transform::IDENTITY);

        let sharp_clip = placed_shape_to_rects(rounded(4.0), &[rounded(24.0)]);
        assert!(
            !covers(&sharp_clip, 2, 2),
            "the clip rounds harder, so the clip's corner is what is left"
        );
        let sharp_shape = placed_shape_to_rects(rounded(24.0), &[rounded(4.0)]);
        assert!(
            !covers(&sharp_shape, 2, 2),
            "and the other way round gives the same answer"
        );
    }

    /// A clip is placed by its own transform, so one inside a translated
    /// subtree cuts where it is rather than where it was declared.
    #[test]
    fn a_clip_is_placed_before_it_cuts() {
        let card = PlacedShape::placed(
            Rect::new(0.0, 0.0, 100.0, 100.0),
            round(0.0),
            1.0,
            Transform::translate(500.0, 300.0),
        );
        let clip = PlacedShape::placed(
            Rect::new(0.0, 0.0, 100.0, 100.0),
            round(0.0),
            1.0,
            Transform::translate(500.0, 300.0),
        );

        let rects = placed_shape_to_rects(card, &[clip]);
        assert!(
            covers(&rects, 550, 350),
            "the clip covers the whole card, so nothing is cut"
        );

        // Compared without being placed, the clip would sit at the origin and
        // take the whole card with it.
        let unplaced = PlacedShape {
            curvature: 1.0,
            placement: Transform::IDENTITY,
            ..clip
        };
        assert!(placed_shape_to_rects(card, &[unplaced]).is_empty());
    }

    // -- turned shapes --------------------------------------------------

    /// A turned rectangle is tessellated as the turned rectangle, and not as
    /// the box around it.
    ///
    /// A 100×100 square turned 45° has a 141×141 bounding box whose corners are
    /// nowhere near the shape — 29 pixels of empty diagonal at each one. The
    /// compositor blurred the desktop in all four, which is what #198 is about.
    #[test]
    fn a_turned_square_does_not_claim_its_corners() {
        let rects = placed_shape_to_rects(
            shape(
                Rect::new(0.0, 0.0, 100.0, 100.0),
                round(0.0),
                Transform::rotate_degrees(45.0).center_at(50.0, 50.0),
            ),
            &[],
        );
        assert!(!rects.is_empty());

        // The diamond's own points, which the bounding box shares.
        assert!(covers(&rects, 50, 20), "the top point is in the shape");
        assert!(covers(&rects, 50, 50), "and so is the middle");

        // The bounding box's corners, which are 29 pixels of nothing.
        for (x, y) in [(-15, -15), (115, -15), (-15, 115), (115, 115)] {
            assert!(
                !covers(&rects, x, y),
                "({x}, {y}) is a corner of the box, not of the shape"
            );
        }
    }

    /// Every rectangle of a turned shape is inside it — the same promise the
    /// upright tessellation makes, asked of the case that used to have no
    /// answer at all.
    #[test]
    fn slabs_stay_inside_a_turned_shape() {
        let (w, h) = (120.0f32, 60.0f32);
        let transform = Transform::rotate_degrees(25.0).center_at(w / 2.0, h / 2.0);
        let rects = placed_shape_to_rects(
            PlacedShape {
                rect: Rect::new(0.0, 0.0, w, h),
                radii: round(0.0),
                curvature: 1.0,
                placement: transform,
            },
            &[],
        );
        assert!(!rects.is_empty());

        let back = transform.inverse().expect("a rotation is invertible");
        for rect in &rects {
            for (px, py) in [
                (rect.x, rect.y),
                (rect.x + rect.width, rect.y),
                (rect.x, rect.y + rect.height),
                (rect.x + rect.width, rect.y + rect.height),
            ] {
                let (lx, ly) = back.transform_point(px as f32, py as f32);
                assert!(
                    lx >= -1.0 && ly >= -1.0 && lx <= w + 1.0 && ly <= h + 1.0,
                    "({px}, {py}) maps back to ({lx}, {ly}), outside the shape"
                );
            }
        }
    }

    /// A turned shape covers far less than its box, and the number is the
    /// point: this is the area the compositor was blurring where nothing was
    /// drawn.
    #[test]
    fn a_turned_shape_claims_about_its_own_area() {
        let (w, h) = (150.0f32, 90.0f32);
        let rects = placed_shape_to_rects(
            shape(
                Rect::new(0.0, 0.0, w, h),
                round(0.0),
                Transform::rotate_degrees(20.0).center_at(w / 2.0, h / 2.0),
            ),
            &[],
        );
        let covered: i64 = rects.iter().map(|r| r.width as i64 * r.height as i64).sum();
        let shape = (w * h) as i64;

        assert!(
            covered <= shape,
            "the rectangles inscribe the shape, so they cannot exceed its \
             {shape} px — got {covered}"
        );
        assert!(
            covered > shape * 9 / 10,
            "and they should not give away much of it either — got {covered} \
             of {shape}"
        );
        // The issue's own arithmetic: the box is 73% larger than the shape.
        let boxed = {
            let b = Transform::rotate_degrees(20.0)
                .center_at(w / 2.0, h / 2.0)
                .map_rect(Rect::new(0.0, 0.0, w, h));
            (b.width * b.height) as i64
        };
        assert!(
            boxed > shape * 17 / 10,
            "the box this replaces is {boxed} px against the shape's {shape}"
        );
    }

    /// A turned shape keeps its rounded corners: the arcs are transformed with
    /// everything else, and the rectangles still inscribe the result.
    ///
    /// **Every other turned test here uses a radius of zero**, which skips the
    /// arc solve entirely — so the corner arithmetic had no rotated case at all
    /// and shipped reading the wrong row of the matrix. The symptom was a
    /// region in stripes covering about half the shape while reaching several
    /// pixels past its outline, and the test that stood here asked only that
    /// rounding *removes* area, which a broken solve does more enthusiastically
    /// than a working one.
    ///
    /// So: inside, by an oracle that maps each rectangle back, and not much
    /// smaller than the shape.
    #[test]
    fn a_turned_rounded_shape_is_inside_itself_and_most_of_itself() {
        let (w, h, r) = (110.0f32, 70.0f32, 16.0f32);
        for degrees in [25.0f32, 45.0, 115.0, -30.0] {
            let transform = Transform::rotate_degrees(degrees).center_at(w / 2.0, h / 2.0);
            let rects = placed_shape_to_rects(
                PlacedShape {
                    rect: Rect::new(0.0, 0.0, w, h),
                    radii: round(r),
                    curvature: 1.0,
                    placement: transform,
                },
                &[],
            );
            assert!(!rects.is_empty(), "at {degrees}°");

            let back = transform.inverse().expect("a rotation is invertible");
            let inside = |px: f32, py: f32| {
                let (x, y) = back.transform_point(px, py);
                let cx = x.clamp(r, w - r);
                let cy = y.clamp(r, h - r);
                ((x - cx).powi(2) + (y - cy).powi(2)).sqrt() <= r + 1.0
                    && (-1.0..=w + 1.0).contains(&x)
                    && (-1.0..=h + 1.0).contains(&y)
            };
            for rect in &rects {
                for (px, py) in [
                    (rect.x, rect.y),
                    (rect.x + rect.width, rect.y),
                    (rect.x, rect.y + rect.height),
                    (rect.x + rect.width, rect.y + rect.height),
                ] {
                    assert!(
                        inside(px as f32, py as f32),
                        "at {degrees}°, ({px}, {py}) is outside the shape"
                    );
                }
            }

            // And most of it: rectangles that are merely *inside* can still be
            // stripes, which is what the wrong row produced.
            let covered: i64 = rects.iter().map(|r| r.width as i64 * r.height as i64).sum();
            let shape_area = (w * h - (4.0 - std::f32::consts::PI) * r * r) as i64;
            assert!(
                covered > shape_area * 9 / 10,
                "at {degrees}°, {covered} px of a {shape_area} px shape"
            );
        }
    }

    /// A clip narrows the shape, and an axis-aligned one narrows it to a box.
    #[test]
    fn a_clip_narrows_a_turned_shape() {
        let diamond = shape(
            Rect::new(0.0, 0.0, 100.0, 100.0),
            round(0.0),
            Transform::rotate_degrees(45.0).center_at(50.0, 50.0),
        );
        let box_clip = |r: Rect| [shape(r, round(0.0), Transform::IDENTITY)];
        let clipped =
            placed_shape_to_rects(diamond, &box_clip(Rect::new(50.0, -50.0, 100.0, 200.0)));

        assert!(
            clipped.iter().all(|r| r.x >= 50),
            "nothing reaches left of the clip"
        );
        assert!(
            covers(&clipped, 60, 50),
            "and what is on show is still there"
        );
        assert!(
            placed_shape_to_rects(diamond, &box_clip(Rect::new(500.0, 0.0, 10.0, 10.0))).is_empty(),
            "a clip that misses leaves nothing to publish"
        );
    }

    /// Every clip down a chain narrows the region, each as the shape it is:
    /// a circle over a square inset from its corners, which no one rounded
    /// rect describes.
    #[test]
    fn every_clip_in_a_chain_narrows_the_region() {
        let card = shape(
            Rect::new(0.0, 0.0, 200.0, 200.0),
            round(0.0),
            Transform::IDENTITY,
        );
        let circle = shape(
            Rect::new(0.0, 0.0, 100.0, 100.0),
            round(50.0),
            Transform::IDENTITY,
        );
        let inset = shape(
            Rect::new(10.0, 10.0, 80.0, 80.0),
            round(0.0),
            Transform::IDENTITY,
        );
        let rects = placed_shape_to_rects(card, &[inset, circle]);

        assert!(covers(&rects, 50, 50), "inside both");
        assert!(
            covers(&rects, 50, 12),
            "the inset's top edge, inside the circle"
        );
        assert!(
            !covers(&rects, 12, 12),
            "the inset's corner, which the circle has cut away"
        );
        assert!(!covers(&rects, 50, 5), "inside the circle, above the inset");
    }

    /// A clip turned 25° from the one it is under is no longer folded into the
    /// box around both: the region follows each clip's own edges, through the
    /// chain the frame keeps for them.
    #[test]
    fn a_region_under_clips_turned_apart_follows_both() {
        use crate::renderer::clip::ClipTree;
        use crate::renderer::{FlattenedCommand, RenderLayer};

        let square = |placement| shape(Rect::new(0.0, 0.0, 100.0, 100.0), round(0.0), placement);
        let turned = Transform::rotate_degrees(25.0).center_at(50.0, 50.0);
        let mut tree = ClipTree::default();
        let outer = tree.place(square(turned), None);
        let inner = tree.place(square(Transform::IDENTITY), Some(outer));

        let rect = Rect::new(-50.0, -50.0, 200.0, 200.0);
        let cmd = FlattenedCommand {
            command: std::rc::Rc::new(DrawCommand::InputRegion {
                rect,
                corner_radii: round(0.0),
                curvature: 1.0,
                takes: true,
            }),
            world_transform: Transform::IDENTITY,
            layer: RenderLayer::Shapes,
            opacity: 1.0,
            clip: Some(tree.reference(inner)),
        };
        let rects = shape_of(&cmd, tree.chains(), rect, round(0.0), 1.0);

        assert!(covers(&rects, 50, 50), "the middle, inside both");
        assert!(
            !covers(&rects, 2, 2),
            "the upright square's corner, which the turned one does not reach"
        );
        assert!(
            rects
                .iter()
                .all(|r| r.x >= 0 && r.y >= 0 && r.x + r.width <= 100),
            "and nothing outside the upright square"
        );
    }
}