Files
designcraft/crates/render/tests/it/text_stroke_behind.rs
T

64 lines
3.2 KiB
Rust

//! Stroke behind fill on text: the fill covers the inner half of a double-width stroke.
use designcraft_color::{Color, swatch::Swatch};
use designcraft_compose::Cache;
use designcraft_doc::build::NewDocument;
use designcraft_doc::{Document, ParaFormat, SpreadRef};
use designcraft_geom::Rect;
use designcraft_render::{RenderOptions, Rendered, Renderer};
const WHITE: [u8; 4] = [255, 255, 255, 255];
const RED: [u8; 4] = [255, 0, 0, 255];
const BLUE: [u8; 4] = [0, 0, 255, 255];
const WEIGHT: f64 = 12.0;
/// A 200 pt "I" filled with `fill`, stroked red at [`WEIGHT`] (none when `stroke` is false).
fn render(fill: &str, stroke: bool, behind: bool) -> Rendered {
let mut d = Document::new(&NewDocument { width: 400.0, height: 400.0, facing_pages: false, ..Default::default() });
d.swatches.push(Swatch::color("Red", Color::rgb8(255, 0, 0)));
d.swatches.push(Swatch::color("Blue", Color::rgb8(0, 0, 255)));
let lid = d.default_layer();
let (_, sid) = d.add_text_frame(SpreadRef::Doc(0), Rect::new(40.0, 0.0, 400.0, 400.0), lid, "I", ParaFormat::default()).unwrap();
d.story_mut(sid).unwrap().format_chars(0..1, |f| {
f.over.size = Some(200.0);
f.over.fill = Some(fill.into());
f.over.stroke = Some(if stroke { "Red" } else { designcraft_color::swatch::NONE }.into());
f.over.stroke_weight = Some(WEIGHT);
f.over.stroke_behind_fill = Some(behind);
});
let mut r = Renderer::new();
r.threads = 0;
let cache = Cache::new();
let cs = cache.get(&d, sid, None);
assert!(!cs.frames[0].lines.is_empty(), "the glyph is set");
r.render_page(&d, &cache, 0, 1.0, false, &RenderOptions { paper: false, background: Some(WHITE), ..Default::default() }).unwrap()
}
/// The left edge of the stem on a row through the middle of the unstroked glyph.
fn stem_edge() -> (u32, u32) {
let img = render("Blue", false, false);
let blue: Vec<(u32, u32)> = (0..img.height).flat_map(|y| (0..img.width).map(move |x| (x, y))).filter(|&(x, y)| img.pixel(x, y) == BLUE).collect();
assert!(!blue.is_empty(), "the glyph is drawn");
let y0 = blue.iter().map(|p| p.1).min().unwrap();
let y1 = blue.iter().map(|p| p.1).max().unwrap();
let y = (y0 + y1) / 2;
let x = (0..img.width).find(|&x| img.pixel(x, y) == BLUE).unwrap();
(x, y)
}
#[test]
fn stroke_behind_fill_shows_only_outside_the_letter() {
let (x, y) = stem_edge();
let inner = x + 3; // inside the outline, within the inner half of a centred stroke
let outer = x - 9; // outside the outline, beyond the outer half of a centred stroke
let over = render("Blue", true, false);
assert_eq!(over.pixel(inner, y), RED, "a centred stroke covers the fill's edge");
assert_eq!(over.pixel(outer, y), WHITE, "a centred stroke reaches half its weight outside");
let behind = render("Blue", true, true);
assert_eq!(behind.pixel(inner, y), BLUE, "the fill covers the stroke behind it");
assert_eq!(behind.pixel(outer, y), RED, "the full stroke weight lies outside the letter");
assert_eq!(behind.pixel(x - 15, y), WHITE, "and no further");
let hollow = render(designcraft_color::swatch::NONE, true, true);
assert_eq!(hollow.pixel(inner, y), WHITE, "with no fill the letter stays empty");
assert_eq!(hollow.pixel(outer, y), RED);
}