use std::sync::{Arc, Mutex, OnceLock};
use windows::Win32::Foundation::{COLORREF, HWND, LPARAM, LRESULT, POINT, RECT, SIZE, WPARAM};
use windows::Win32::Graphics::Gdi::{
AC_SRC_ALPHA, AC_SRC_OVER, BI_RGB, BITMAPINFO, BITMAPINFOHEADER, BLENDFUNCTION,
CreateCompatibleDC, CreateDIBSection, DIB_RGB_COLORS, DeleteDC, DeleteObject, GetDC, HBITMAP,
HDC, HGDIOBJ, ReleaseDC, SelectObject,
};
use windows::Win32::System::LibraryLoader::GetModuleHandleW;
use windows::Win32::UI::WindowsAndMessaging::{
CS_HREDRAW, CS_VREDRAW, CreateWindowExW, DefWindowProcW, GWLP_USERDATA, GetWindowLongPtrW,
GetWindowRect, RegisterClassExW, SW_HIDE, SW_SHOWNOACTIVATE, SWP_NOACTIVATE, SWP_NOMOVE,
SWP_NOSENDCHANGING, SWP_NOSIZE, SetWindowLongPtrW, SetWindowPos, ShowWindow, ULW_ALPHA,
UpdateLayeredWindow, WINDOW_EX_STYLE, WINDOW_STYLE, WM_SIZE, WNDCLASSEXW, WS_EX_LAYERED,
WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW, WS_EX_TRANSPARENT, WS_POPUP,
};
use windows::core::PCWSTR;
use windows::core::w;
use super::style::{BorderStyle, CornerPreference};
use crate::common::Rect;
use crate::config::Color;
const OVERLAY_CLASS_NAME: PCWSTR = w!("FlowBorderOverlay");
static OVERLAY_CLASS_ATOM: OnceLock<u16> = OnceLock::new();
unsafe extern "system" fn overlay_wnd_proc(
hwnd: HWND,
msg: u32,
wparam: WPARAM,
lparam: LPARAM,
) -> LRESULT {
if msg == WM_SIZE {
let ptr_val = unsafe { GetWindowLongPtrW(hwnd, GWLP_USERDATA) };
if ptr_val != 0 {
let border_inner = unsafe { &*(ptr_val as *const BorderInner) };
border_inner.on_wm_size();
}
return LRESULT(0);
}
unsafe { DefWindowProcW(hwnd, msg, wparam, lparam) }
}
static OVERLAY_CLASS_LOCK: Mutex<()> = Mutex::new(());
fn ensure_window_class_registered() -> Result<(), String> {
if OVERLAY_CLASS_ATOM.get().is_some() {
return Ok(());
}
let _guard = OVERLAY_CLASS_LOCK.lock().expect("class lock poisoned");
if OVERLAY_CLASS_ATOM.get().is_some() {
return Ok(());
}
let hinstance = unsafe { GetModuleHandleW(PCWSTR::null()) }
.map_err(|e| format!("GetModuleHandleW failed: {e}"))?;
let wcex = WNDCLASSEXW {
cbSize: std::mem::size_of::<WNDCLASSEXW>() as u32,
style: CS_HREDRAW | CS_VREDRAW,
lpfnWndProc: Some(overlay_wnd_proc),
hInstance: hinstance.into(),
lpszClassName: OVERLAY_CLASS_NAME,
..Default::default()
};
let atom = unsafe { RegisterClassExW(&wcex) };
if atom == 0 {
return Err("RegisterClassExW returned 0".to_owned());
}
let _ = OVERLAY_CLASS_ATOM.set(atom);
Ok(())
}
#[derive(Debug, Clone)]
pub struct Border {
inner: Arc<BorderInner>,
}
#[derive(Debug)]
struct BorderInner {
overlay: Mutex<isize>,
target: isize,
style: Mutex<BorderStyle>,
corner_preference: CornerPreference,
surface: Mutex<Option<CachedSurface>>,
}
impl Border {
pub(crate) fn create(style: BorderStyle, target_hwnd: isize) -> Result<Self, String> {
ensure_window_class_registered()?;
let ex_style = WINDOW_EX_STYLE(
WS_EX_LAYERED.0 | WS_EX_TRANSPARENT.0 | WS_EX_NOACTIVATE.0 | WS_EX_TOOLWINDOW.0,
);
let style_flags = WINDOW_STYLE(WS_POPUP.0);
let hwnd = unsafe {
CreateWindowExW(
ex_style,
OVERLAY_CLASS_NAME,
w!(""),
style_flags,
0,
0,
1,
1,
None,
None,
None,
None,
)
}
.map_err(|e| format!("CreateWindowExW failed: {e}"))?;
let border = Self {
inner: Arc::new(BorderInner {
overlay: Mutex::new(hwnd.0 as isize),
target: target_hwnd,
style: Mutex::new(style),
corner_preference: style.corner_preference,
surface: Mutex::new(None),
}),
};
let inner_ptr = Arc::as_ptr(&border.inner) as isize;
let _ = unsafe { SetWindowLongPtrW(hwnd, GWLP_USERDATA, inner_ptr) };
border.set_visible(true);
border.seat_above_target();
Ok(border)
}
#[must_use]
pub(crate) fn hwnd(&self) -> isize {
*self.inner.overlay.lock().expect("overlay mutex poisoned")
}
#[must_use]
pub(crate) fn corner_preference(&self) -> CornerPreference {
self.inner.corner_preference
}
pub(crate) fn seat_above_target(&self) {
let raw = *self.inner.overlay.lock().expect("overlay mutex poisoned");
if raw == 0 {
return;
}
let overlay_hwnd = HWND(raw as *mut _);
let target_hwnd = HWND(self.inner.target as *mut _);
let _ = unsafe {
SetWindowPos(
overlay_hwnd,
Some(target_hwnd),
0,
0,
0,
0,
SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_NOMOVE | SWP_NOSIZE,
)
};
}
}
impl Drop for BorderInner {
fn drop(&mut self) {
let mut guard = self.overlay.lock().expect("overlay mutex poisoned");
let raw = *guard;
if raw == 0 {
return;
}
let hwnd = HWND(raw as *mut _);
let _ = unsafe { windows::Win32::UI::WindowsAndMessaging::DestroyWindow(hwnd) };
*guard = 0;
}
}
impl BorderInner {
fn overlay_rect(&self) -> Option<Rect> {
let raw = *self.overlay.lock().expect("overlay mutex poisoned");
if raw == 0 {
return None;
}
let hwnd = HWND(raw as *mut _);
let mut rect = RECT::default();
if unsafe { GetWindowRect(hwnd, &mut rect) }.is_err() {
return None;
}
Some(Rect {
x: rect.left,
y: rect.top,
width: rect.right - rect.left,
height: rect.bottom - rect.top,
})
}
fn paint(&self, rect: Rect) {
let w = rect.width;
let h = rect.height;
if w <= 0 || h <= 0 {
return;
}
let raw = *self.overlay.lock().expect("overlay mutex poisoned");
if raw == 0 {
return;
}
let overlay_hwnd = HWND(raw as *mut _);
let style = *self.style.lock().expect("style mutex poisoned");
let mut surface_guard = self.surface.lock().expect("surface mutex poisoned");
let shape_matches = surface_guard
.as_ref()
.is_some_and(|s| s.shape_matches(w, h, &style));
if shape_matches {
let surface = surface_guard.as_mut().expect("shape_matches implies Some");
if surface.color == style.color {
return;
}
surface.recolor(style.color);
surface.upload(overlay_hwnd, &rect);
return;
}
let reused = match surface_guard.as_mut() {
Some(surface) if surface.buffer_fits(w, h) => {
surface.render_ring(w, h, &style);
surface.upload(overlay_hwnd, &rect);
true
}
_ => false,
};
if !reused {
if let Some(surface) = CachedSurface::build(w, h, &style) {
surface.upload(overlay_hwnd, &rect);
*surface_guard = Some(surface);
}
}
}
fn on_wm_size(&self) {
let Some(rect) = self.overlay_rect() else {
return;
};
self.paint(rect);
}
}
impl Border {
pub(crate) fn set_geometry(&self, visible_rect: Rect) {
if visible_rect.is_empty() {
return;
}
let raw = *self.inner.overlay.lock().expect("overlay mutex poisoned");
if raw == 0 {
return;
}
let overlay_hwnd = HWND(raw as *mut _);
let target_hwnd = HWND(self.inner.target as *mut _);
let _ = unsafe {
SetWindowPos(
overlay_hwnd,
Some(target_hwnd),
visible_rect.x,
visible_rect.y,
visible_rect.width,
visible_rect.height,
SWP_NOACTIVATE | SWP_NOSENDCHANGING,
)
};
}
pub(crate) fn set_style(&self, style: BorderStyle) {
{
let mut guard = self.inner.style.lock().expect("style mutex poisoned");
if *guard == style {
return;
}
*guard = style;
}
let Some(rect) = self.inner.overlay_rect() else {
return;
};
self.inner.paint(rect);
}
pub(crate) fn set_visible(&self, visible: bool) {
let raw = *self.inner.overlay.lock().expect("overlay mutex poisoned");
if raw == 0 {
return;
}
let hwnd = HWND(raw as *mut _);
let cmd = if visible { SW_SHOWNOACTIVATE } else { SW_HIDE };
let _ = unsafe { ShowWindow(hwnd, cmd) };
}
}
struct CachedSurface {
w: i32,
h: i32,
buf_w: i32,
buf_h: i32,
thickness: u32,
corner: CornerPreference,
color: Color,
coverage: Vec<u8>,
tile_r: usize,
tile_t: usize,
hdc_mem: HDC,
bitmap: HBITMAP,
old_obj: HGDIOBJ,
bits: *mut u32,
len: usize,
}
impl std::fmt::Debug for CachedSurface {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CachedSurface")
.field("w", &self.w)
.field("h", &self.h)
.field("thickness", &self.thickness)
.field("corner", &self.corner)
.field("color", &self.color)
.finish_non_exhaustive()
}
}
impl CachedSurface {
fn shape_matches(&self, w: i32, h: i32, style: &BorderStyle) -> bool {
self.w == w
&& self.h == h
&& self.thickness == style.width_px
&& self.corner == style.corner_preference
}
fn buffer_fits(&self, w: i32, h: i32) -> bool {
w <= self.buf_w && h <= self.buf_h
}
fn render_ring(&mut self, w: i32, h: i32, style: &BorderStyle) {
debug_assert!(self.buffer_fits(w, h), "caller must ensure buffer_fits");
let thickness = style.width_px as usize;
let corner_radius = corner_radius_px(style.corner_preference, thickness);
let half = (w as usize).min(h as usize) / 2;
let t = thickness.min(half);
let r = corner_radius.min(half);
if r != self.tile_r || t != self.tile_t {
self.coverage = render_corner_coverage(r, t);
self.tile_r = r;
self.tile_t = t;
}
let stride = self.buf_w as usize;
let wu = w as usize;
let hu = h as usize;
unsafe {
for y in 0..hu {
std::ptr::write_bytes(self.bits.add(y * stride), 0, wu);
}
let pixels = std::slice::from_raw_parts_mut(self.bits, self.len);
let colored = pack_bgra(style.color, 0xFF);
composite_ring(
pixels,
BufferLayout {
stride,
width: wu,
height: hu,
},
thickness,
corner_radius,
&self.coverage,
colored,
);
}
self.w = w;
self.h = h;
self.thickness = style.width_px;
self.corner = style.corner_preference;
self.color = style.color;
}
fn build(w: i32, h: i32, style: &BorderStyle) -> Option<Self> {
let buf_w = next_capacity(w);
let buf_h = next_capacity(h);
unsafe {
let hdc_screen = GetDC(None);
if hdc_screen.is_invalid() {
log::trace!("borders: GetDC failed for screen");
return None;
}
let hdc_mem = CreateCompatibleDC(Some(hdc_screen));
let _ = ReleaseDC(None, hdc_screen);
if hdc_mem.is_invalid() {
log::trace!("borders: CreateCompatibleDC failed");
return None;
}
let bmi = BITMAPINFO {
bmiHeader: BITMAPINFOHEADER {
biSize: std::mem::size_of::<BITMAPINFOHEADER>() as u32,
biWidth: buf_w,
biHeight: -buf_h,
biPlanes: 1,
biBitCount: 32,
biCompression: BI_RGB.0,
biSizeImage: (buf_w as u32) * (buf_h as u32) * 4,
biXPelsPerMeter: 0,
biYPelsPerMeter: 0,
biClrUsed: 0,
biClrImportant: 0,
},
bmiColors: [Default::default()],
};
let mut bits_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
let bitmap =
match CreateDIBSection(Some(hdc_mem), &bmi, DIB_RGB_COLORS, &mut bits_ptr, None, 0)
{
Ok(b) => b,
Err(e) => {
log::trace!("borders: CreateDIBSection failed: {e}");
let _ = DeleteDC(hdc_mem);
return None;
}
};
if bits_ptr.is_null() {
let _ = DeleteObject(bitmap.into());
let _ = DeleteDC(hdc_mem);
return None;
}
let len = (buf_w as usize) * (buf_h as usize);
let bits = bits_ptr as *mut u32;
std::ptr::write_bytes(bits, 0, len);
let old_obj = SelectObject(hdc_mem, bitmap.into());
let mut surface = CachedSurface {
w,
h,
buf_w,
buf_h,
thickness: style.width_px,
corner: style.corner_preference,
color: style.color,
coverage: Vec::new(),
tile_r: usize::MAX,
tile_t: usize::MAX,
hdc_mem,
bitmap,
old_obj,
bits,
len,
};
surface.render_ring(w, h, style);
Some(surface)
}
}
fn recolor(&mut self, new_color: Color) {
let stride = self.buf_w as usize;
let w = self.w as usize;
let h = self.h as usize;
debug_assert!(
w <= self.buf_w as usize && h <= self.buf_h as usize,
"recolor bounds derived from render_ring/build invariant"
);
unsafe {
for y in 0..h {
let row = self.bits.add(y * stride);
let pixels = std::slice::from_raw_parts_mut(row, w);
for px in pixels.iter_mut() {
*px = recolor_pixel(*px, new_color);
}
}
}
self.color = new_color;
}
fn upload(&self, overlay_hwnd: HWND, rect: &Rect) {
let pt_dst = POINT {
x: rect.x,
y: rect.y,
};
let pt_src = POINT { x: 0, y: 0 };
let size = SIZE {
cx: self.w,
cy: self.h,
};
let blend = BLENDFUNCTION {
BlendOp: AC_SRC_OVER as u8,
BlendFlags: 0,
SourceConstantAlpha: 255,
AlphaFormat: AC_SRC_ALPHA as u8,
};
unsafe {
let result = UpdateLayeredWindow(
overlay_hwnd,
None,
Some(&pt_dst),
Some(&size),
Some(self.hdc_mem),
Some(&pt_src),
COLORREF(0),
Some(&blend),
ULW_ALPHA,
);
if result.is_err() {
log::trace!("borders: UpdateLayeredWindow failed");
}
}
}
}
impl Drop for CachedSurface {
fn drop(&mut self) {
unsafe {
let _ = SelectObject(self.hdc_mem, self.old_obj);
let _ = DeleteObject(self.bitmap.into());
let _ = DeleteDC(self.hdc_mem);
}
}
}
unsafe impl Send for CachedSurface {}
#[must_use]
pub(crate) const fn pack_bgra(color: Color, alpha: u8) -> u32 {
let r = color.r as u32;
let g = color.g as u32;
let b = color.b as u32;
let a = alpha as u32;
(a << 24) | (r << 16) | (g << 8) | b
}
#[must_use]
pub(crate) fn pack_premultiplied(rgb: u32, alpha: u8) -> u32 {
let a = u32::from(alpha);
let r = ((rgb >> 16) & 0xFF) * a;
let g = ((rgb >> 8) & 0xFF) * a;
let b = (rgb & 0xFF) * a;
let r = (r + 127) / 255;
let g = (g + 127) / 255;
let b = (b + 127) / 255;
(a << 24) | (r << 16) | (g << 8) | b
}
#[must_use]
pub(crate) fn recolor_pixel(px: u32, new_color: Color) -> u32 {
let a = (px >> 24) & 0xFF;
if a == 0 {
return px;
}
let rgb =
(u32::from(new_color.r) << 16) | (u32::from(new_color.g) << 8) | u32::from(new_color.b);
pack_premultiplied(rgb, a as u8)
}
fn corner_radius_px(pref: CornerPreference, thickness: usize) -> usize {
let window_radius: usize = match pref {
CornerPreference::Square => 0,
CornerPreference::Rounded => 8,
CornerPreference::RoundedSmall => 4,
CornerPreference::Default => 8,
};
if window_radius == 0 {
0
} else {
window_radius + thickness
}
}
#[cfg_attr(not(test), allow(dead_code))]
fn in_rounded_rect(x: f64, y: f64, ox: f64, oy: f64, w: f64, h: f64, cr: f64) -> bool {
if w <= 0.0 || h <= 0.0 {
return false;
}
if x < ox || y < oy {
return false;
}
let lx = x - ox;
let ly = y - oy;
if lx >= w || ly >= h {
return false;
}
if cr <= 0.0 {
return true;
}
if lx >= cr && lx < w - cr {
return true;
}
if ly >= cr && ly < h - cr {
return true;
}
let cx = if lx < cr { cr } else { w - cr };
let cy = if ly < cr { cr } else { h - cr };
let dx = lx - cx;
let dy = ly - cy;
dx * dx + dy * dy <= cr * cr
}
fn circle_segment_antiderivative(y: f64, r: f64) -> f64 {
if r == 0.0 {
return 0.0;
}
let r2 = r * r;
let yc = y.clamp(-r, r);
let chord = (r2 - yc * yc).max(0.0).sqrt();
(yc * chord + r2 * (yc / r).asin()) * 0.5
}
fn pixel_circle_area_q1(u0: f64, u1: f64, v0: f64, v1: f64, r: f64) -> f64 {
debug_assert!(
u0 >= 0.0 && v0 >= 0.0 && u1 > u0 && v1 > v0 && r >= 0.0,
"pixel_circle_area_q1 requires the upper-right quadrant"
);
if u0 * u0 + v0 * v0 >= r * r {
return 0.0;
}
if u1 * u1 + v1 * v1 <= r * r {
return (u1 - u0) * (v1 - v0);
}
let y_u1 = (r * r - u1 * u1).max(0.0).sqrt();
let y_u0 = (r * r - u0 * u0).max(0.0).sqrt();
let seg1_hi = v1.min(y_u1);
let seg1 = (seg1_hi - v0).max(0.0) * (u1 - u0);
let seg2_lo = v0.max(y_u1);
let seg2_hi = v1.min(y_u0);
let seg2 = if seg2_lo < seg2_hi {
circle_segment_antiderivative(seg2_hi, r)
- circle_segment_antiderivative(seg2_lo, r)
- u0 * (seg2_hi - seg2_lo)
} else {
0.0
};
seg1 + seg2
}
fn corner_pixel_alpha(
px: usize,
py: usize,
cx: usize,
cy: usize,
outer_r: f64,
inner_r: f64,
in_inner_corner: bool,
) -> u8 {
let (u0, u1) = if px < cx {
((cx - px - 1) as f64, (cx - px) as f64)
} else {
((px - cx) as f64, (px + 1 - cx) as f64)
};
let (v0, v1) = if py < cy {
((cy - py - 1) as f64, (cy - py) as f64)
} else {
((py - cy) as f64, (py + 1 - cy) as f64)
};
let area_outer = pixel_circle_area_q1(u0, u1, v0, v1, outer_r);
let area_inner = if in_inner_corner {
pixel_circle_area_q1(u0, u1, v0, v1, inner_r)
} else {
0.0
};
let cov = (area_outer - area_inner).clamp(0.0, 1.0);
(cov * 255.0).round() as u8
}
#[cfg_attr(not(test), allow(dead_code))]
pub(crate) fn fill_border_ring(
pixels: &mut [u32],
width: usize,
height: usize,
thickness: usize,
corner_radius: usize,
color: u32,
) {
assert_eq!(
pixels.len(),
width * height,
"pixels buffer must be exactly width * height"
);
if width == 0 || height == 0 {
return;
}
let half = width.min(height) / 2;
let t = thickness.min(half);
if t == 0 {
return;
}
let r = corner_radius.min(half);
if r == 0 {
let last_row = height - t;
let last_col = width - t;
for y in 0..height {
let row_start = y * width;
if y < t || y >= last_row {
pixels[row_start..row_start + width].fill(color);
} else {
pixels[row_start..row_start + t].fill(color);
pixels[row_start + last_col..row_start + width].fill(color);
}
}
return;
}
let inner_radius = r.saturating_sub(t);
let rgb = color & 0x00FF_FFFF;
let outer_r = r as f64;
let inner_r = inner_radius as f64;
for y in 0..t {
let row = y * width;
pixels[row + r..row + (width - r)].fill(color);
}
for y in (height - t)..height {
let row = y * width;
pixels[row + r..row + (width - r)].fill(color);
}
for y in r..(height - r) {
let row = y * width;
pixels[row..row + t].fill(color);
pixels[row + (width - t)..row + width].fill(color);
}
for py in 0..r {
for px in 0..r {
let in_inner = px >= t && py >= t;
let alpha = corner_pixel_alpha(px, py, r, r, outer_r, inner_r, in_inner);
if alpha > 0 {
pixels[py * width + px] = pack_premultiplied(rgb, alpha);
}
}
}
for py in 0..r {
for px in (width - r)..width {
let in_inner = px < width - t && py >= t;
let alpha = corner_pixel_alpha(px, py, width - r, r, outer_r, inner_r, in_inner);
if alpha > 0 {
pixels[py * width + px] = pack_premultiplied(rgb, alpha);
}
}
}
for py in (height - r)..height {
for px in 0..r {
let in_inner = px >= t && py < height - t;
let alpha = corner_pixel_alpha(px, py, r, height - r, outer_r, inner_r, in_inner);
if alpha > 0 {
pixels[py * width + px] = pack_premultiplied(rgb, alpha);
}
}
}
for py in (height - r)..height {
for px in (width - r)..width {
let in_inner = px < width - t && py < height - t;
let alpha =
corner_pixel_alpha(px, py, width - r, height - r, outer_r, inner_r, in_inner);
if alpha > 0 {
pixels[py * width + px] = pack_premultiplied(rgb, alpha);
}
}
}
}
#[must_use]
const fn next_capacity(n: i32) -> i32 {
let n = if n < 1 { 1 } else { n as usize };
n.next_power_of_two() as i32
}
#[must_use]
pub(crate) fn render_corner_coverage(radius: usize, thickness: usize) -> Vec<u8> {
if radius == 0 {
return Vec::new();
}
let r = radius;
let t = thickness.min(r);
let inner_radius = r.saturating_sub(t);
let outer_r = r as f64;
let inner_r = inner_radius as f64;
let mut coverage = vec![0u8; r * r];
for py in 0..r {
for px in 0..r {
let in_inner_corner = px >= t && py >= t;
coverage[py * r + px] =
corner_pixel_alpha(px, py, r, r, outer_r, inner_r, in_inner_corner);
}
}
coverage
}
#[derive(Clone, Copy)]
struct CornerPos {
ox: usize,
oy: usize,
flip_x: bool,
flip_y: bool,
}
#[derive(Clone, Copy)]
pub(crate) struct BufferLayout {
stride: usize,
width: usize,
height: usize,
}
fn blit_corner(
pixels: &mut [u32],
stride: usize,
coverage: &[u8],
r: usize,
rgb: u32,
pos: CornerPos,
) {
let CornerPos {
ox,
oy,
flip_x,
flip_y,
} = pos;
for ty in 0..r {
let y = if flip_y { oy + r - 1 - ty } else { oy + ty };
for tx in 0..r {
let cov = coverage[ty * r + tx];
if cov > 0 {
let x = if flip_x { ox + r - 1 - tx } else { ox + tx };
pixels[y * stride + x] = pack_premultiplied(rgb, cov);
}
}
}
}
pub(crate) fn composite_ring(
pixels: &mut [u32],
layout: BufferLayout,
thickness: usize,
corner_radius: usize,
corner_coverage: &[u8],
color: u32,
) {
let BufferLayout {
stride,
width,
height,
} = layout;
assert!(
pixels.len() >= stride * height,
"pixels buffer must hold at least stride * height"
);
if width == 0 || height == 0 {
return;
}
let half = width.min(height) / 2;
let t = thickness.min(half);
if t == 0 {
return;
}
let r = corner_radius.min(half);
let rgb = color & 0x00FF_FFFF;
for y in 0..t {
let row = y * stride;
pixels[row + r..row + (width - r)].fill(color);
}
for y in (height - t)..height {
let row = y * stride;
pixels[row + r..row + (width - r)].fill(color);
}
for y in r..(height - r) {
let row = y * stride;
pixels[row..row + t].fill(color);
pixels[row + (width - t)..row + width].fill(color);
}
if r == 0 {
return;
}
debug_assert!(
corner_coverage.len() >= r * r,
"corner_coverage must hold at least r*r bytes for a nonzero radius"
);
blit_corner(
pixels,
stride,
corner_coverage,
r,
rgb,
CornerPos {
ox: 0,
oy: 0,
flip_x: false,
flip_y: false,
},
);
blit_corner(
pixels,
stride,
corner_coverage,
r,
rgb,
CornerPos {
ox: width - r,
oy: 0,
flip_x: true,
flip_y: false,
},
);
blit_corner(
pixels,
stride,
corner_coverage,
r,
rgb,
CornerPos {
ox: 0,
oy: height - r,
flip_x: false,
flip_y: true,
},
);
blit_corner(
pixels,
stride,
corner_coverage,
r,
rgb,
CornerPos {
ox: width - r,
oy: height - r,
flip_x: true,
flip_y: true,
},
);
}
#[cfg(test)]
mod tests {
use super::*;
fn color(r: u8, g: u8, b: u8) -> Color {
Color::rgb(r, g, b)
}
#[test]
fn pack_bgra_orders_channels_as_blue_green_red_alpha() {
let packed = pack_bgra(color(0xFF, 0x88, 0x00), 0xAA);
assert_eq!(packed, 0xAA_FF_88_00);
}
#[test]
fn pack_bgra_full_alpha_for_opaque() {
let packed = pack_bgra(color(0x12, 0x34, 0x56), 0xFF);
assert_eq!(packed & 0xFF00_0000, 0xFF00_0000);
}
#[test]
fn fill_border_ring_zero_thickness_leaves_buffer_transparent() {
let mut buf = vec![0u32; 9];
fill_border_ring(&mut buf, 3, 3, 0, 0, 0xFFFF00FF);
assert!(buf.iter().all(|&p| p == 0));
}
#[test]
fn fill_border_ring_one_pixel_ring_on_3x3_leaves_only_center_transparent() {
let mut buf = vec![0u32; 9];
let colored = pack_bgra(color(0, 0, 0), 0xFF);
fill_border_ring(&mut buf, 3, 3, 1, 0, colored);
assert_eq!(buf[0], colored);
assert_eq!(buf[1], colored);
assert_eq!(buf[2], colored);
assert_eq!(buf[3], colored);
assert_eq!(buf[4], 0, "center must stay transparent");
assert_eq!(buf[5], colored);
assert_eq!(buf[6], colored);
assert_eq!(buf[7], colored);
assert_eq!(buf[8], colored);
}
#[test]
fn fill_border_ring_two_pixel_ring_on_5x5_colors_outer_two_layers() {
let mut buf = vec![0u32; 25];
let colored = pack_bgra(color(0, 0, 0), 0xFF);
fill_border_ring(&mut buf, 5, 5, 2, 0, colored);
for x in 0..5 {
assert_eq!(buf[x], colored, "row 0 col {x}");
assert_eq!(buf[5 + x], colored, "row 1 col {x}");
assert_eq!(buf[15 + x], colored, "row 3 col {x}");
assert_eq!(buf[20 + x], colored, "row 4 col {x}");
}
assert_eq!(buf[10], colored);
assert_eq!(buf[11], colored);
assert_eq!(buf[12], 0, "exact center must stay transparent");
assert_eq!(buf[13], colored);
assert_eq!(buf[14], colored);
}
#[test]
fn fill_border_ring_oversized_thickness_clamps_to_half_dimension() {
let mut buf = vec![0u32; 16];
let colored = pack_bgra(color(0, 0, 0), 0xFF);
fill_border_ring(&mut buf, 4, 4, 100, 0, colored);
assert!(buf.iter().all(|&p| p == colored));
}
#[test]
fn fill_border_ring_empty_dimensions_is_noop() {
let mut buf: Vec<u32> = vec![];
fill_border_ring(&mut buf, 0, 0, 5, 0, 0xFFFF00FF);
}
#[test]
fn pack_bgra_zero_alpha_is_fully_transparent() {
let packed = pack_bgra(color(0xFF, 0xFF, 0xFF), 0x00);
assert_eq!(packed & 0xFF00_0000, 0, "alpha byte must be zero");
assert_eq!(packed, 0x00_FF_FF_FF);
}
#[test]
fn pack_bgra_black_opaque_is_alpha_high_only() {
let packed = pack_bgra(color(0, 0, 0), 0xFF);
assert_eq!(packed, 0xFF_00_00_00);
}
#[test]
fn pack_bgra_white_opaque_is_all_ones() {
let packed = pack_bgra(color(0xFF, 0xFF, 0xFF), 0xFF);
assert_eq!(packed, 0xFFFF_FFFF);
}
#[test]
fn fill_border_ring_non_square_wide_buffer() {
let mut buf = vec![0u32; 18]; let colored = pack_bgra(color(0, 0, 0), 0xFF);
fill_border_ring(&mut buf, 6, 3, 1, 0, colored);
assert!(
buf[0..6].iter().all(|&p| p == colored),
"row 0 fully colored"
);
assert_eq!(buf[6], colored, "row 1 left edge");
assert_eq!(buf[7], 0, "row 1 col 1 transparent");
assert_eq!(buf[8], 0, "row 1 col 2 transparent");
assert_eq!(buf[9], 0, "row 1 col 3 transparent");
assert_eq!(buf[10], 0, "row 1 col 4 transparent");
assert_eq!(buf[11], colored, "row 1 right edge");
assert!(
buf[12..18].iter().all(|&p| p == colored),
"row 2 fully colored"
);
}
#[should_panic(expected = "pixels buffer must be exactly width * height")]
#[test]
fn fill_border_ring_wrong_buffer_size_panics() {
let mut buf = vec![0u32; 10]; fill_border_ring(&mut buf, 3, 3, 1, 0, 0xFFFF00FF);
}
#[test]
fn corner_radius_px_square_is_zero() {
assert_eq!(corner_radius_px(CornerPreference::Square, 3), 0);
}
#[test]
fn corner_radius_px_rounded_adds_thickness() {
assert_eq!(corner_radius_px(CornerPreference::Rounded, 3), 11);
assert_eq!(corner_radius_px(CornerPreference::RoundedSmall, 3), 7);
assert_eq!(corner_radius_px(CornerPreference::Default, 3), 11);
}
#[test]
fn in_rounded_rect_zero_radius_is_bbox() {
assert!(in_rounded_rect(0.0, 0.0, 0.0, 0.0, 5.0, 5.0, 0.0));
assert!(in_rounded_rect(4.0, 4.0, 0.0, 0.0, 5.0, 5.0, 0.0));
assert!(!in_rounded_rect(5.0, 0.0, 0.0, 0.0, 5.0, 5.0, 0.0));
assert!(!in_rounded_rect(0.0, 5.0, 0.0, 0.0, 5.0, 5.0, 0.0));
}
#[test]
fn in_rounded_rect_arc_excludes_extreme_corner() {
assert!(!in_rounded_rect(0.0, 0.0, 0.0, 0.0, 9.0, 9.0, 4.0));
assert!(in_rounded_rect(4.0, 0.0, 0.0, 0.0, 9.0, 9.0, 4.0));
assert!(in_rounded_rect(4.0, 4.0, 0.0, 0.0, 9.0, 9.0, 4.0));
}
#[test]
fn in_rounded_rect_arc_boundary_point_is_inside() {
assert!(in_rounded_rect(5.0, 0.0, 0.0, 0.0, 10.0, 10.0, 5.0));
assert!(!in_rounded_rect(4.0, 0.0, 0.0, 0.0, 10.0, 10.0, 5.0));
}
#[test]
fn pixel_circle_area_q1_matches_quarter_circle() {
let r = 5.0_f64;
let area = pixel_circle_area_q1(0.0, r, 0.0, r, r);
let expected = std::f64::consts::PI * r * r / 4.0;
assert!(
(area - expected).abs() < 1e-9,
"quarter-circle area: got {area}, expected {expected}"
);
}
#[test]
fn pixel_circle_area_q1_outside_is_zero() {
assert_eq!(pixel_circle_area_q1(6.0, 7.0, 6.0, 7.0, 5.0), 0.0);
}
#[test]
fn pixel_circle_area_q1_inside_is_pixel_area() {
assert_eq!(pixel_circle_area_q1(0.0, 1.0, 0.0, 1.0, 5.0), 1.0);
assert_eq!(pixel_circle_area_q1(0.5, 1.5, 0.5, 1.5, 5.0), 1.0);
}
#[test]
fn pack_premultiplied_scales_channels() {
assert_eq!(pack_premultiplied(0x00FF_FFFF, 128), 0x8080_8080);
assert_eq!(pack_premultiplied(0x00AA_BBCC, 0x80), 0x8055_5E66);
}
#[test]
fn pack_premultiplied_identity_at_full_alpha() {
assert_eq!(pack_premultiplied(0x00FF_FFFF, 0xFF), 0xFFFF_FFFF);
assert_eq!(pack_premultiplied(0x00AA_BBCC, 0xFF), 0xFFAA_BBCC);
}
#[test]
fn pack_premultiplied_zero_alpha_is_zero() {
assert_eq!(pack_premultiplied(0x00FF_FFFF, 0), 0);
assert_eq!(pack_premultiplied(0x00AA_BBCC, 0), 0);
}
#[test]
fn circle_segment_antiderivative_endpoints_and_monotonic() {
let r = 4.0_f64;
assert_eq!(circle_segment_antiderivative(0.0, r), 0.0);
let g_neg = circle_segment_antiderivative(-r, r);
let g_pos = circle_segment_antiderivative(r, r);
assert!(g_neg < 0.0, "G(-r) must be negative, got {g_neg}");
assert!(g_pos > 0.0, "G(r) must be positive, got {g_pos}");
assert!(
(g_neg + g_pos).abs() < 1e-9,
"G(-r) + G(r) must be 0, got {}",
g_neg + g_pos
);
let quarter = r * r * std::f64::consts::PI / 4.0;
assert!(
(g_pos - quarter).abs() < 1e-9,
"G(r) must be πr²/4, got {g_pos}, expected {quarter}"
);
let g_mid = circle_segment_antiderivative(r * 0.5, r);
assert!(g_mid > 0.0 && g_mid < g_pos, "G must be monotonic");
}
#[test]
fn fill_border_ring_rounded_keeps_extreme_corners_transparent() {
let mut buf = vec![0u32; 11 * 11];
let colored = pack_bgra(color(0, 0, 0), 0xFF);
fill_border_ring(&mut buf, 11, 11, 1, 4, colored);
assert_eq!(buf[0], 0, "top-left corner transparent");
assert_eq!(buf[10], 0, "top-right corner transparent");
assert_eq!(buf[11 * 10], 0, "bottom-left corner transparent");
assert_eq!(buf[11 * 10 + 10], 0, "bottom-right corner transparent");
assert_eq!(buf[5], colored, "top edge middle colored");
assert_eq!(buf[5 * 11], colored, "left edge middle colored");
}
#[test]
fn fill_border_ring_rounded_leaves_center_transparent() {
let mut buf = vec![0u32; 11 * 11];
let colored = pack_bgra(color(0, 0, 0), 0xFF);
fill_border_ring(&mut buf, 11, 11, 1, 4, colored);
assert_eq!(buf[5 * 11 + 5], 0, "center transparent");
}
#[test]
fn fill_border_ring_rounded_emits_partial_alpha_on_arcs() {
const W: usize = 40;
const H: usize = 40;
let mut buf = vec![0u32; W * H];
let colored = pack_bgra(color(0, 0, 0), 0xFF);
fill_border_ring(&mut buf, W, H, 3, 15, colored);
let rgb = colored & 0x00FF_FFFF;
let mut partial = 0usize;
let mut full = 0usize;
let mut empty = 0usize;
let mut partial_alphas = std::collections::HashSet::new();
for &px in &buf {
let a = (px >> 24) & 0xFF;
if a == 0 {
empty += 1;
} else if a == 0xFF && (px & 0x00FF_FFFF) == rgb {
full += 1;
} else {
partial += 1;
partial_alphas.insert(a);
}
}
assert!(
partial > 0,
"rounded ring must have AA (partial-alpha) pixels"
);
assert!(full > 0, "straight-band ring pixels must be fully opaque");
assert!(
empty > 0,
"extreme corners + interior must stay transparent"
);
assert!(
partial_alphas.len() >= 2,
"AA arc must show a graded coverage gradient, found only {:?}",
partial_alphas
);
for y in 0..H {
for x in 0..W {
let px = buf[y * W + x];
assert_eq!(
px,
buf[y * W + (W - 1 - x)],
"alpha map must mirror horizontally at ({x},{y})"
);
assert_eq!(
px,
buf[(H - 1 - y) * W + x],
"alpha map must mirror vertically at ({x},{y})"
);
}
}
}
#[test]
fn fill_border_ring_rounded_zero_inner_radius_keeps_interior_transparent() {
let mut buf = vec![0u32; 16 * 16];
let colored = pack_bgra(color(0, 0, 0), 0xFF);
fill_border_ring(&mut buf, 16, 16, 4, 4, colored);
assert_eq!(buf[0], 0, "top-left corner outside the outer arc");
assert_eq!(
buf[8], colored,
"top straight band must be fully opaque even with inner_radius 0"
);
assert_eq!(
buf[8 * 16 + 8],
0,
"interior inside inner bbox must stay transparent"
);
}
#[test]
fn recolor_pixel_preserves_alpha_and_swaps_rgb() {
let original = pack_bgra(color(0x11, 0x22, 0x33), 0x80);
let recolored = recolor_pixel(original, color(0xAA, 0xBB, 0xCC));
assert_eq!(recolored, pack_premultiplied(0x00AA_BBCC, 0x80));
assert_eq!(recolored >> 24, 0x80, "alpha byte must be preserved");
}
#[test]
fn recolor_pixel_leaves_transparent_untouched() {
assert_eq!(recolor_pixel(0, color(0xFF, 0xFF, 0xFF)), 0);
let px = 0x00_11_22_33u32;
assert_eq!(recolor_pixel(px, color(0xFF, 0xFF, 0xFF)), px);
}
#[test]
fn recolor_pixel_full_alpha_preserves_opacity_and_swaps_rgb() {
let original = pack_bgra(color(0x11, 0x22, 0x33), 0xFF);
let recolored = recolor_pixel(original, color(0xAA, 0xBB, 0xCC));
assert_eq!(recolored, pack_bgra(color(0xAA, 0xBB, 0xCC), 0xFF));
assert_eq!(recolored >> 24, 0xFF);
}
fn destroyed_border_inner() -> BorderInner {
BorderInner {
overlay: Mutex::new(0),
target: 0,
style: Mutex::new(BorderStyle::new(
color(0, 0, 0),
1,
CornerPreference::Square,
)),
corner_preference: CornerPreference::Square,
surface: Mutex::new(None),
}
}
#[test]
fn on_wm_size_is_noop_when_overlay_destroyed() {
let inner = destroyed_border_inner();
inner.on_wm_size();
assert!(
inner.surface.lock().unwrap().is_none(),
"destroyed overlay must not allocate a cached surface"
);
}
#[test]
fn paint_is_noop_when_overlay_destroyed() {
let inner = destroyed_border_inner();
let non_empty_rect = Rect {
x: 0,
y: 0,
width: 10,
height: 10,
};
inner.paint(non_empty_rect);
assert!(
inner.surface.lock().unwrap().is_none(),
"destroyed overlay must not allocate a cached surface"
);
}
#[test]
fn paint_is_noop_for_zero_area_rect() {
let inner = destroyed_border_inner();
let zero_area_rect = Rect {
x: 0,
y: 0,
width: 10,
height: 0,
};
inner.paint(zero_area_rect);
assert!(
inner.surface.lock().unwrap().is_none(),
"zero-area rect must not allocate a cached surface"
);
}
fn effective_geometry(
width: usize,
height: usize,
thickness: usize,
corner_radius: usize,
) -> (usize, usize) {
let half = width.min(height) / 2;
(thickness.min(half), corner_radius.min(half))
}
fn assert_parity(width: usize, height: usize, thickness: usize, corner_radius: usize) {
let (t, r) = effective_geometry(width, height, thickness, corner_radius);
let coverage = render_corner_coverage(r, t);
let colored = pack_bgra(color(0x42, 0x7A, 0xFF), 0xFF);
let mut expected = vec![0u32; width * height];
let mut actual = vec![0u32; width * height];
fill_border_ring(
&mut expected,
width,
height,
thickness,
corner_radius,
colored,
);
composite_ring(
&mut actual,
BufferLayout {
stride: width,
width,
height,
},
thickness,
corner_radius,
&coverage,
colored,
);
for y in 0..height {
for x in 0..width {
let idx = y * width + x;
assert_eq!(
actual[idx], expected[idx],
"composite != fill_border_ring at ({x},{y}) for \
W={width} H={height} T={thickness} R={corner_radius} \
(effective t={t} r={r})",
);
}
}
}
#[test]
fn composite_ring_matches_fill_border_ring_across_geometry_sweep() {
assert_parity(3, 3, 1, 0);
assert_parity(5, 5, 2, 0);
assert_parity(6, 3, 1, 0);
assert_parity(4, 4, 100, 0);
assert_parity(11, 11, 1, 4);
assert_parity(11, 11, 3, 4);
assert_parity(40, 40, 3, 15);
assert_parity(33, 21, 2, 9);
assert_parity(10, 20, 2, 5); assert_parity(20, 10, 2, 5); assert_parity(11, 22, 2, 5);
assert_parity(5, 5, 1, 8); assert_parity(7, 9, 3, 20);
assert_parity(1600, 900, 3, 11); assert_parity(1600, 900, 3, 7);
assert_parity(20, 20, 0, 5);
}
#[test]
fn composite_ring_with_wider_stride_matches_fill_border_ring() {
let (width, height, thickness, corner_radius) = (40, 30, 3, 9);
let (t, r) = effective_geometry(width, height, thickness, corner_radius);
let coverage = render_corner_coverage(r, t);
let colored = pack_bgra(color(0x42, 0x7A, 0xFF), 0xFF);
let mut expected = vec![0u32; width * height];
fill_border_ring(
&mut expected,
width,
height,
thickness,
corner_radius,
colored,
);
let stride = width + 11;
let buf_h = height + 5;
let mut actual = vec![0u32; stride * buf_h];
composite_ring(
&mut actual,
BufferLayout {
stride,
width,
height,
},
thickness,
corner_radius,
&coverage,
colored,
);
for y in 0..height {
for x in 0..width {
assert_eq!(
actual[y * stride + x],
expected[y * width + x],
"stride composite != fill_border_ring at ({x},{y})"
);
}
}
for y in 0..height {
for x in width..stride {
assert_eq!(
actual[y * stride + x],
0,
"stride padding polluted at ({x},{y})"
);
}
}
for y in height..buf_h {
for x in 0..stride {
assert_eq!(
actual[y * stride + x],
0,
"vertical padding polluted at ({x},{y})"
);
}
}
}
#[test]
fn render_corner_coverage_emits_graded_arc() {
let cov = render_corner_coverage(15, 3);
assert_eq!(cov.len(), 15 * 15);
let distinct: std::collections::HashSet<u8> = cov.iter().copied().collect();
assert!(distinct.contains(&0), "extreme corner + interior must be 0");
assert!(
distinct.contains(&255),
"solid straight-band part of the tile must be fully covered"
);
assert!(
distinct.len() >= 3,
"arc must show a graded coverage gradient, got {distinct:?}"
);
}
#[test]
fn render_corner_coverage_zero_radius_is_empty() {
assert!(render_corner_coverage(0, 3).is_empty());
let mut expected = vec![0u32; 6 * 4];
let mut actual = vec![0u32; 6 * 4];
let colored = pack_bgra(color(0, 0, 0), 0xFF);
fill_border_ring(&mut expected, 6, 4, 1, 0, colored);
composite_ring(
&mut actual,
BufferLayout {
stride: 6,
width: 6,
height: 4,
},
1,
0,
&[],
colored,
);
assert_eq!(actual, expected);
}
#[test]
fn next_capacity_non_positive_clamps_to_one() {
assert_eq!(next_capacity(0), 1);
assert_eq!(next_capacity(-1), 1);
assert_eq!(next_capacity(-1024), 1);
}
#[test]
fn next_capacity_rounds_up_to_next_power_of_two() {
assert_eq!(next_capacity(1), 1);
assert_eq!(next_capacity(2), 2);
assert_eq!(next_capacity(3), 4);
assert_eq!(next_capacity(5), 8);
assert_eq!(next_capacity(1024), 1024, "exact pow2 stays put");
assert_eq!(next_capacity(1025), 2048, "one past pow2 rounds up");
assert_eq!(next_capacity(1600), 2048, "realistic window width");
}
#[test]
fn composite_ring_zero_dimension_leaves_buffer_untouched() {
let mut buf_w = vec![0xDEAD_BEEF_u32; 64];
composite_ring(
&mut buf_w,
BufferLayout {
stride: 8,
width: 0,
height: 8,
},
2,
0,
&[],
0xFFFF00FF,
);
assert!(
buf_w.iter().all(|&p| p == 0xDEAD_BEEF),
"zero-width composite must not write any pixel"
);
let mut buf_h = vec![0xDEAD_BEEF_u32; 64];
composite_ring(
&mut buf_h,
BufferLayout {
stride: 8,
width: 8,
height: 0,
},
2,
0,
&[],
0xFFFF00FF,
);
assert!(
buf_h.iter().all(|&p| p == 0xDEAD_BEEF),
"zero-height composite must not write any pixel"
);
}
#[test]
fn composite_ring_zero_thickness_leaves_buffer_untouched() {
let mut buf = vec![0xDEAD_BEEF_u32; 100];
composite_ring(
&mut buf,
BufferLayout {
stride: 10,
width: 10,
height: 10,
},
0,
4, &[],
0xFFFF00FF,
);
assert!(
buf.iter().all(|&p| p == 0xDEAD_BEEF),
"zero-thickness composite must not write any pixel"
);
}
#[should_panic(expected = "pixels buffer must hold at least stride * height")]
#[test]
fn composite_ring_panics_when_buffer_smaller_than_stride_times_height() {
let mut buf = vec![0u32; 10];
composite_ring(
&mut buf,
BufferLayout {
stride: 8,
width: 8,
height: 2,
},
1,
0,
&[],
0xFFFF00FF,
);
}
#[should_panic]
#[test]
fn composite_ring_panics_when_corner_coverage_shorter_than_r_squared() {
let mut buf = vec![0u32; 100];
composite_ring(
&mut buf,
BufferLayout {
stride: 10,
width: 10,
height: 10,
},
1,
4,
&[0u8, 0, 0],
0xFFFF00FF,
);
}
#[test]
fn render_corner_coverage_oversized_thickness_clamps_to_radius() {
let cov_clamped = render_corner_coverage(5, 100);
let cov_at_radius = render_corner_coverage(5, 5);
assert_eq!(
cov_clamped, cov_at_radius,
"thickness > radius must clamp to t == radius"
);
}
#[test]
fn render_corner_coverage_size_is_radius_squared() {
for r in [1usize, 2, 3, 5, 8, 12] {
assert_eq!(
render_corner_coverage(r, r / 2).len(),
r * r,
"tile for r={r} must be r*r bytes"
);
}
}
#[test]
fn render_corner_coverage_tile_is_transpose_symmetric() {
let r = 12;
let cov = render_corner_coverage(r, 4);
for y in 0..r {
for x in 0..r {
assert_eq!(
cov[y * r + x],
cov[x * r + y],
"tile must be symmetric under transpose at ({x},{y})"
);
}
}
}
fn identifiable_coverage(r: usize) -> Vec<u8> {
let mut v = Vec::with_capacity(r * r);
for ty in 0..r {
for tx in 0..r {
v.push((tx * 16 + ty + 1) as u8);
}
}
v
}
#[test]
fn blit_corner_no_flip_writes_tile_verbatim_at_origin() {
let r = 4;
let cov = identifiable_coverage(r);
let mut buf = vec![0u32; r * r];
blit_corner(
&mut buf,
r,
&cov,
r,
0x00FF_FFFF,
CornerPos {
ox: 0,
oy: 0,
flip_x: false,
flip_y: false,
},
);
for ty in 0..r {
for tx in 0..r {
let expected_alpha = cov[ty * r + tx];
assert_eq!(
buf[ty * r + tx],
pack_premultiplied(0x00FF_FFFF, expected_alpha),
"no-flip blit wrong at ({tx},{ty})"
);
}
}
}
#[test]
fn blit_corner_flip_x_mirrors_horizontally() {
let r = 4;
let cov = identifiable_coverage(r);
let mut buf = vec![0u32; r * r];
blit_corner(
&mut buf,
r,
&cov,
r,
0x00FF_FFFF,
CornerPos {
ox: 0,
oy: 0,
flip_x: true,
flip_y: false,
},
);
for ty in 0..r {
for tx in 0..r {
let expected_alpha = cov[ty * r + (r - 1 - tx)];
assert_eq!(
buf[ty * r + tx],
pack_premultiplied(0x00FF_FFFF, expected_alpha),
"flip_x blit wrong at ({tx},{ty})"
);
}
}
}
#[test]
fn blit_corner_flip_y_mirrors_vertically() {
let r = 4;
let cov = identifiable_coverage(r);
let mut buf = vec![0u32; r * r];
blit_corner(
&mut buf,
r,
&cov,
r,
0x00FF_FFFF,
CornerPos {
ox: 0,
oy: 0,
flip_x: false,
flip_y: true,
},
);
for ty in 0..r {
for tx in 0..r {
let expected_alpha = cov[(r - 1 - ty) * r + tx];
assert_eq!(
buf[ty * r + tx],
pack_premultiplied(0x00FF_FFFF, expected_alpha),
"flip_y blit wrong at ({tx},{ty})"
);
}
}
}
#[test]
fn blit_corner_flip_xy_rotates_180() {
let r = 4;
let cov = identifiable_coverage(r);
let mut buf = vec![0u32; r * r];
blit_corner(
&mut buf,
r,
&cov,
r,
0x00FF_FFFF,
CornerPos {
ox: 0,
oy: 0,
flip_x: true,
flip_y: true,
},
);
for ty in 0..r {
for tx in 0..r {
let expected_alpha = cov[(r - 1 - ty) * r + (r - 1 - tx)];
assert_eq!(
buf[ty * r + tx],
pack_premultiplied(0x00FF_FFFF, expected_alpha),
"flip_xy blit wrong at ({tx},{ty})"
);
}
}
}
#[test]
fn blit_corner_skips_zero_coverage_pixels() {
let cov = vec![1u8, 2, 3, 4, 0, 6, 7, 8, 9];
let mut buf = vec![0u32; 9];
blit_corner(
&mut buf,
3,
&cov,
3,
0x00FF_FFFF,
CornerPos {
ox: 0,
oy: 0,
flip_x: false,
flip_y: false,
},
);
assert_eq!(buf[4], 0, "zero-coverage pixel must be skipped");
assert_eq!(
buf[0],
pack_premultiplied(0x00FF_FFFF, cov[0]),
"non-zero pixel at (0,0) must be written"
);
}
#[test]
fn blit_corner_places_tile_at_offset_with_stride() {
let r = 2;
let cov = identifiable_coverage(r);
let stride = 8;
let width = 6;
let height = 5;
let mut buf = vec![0u32; stride * height];
let ox = width - r;
let oy = height - r;
blit_corner(
&mut buf,
stride,
&cov,
r,
0x00FF_FFFF,
CornerPos {
ox,
oy,
flip_x: true,
flip_y: true,
},
);
for ty in 0..r {
for tx in 0..r {
let dst_x = ox + (r - 1 - tx);
let dst_y = oy + (r - 1 - ty);
let src = cov[ty * r + tx];
assert_eq!(
buf[dst_y * stride + dst_x],
pack_premultiplied(0x00FF_FFFF, src),
"offset+stride blit wrong at src ({tx},{ty}) -> dst ({dst_x},{dst_y})"
);
}
}
assert_eq!(buf[0], 0, "buffer outside the tile placement must stay 0");
}
}