tests.rs
raw
use super::*;
use crate::display_list::{Fragment, Glyph, GlyphRun};
use crate::geom::{Affine, Rect, Stroke};
use crate::paint::{Blob, Color, FontData};
fn font() -> FontData {
// The bytes are never parsed here: `ink_bounds` reads glyph positions and
// the run's size, both of which the display list already carries.
FontData::new(Blob::new(std::sync::Arc::new(Vec::new())), 0)
}
fn run(size: f32, positions: &[(f32, f32)]) -> GlyphRun {
GlyphRun {
font: font(),
size,
brush: Color::BLACK.into(),
glyphs: positions
.iter()
.map(|&(x, y)| Glyph { id: 0, x, y })
.collect(),
normalized_coords: Vec::new(),
hint: true,
synthesis: Default::default(),
}
}
#[test]
fn a_run_bounds_its_glyphs_with_room_for_their_ink() {
let bounds = run(10.0, &[(100.0, 200.0), (140.0, 200.0)])
.ink_bounds()
.expect("a run with glyphs has bounds");
// The placements alone span (100,200)–(140,200); the reach is what turns
// that into a box the outlines cannot escape.
assert!(bounds.x0 <= 100.0 && bounds.x1 >= 140.0);
assert!(bounds.y0 < 200.0 && bounds.y1 > 200.0);
assert!(bounds.x1 - 140.0 >= 10.0, "an em of advance at the least");
}
#[test]
fn an_empty_run_has_no_bounds() {
assert!(run(10.0, &[]).ink_bounds().is_none());
}
#[test]
fn scope_markers_and_children_report_no_bounds() {
let mut fragment = Fragment::new();
fragment.push_clip(Rect::new(0.0, 0.0, 10.0, 10.0));
fragment.push_transform(Affine::translate((1.0, 1.0)));
fragment.pop_transform();
fragment.pop_clip();
for item in &fragment.items {
assert_eq!(item.draw_bounds(Affine::IDENTITY), None);
}
}
#[test]
fn a_fill_reports_its_shape_under_the_transform() {
let mut fragment = Fragment::new();
fragment.fill(Rect::new(0.0, 0.0, 10.0, 10.0), Color::BLACK);
let bounds = fragment.items[0]
.draw_bounds(Affine::translate((100.0, 0.0)))
.expect("a fill draws");
assert_eq!(bounds, Rect::new(100.0, 0.0, 110.0, 10.0));
}
#[test]
fn a_stroke_reports_past_its_shape() {
let mut fragment = Fragment::new();
fragment.stroke(
Rect::new(0.0, 0.0, 10.0, 10.0),
Color::BLACK,
Stroke::new(4.0),
);
let bounds = fragment.items[0]
.draw_bounds(Affine::IDENTITY)
.expect("a stroke draws");
assert!(bounds.x0 <= -2.0 && bounds.x1 >= 12.0);
}
#[test]
fn an_unclipped_stack_keeps_everything() {
let clip = ClipBounds::new(None);
assert!(clip.any_visible());
assert!(clip.visible(Rect::new(-1e9, -1e9, -1e8, -1e8)));
}
#[test]
fn a_clip_culls_what_lies_outside_it() {
let clip = ClipBounds::new(Some(Rect::new(0.0, 0.0, 100.0, 100.0)));
assert!(clip.visible(Rect::new(50.0, 50.0, 150.0, 150.0)));
assert!(!clip.visible(Rect::new(200.0, 0.0, 300.0, 100.0)));
// Sharing an edge covers no pixels.
assert!(!clip.visible(Rect::new(100.0, 0.0, 200.0, 100.0)));
}
#[test]
fn nested_clips_intersect_and_unwind() {
let mut clip = ClipBounds::new(Some(Rect::new(0.0, 0.0, 100.0, 100.0)));
clip.push(Rect::new(50.0, 0.0, 200.0, 100.0));
assert_eq!(clip.current(), Some(Rect::new(50.0, 0.0, 100.0, 100.0)));
assert!(!clip.visible(Rect::new(0.0, 0.0, 40.0, 40.0)));
clip.pop();
assert!(clip.visible(Rect::new(0.0, 0.0, 40.0, 40.0)));
}
#[test]
fn a_clip_closed_to_nothing_stays_closed() {
let mut clip = ClipBounds::new(Some(Rect::new(0.0, 0.0, 100.0, 100.0)));
clip.push(Rect::new(500.0, 500.0, 600.0, 600.0));
assert!(!clip.any_visible());
// A scope opened inside it cannot bring anything back.
clip.push(Rect::new(0.0, 0.0, 100.0, 100.0));
assert!(!clip.any_visible());
assert!(!clip.visible(Rect::new(0.0, 0.0, 100.0, 100.0)));
clip.pop();
clip.pop();
assert!(clip.any_visible());
}
#[test]
fn an_unclipped_outer_scope_is_restored_as_unclipped() {
let mut clip = ClipBounds::new(None);
clip.push(Rect::new(0.0, 0.0, 10.0, 10.0));
assert!(!clip.visible(Rect::new(100.0, 100.0, 200.0, 200.0)));
clip.pop();
assert_eq!(clip.current(), None);
assert!(clip.visible(Rect::new(100.0, 100.0, 200.0, 200.0)));
}
#[test]
fn the_transform_is_what_places_an_item_against_the_clip() {
let clip = ClipBounds::new(Some(Rect::new(0.0, 0.0, 100.0, 100.0)));
let mut fragment = Fragment::new();
fragment.fill(Rect::new(0.0, 0.0, 10.0, 10.0), Color::BLACK);
let item = &fragment.items[0];
assert!(clip.item_visible(item, Affine::IDENTITY));
assert!(!clip.item_visible(item, Affine::translate((1000.0, 0.0))));
}