diff options
| author | srdusr <[email protected]> | 2025-04-03 22:35:00 +0200 |
|---|---|---|
| committer | srdusr <[email protected]> | 2025-04-03 22:35:00 +0200 |
| commit | 254557f94544fe8841a4e9422eee9228e7ed4152 (patch) | |
| tree | 4a1197daae3571d00e9af5e779107edaca183443 /crates/wayland/src/decoration/tests.rs | |
| parent | 4d61d76b1b73f56fc14ed977806e4d4ad313fd51 (diff) | |
| download | srdwm-254557f94544fe8841a4e9422eee9228e7ed4152.tar.gz srdwm-254557f94544fe8841a4e9422eee9228e7ed4152.zip | |
Fix border corner rendered as a solid wedge instead of a ring
round_top_corners/round_bottom_corners only ever cut pixels *outside*
the shared corner radius (the rounded outer silhouette). Nothing cut
anything *inside* it, so a border strip's own "extra" rows (present
whenever corner_radius > border_width) stayed a solid filled disk out
to the centre column/row, then hit clip_middle_beyond_thickness's
hard, unblended rectangular cut right at the disk's own most opaque
point - a clean right-angle step, not a curve. Confirmed live,
zoomed: a real square notch bitten into an otherwise smooth arc,
reported as "squares on the inside corners of each vertex."
Added carve_inner_corner_pixel, the same smoothstep falloff as the
existing outer cut but inverted (cuts near the centre instead of far
from it), applied at radius - border_width so the corner becomes a
genuine ring of ~border_width visible thickness tapering smoothly to
transparent, instead of a filled wedge. Only render_border_top/
render_border_bottom pass an inner_radius; the titlebar's own corner
and the lock-screen box keep their existing solid-disk behaviour,
which is correct for a single flat-coloured panel with nothing of a
different colour underneath needing to show through.
Also generalizes round_top_corners with an explicit center_col
parameter, mirroring the existing center_row shift: the titlebar's own
corner circle was never shifted horizontally to match the border
strip's (only vertically), leaving a border_width-wide sliver of the
titlebar's own misaligned curve poking through at the seam.
border_top_and_titlebar_corners_meet_without_a_seam and
border_top_curve_actually_closes_within_the_side_strips_own_width
updated to match: both now compare the correct corresponding columns
(the titlebar's own buffer starts border_width columns inside the
border strip's), and the latter no longer demands exact 255 opacity at
a point that legitimately sits within the new inner cut's own
antialiasing band.
Diffstat (limited to 'crates/wayland/src/decoration/tests.rs')
| -rw-r--r-- | crates/wayland/src/decoration/tests.rs | 90 |
1 files changed, 57 insertions, 33 deletions
diff --git a/crates/wayland/src/decoration/tests.rs b/crates/wayland/src/decoration/tests.rs index e9ef02e..4507a05 100644 --- a/crates/wayland/src/decoration/tests.rs +++ b/crates/wayland/src/decoration/tests.rs @@ -503,36 +503,46 @@ fn border_top_and_titlebar_corners_meet_without_a_seam() { let border = render_border_top(width, thickness, color, radius); let titlebar = render_titlebar(width, 24, "", color, (0xff, 0xff, 0xff), true, radius, thickness, true, None, false, false, false, None, true, false); let border_alpha_at = |x: usize| border[((thickness as usize - 1) * width as usize + x) * 4 + 3]; - let titlebar_alpha_at = |x: usize| titlebar[x * 4 + 3]; - // Every column across the curve's actual reach, not just one - // sample point - a seam bug shows up as a jump at some columns - // and not others (the exact shape of the mismatch between two - // differently-sized circles), so checking only the corner pixel - // or only the centre could miss it entirely, the same way the - // original bug slipped past the test above it for months. Worked - // out by hand (see this fix's own commit) what the two designs - // actually produce at every column for radius=6/thickness=4: the - // old (`radius + thickness`-for-the-border) design jumped by as - // much as 187 out of 255, at *every* column past the first two; - // this design jumps by at most 70, confined to the two columns - // nearest the exact tip - an inherent limit of splitting one - // steep curve across two separately-rasterised bitmaps a single - // row apart, not a bug to chase further. `< 90` catches any - // regression back toward the old behaviour without demanding - // more precision than two 1px-apart raster buffers can give. - for x in 0..radius as usize + 2 { - let (b, t) = (border_alpha_at(x), titlebar_alpha_at(x)); + let titlebar_alpha_at = |xt: usize| titlebar[xt * 4 + 3]; + // `x` below is the shared *global* column - distance from the true + // left corner tip, in the border strip's own coordinate frame (its + // column 0 is that tip). The titlebar's own buffer starts `thickness` + // columns further in (its column 0 sits at global column `thickness`, + // not 0 - a border strip is wider than the titlebar it sits above by + // `thickness` on each side, same as `round_top_corners`'s own + // `center_col` doc comment already says for the vertical case), so + // the titlebar-local column that corresponds to a given global column + // `x` is `x - thickness`, not `x` itself. Comparing raw index `x` on + // both sides used to "pass" here for the wrong reason: both curves + // used the same (incorrectly) unshifted centre column, so indexing + // them identically happened to compare matching *formula* output + // without the two indices actually referring to the same real screen + // column - fixing that shared centre (`round_top_corners`'s own + // `center_col` parameter) is what surfaced this test needing the same + // correction. + // + // Every column across the curve's actual reach, not just one sample + // point - a seam bug shows up as a jump at some columns and not + // others, so checking only the corner pixel or only the centre could + // miss it entirely, the same way the original bug slipped past the + // test above it for months. `< 90` catches any regression back toward + // a visibly stepped seam without demanding more precision than two + // 1px-apart raster buffers a single row apart can give. + for x in thickness as usize..radius as usize + 2 { + let xt = x - thickness as usize; + let (b, t) = (border_alpha_at(x), titlebar_alpha_at(xt)); let jump = (b as i32 - t as i32).abs(); - assert!(jump < 90, "column {x}: border's last row (alpha={b}) and titlebar's first row (alpha={t}) must be close, not a sharp seam (jump={jump})"); + assert!(jump < 90, "global column {x} (titlebar column {xt}): border's last row (alpha={b}) and titlebar's first row (alpha={t}) must be close, not a sharp seam (jump={jump})"); } - // Past the tip's unavoidable steepness (columns 0-1 above), the - // curve should be genuinely, near-exactly continuous - both - // rows fully opaque by then for this radius/thickness, not just + // Past the tip's unavoidable steepness (the first two global columns + // above), the curve should be genuinely, near-exactly continuous -- + // both rows fully opaque by then for this radius/thickness, not just // "close enough". - for x in 2..radius as usize + 2 { - let (b, t) = (border_alpha_at(x), titlebar_alpha_at(x)); + for x in (thickness as usize + 2)..radius as usize + 2 { + let xt = x - thickness as usize; + let (b, t) = (border_alpha_at(x), titlebar_alpha_at(xt)); let jump = (b as i32 - t as i32).abs(); - assert!(jump <= 2, "column {x}: past the corner tip the seam should be essentially exact, not just under the looser tip tolerance (jump={jump})"); + assert!(jump <= 2, "global column {x} (titlebar column {xt}): past the corner tip the seam should be essentially exact, not just under the looser tip tolerance (jump={jump})"); } } @@ -621,17 +631,31 @@ fn border_top_curve_actually_closes_within_the_side_strips_own_width() { // `border_width` columns - so with `radius` meaningfully larger // than `border_width`, there was a real gap of bare background // between them, at exactly the column range a real vertical border - // strip occupies. This checks that gap is actually closed: by this - // buffer's own last row (where the curve should have fully - // resolved to flat, for a `radius` that fits within the strip's - // half-width), the column right at the edge of where a - // `border_width`-wide side strip would sit must already be opaque. + // strip occupies. `border_width` here matches `thickness` (as every + // real call site does - both come from the same `w.border_width`), + // not an arbitrary different value: `corners::carve_inner_corner_ + // pixel`'s own inner-ring cut is sized from `thickness`, so a test + // that fed it a different, unrelated "real side strip width" would + // no longer be testing this compositor's own real geometry at all. + // + // `> 180`, not `== 255`: the ring now has smooth antialiasing on + // *both* its outer and inner edges (see `carve_inner_corner_pixel`'s + // own doc comment for why the inner one is new) - the exact corner + // this samples (right at the ring's own width, on its very last row) + // sits close enough to both transition bands to be genuinely, by + // design, a little short of fully opaque, the same way the outer + // curve's own edge already was before this fix existed. `> 180` + // catches the real regression this test exists for - the curve + // never reaching this column at all (alpha near 0, a visible gap) -- + // without demanding more precision than two overlapping antialiased + // edges can give at their closest approach. let color = (0x40, 0x50, 0x60); - let (width, thickness, border_width, radius) = (60u32, 2u32, 3u32, 6u32); + let (width, thickness, radius) = (60u32, 3u32, 6u32); let buf = render_border_top(width, thickness, color, radius); let height = (thickness as usize).max(radius as usize); let alpha_at = |x: usize, y: usize| buf[(y * width as usize + x) * 4 + 3]; - assert_eq!(alpha_at(border_width as usize - 1, height - 1), 255, "the side strip's own rightmost column must be fully covered by the curve at the buffer's last row, not left as a gap"); + let alpha = alpha_at(thickness as usize - 1, height - 1); + assert!(alpha > 180, "the side strip's own rightmost column must be visibly covered by the curve at the buffer's last row, not left as a gap (alpha={alpha})"); } #[test] |