#![cfg(all(feature = "desktop", full_widgets))]
use rust_widgets::core::{Color, Rect, Size};
use rust_widgets::render::SoftwareSurface;
fn pixel(rgba: &[u8], width: u32, x: u32, y: u32) -> [u8; 4] {
let offset = ((y * width + x) * 4) as usize;
[rgba[offset], rgba[offset + 1], rgba[offset + 2], rgba[offset + 3]]
}
fn present(surface: &mut SoftwareSurface) {
surface.end_frame();
}
#[test]
fn a_rect_near_i32_max_does_not_overflow_its_span() {
let mut surface = SoftwareSurface::new(Size::new(4, 4), 1.0);
surface.fill_rect(Rect::new(i32::MAX - 2, 0, 8, 1), Color::RED);
surface.draw_rect(Rect::new(i32::MAX - 2, 0, 8, 1), Color::RED);
surface.fill_rounded_rect(Rect::new(i32::MAX - 2, 0, 8, 8), 2, Color::RED);
surface.end_frame();
let rgba = surface.frame_rgba();
assert!(
rgba.chunks(4).all(|chunk| chunk == [0, 0, 0, 0]),
"a rect entirely off the surface must draw nothing"
);
}
#[test]
fn a_width_above_the_f32_significand_is_not_rounded_down() {
const WIDTH: u32 = 16_777_217; let mut surface = SoftwareSurface::new(Size::new(2, 1), 1.0);
surface.fill_rect(Rect::new(-(1 << 24), 0, WIDTH, 1), Color::RED);
surface.end_frame();
let rgba = surface.frame_rgba();
assert_eq!(
pixel(rgba, 2, 0, 0),
[255, 0, 0, 255],
"column 0 is inside the exact span; rounding the width down to 2^24 excluded it"
);
assert_eq!(pixel(rgba, 2, 1, 0), [0, 0, 0, 0], "column 1 is outside the span");
}
#[test]
fn an_oversized_rect_fills_the_whole_surface_instead_of_wrapping_to_nothing() {
let mut surface = SoftwareSurface::new(Size::new(8, 4), 1.0);
surface.fill_rect(Rect::new(0, 0, u32::MAX, u32::MAX), Color::RED);
present(&mut surface);
let rgba = surface.frame_rgba();
assert_eq!(
pixel(rgba, 8, 0, 0),
[255, 0, 0, 255],
"a rect far larger than the surface must fill it; the truncating cast left it empty"
);
assert_eq!(pixel(rgba, 8, 7, 3), [255, 0, 0, 255], "the fill must reach the last pixel");
}
#[test]
fn a_rect_flush_with_the_surface_edge_keeps_its_last_row_and_column() {
let mut surface = SoftwareSurface::new(Size::new(4, 4), 1.0);
surface.fill_rect(Rect::new(0, 0, 4, 4), Color::BLUE);
present(&mut surface);
let rgba = surface.frame_rgba();
for y in 0..4 {
for x in 0..4 {
assert_eq!(
pixel(rgba, 4, x, y),
[0, 0, 255, 255],
"pixel ({x},{y}) of a flush fill is missing"
);
}
}
}
#[test]
fn a_stroke_flush_with_the_surface_edge_draws_every_side() {
let mut surface = SoftwareSurface::new(Size::new(6, 6), 1.0);
surface.draw_rect(Rect::new(0, 0, 6, 6), Color::GREEN);
present(&mut surface);
let rgba = surface.frame_rgba();
for x in 0..6 {
assert_eq!(pixel(rgba, 6, x, 0), [0, 255, 0, 255], "top edge at x={x}");
assert_eq!(pixel(rgba, 6, x, 5), [0, 255, 0, 255], "bottom edge at x={x}");
}
for y in 0..6 {
assert_eq!(pixel(rgba, 6, 0, y), [0, 255, 0, 255], "left edge at y={y}");
assert_eq!(pixel(rgba, 6, 5, y), [0, 255, 0, 255], "right edge at y={y}");
}
assert_eq!(pixel(rgba, 6, 3, 3), [0, 0, 0, 0], "the interior must stay clear");
}
#[test]
fn a_negative_origin_is_clipped_to_the_visible_area() {
let mut surface = SoftwareSurface::new(Size::new(4, 4), 1.0);
surface.fill_rect(Rect::new(-2, -2, 4, 4), Color::WHITE);
present(&mut surface);
let rgba = surface.frame_rgba();
assert_eq!(pixel(rgba, 4, 0, 0), [255, 255, 255, 255]);
assert_eq!(pixel(rgba, 4, 1, 1), [255, 255, 255, 255]);
assert_eq!(pixel(rgba, 4, 2, 2), [0, 0, 0, 0], "outside the rect must stay clear");
assert_eq!(pixel(rgba, 4, 3, 3), [0, 0, 0, 0]);
}
#[test]
fn a_zero_sized_rect_draws_nothing() {
let mut surface = SoftwareSurface::new(Size::new(4, 4), 1.0);
surface.fill_rect(Rect::new(1, 1, 0, 0), Color::RED);
surface.draw_rect(Rect::new(1, 1, 0, 0), Color::RED);
present(&mut surface);
let rgba = surface.frame_rgba();
assert!(
rgba.chunks(4).all(|chunk| chunk == [0, 0, 0, 0]),
"a zero-sized rect must leave the surface untouched"
);
}