mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-13 08:29:14 +00:00
Tests: envelope ink tests set type in a test face and check its outlines
The three envelope ink tests set "Type" in the default family and unwrapped ink_bounds(). Without bundled fonts, craft-fonts or system fonts (vectorcraft-effects' tests on a bare Linux host), no face draws and the effects test panicked at the unwrap. Each test now adds the Heighttest Sans face built from the bundled Source Sans 3 (test-fonts feature, now also on vectorcraft-effects' dev-dependency), sets the text in it, and computes the expected box from the layout's glyph outlines. It checks that envelope_ink gives that box as well as the before and after registration boxes, so a change to the registered measure fails the test.
This commit is contained in:
@@ -26,3 +26,5 @@ serde_json = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
vectorcraft-color = { workspace = true }
|
||||
# A face built in code from the bundled Source Sans 3 (no font file is committed).
|
||||
vectorcraft-text = { workspace = true, features = ["test-fonts"] }
|
||||
|
||||
@@ -6,20 +6,38 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use vectorcraft_doc::{CharStyle, Node, NodeId, NodeKind, TextObject};
|
||||
use vectorcraft_geom::{Point, Rect};
|
||||
use vectorcraft_geom::{Point, Rect, Shape};
|
||||
use vectorcraft_text::test_fonts::{HEIGHT_FAMILY, height_font};
|
||||
|
||||
/// The largest distance between the edges of `a` and `b`.
|
||||
fn off(a: Rect, b: Rect) -> f64 {
|
||||
[a.x0 - b.x0, a.y0 - b.y0, a.x1 - b.x1, a.y1 - b.y1].iter().fold(0.0f64, |m, v| m.max(v.abs()))
|
||||
}
|
||||
|
||||
/// "Type" at 48 pt in a face the test adds, so its glyphs draw on a machine without craft-fonts or
|
||||
/// system fonts.
|
||||
fn type_in_test_face() -> TextObject {
|
||||
assert!(vectorcraft_text::FontDb::global().add_font(height_font(true).unwrap()) > 0, "the test face loads");
|
||||
TextObject::point(Point::new(10.0, 60.0), "Type", CharStyle { font_family: HEIGHT_FAMILY.into(), size: 48.0, ..Default::default() })
|
||||
}
|
||||
|
||||
/// The box of the outlines `t`'s glyphs draw, in document space, measured glyph by glyph.
|
||||
fn outline_box(t: &TextObject) -> Rect {
|
||||
let laid = vectorcraft_text::layout(vectorcraft_text::FontDb::global(), t);
|
||||
let outlines: Vec<Rect> = laid.glyphs.iter().filter(|g| !g.outline.elements().is_empty()).map(|g| (t.xf * &g.outline).bounding_box()).collect();
|
||||
assert_eq!(outlines.len(), 4, "every glyph of \"Type\" draws an outline");
|
||||
outlines.into_iter().reduce(|a, b| a.union(b)).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn live_evaluation_measures_type_in_envelopes_by_its_glyphs() {
|
||||
let t = TextObject::point(Point::new(10.0, 60.0), "Type", CharStyle { size: 48.0, ..Default::default() });
|
||||
let t = type_in_test_face();
|
||||
let n = Arc::new(Node::new(NodeId(1), NodeKind::Text(Box::new(t.clone()))));
|
||||
let laid = n.geometric_bounds().unwrap();
|
||||
let ink = t.xf.transform_rect_bbox(vectorcraft_text::layout(vectorcraft_text::FontDb::global(), &t).ink_bounds().unwrap());
|
||||
let ink = outline_box(&t);
|
||||
assert!(laid.height() - ink.height() > 1.0, "the laid-out box {laid:?} reaches past the glyphs {ink:?}");
|
||||
let measured = vectorcraft_text::envelope_ink(&t, t.xf, None).unwrap();
|
||||
assert!(off(measured, ink) < 1e-6, "the envelope measure gives the glyphs' box: {measured:?} vs {ink:?}");
|
||||
let before = vectorcraft_doc::live::envelope_content_bounds(std::slice::from_ref(&n)).unwrap();
|
||||
assert!(off(before, laid) < 1e-6, "with nothing registered, type keeps its laid-out box: {before:?} vs {laid:?}");
|
||||
|
||||
|
||||
@@ -6,20 +6,38 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use vectorcraft_doc::{CharStyle, Node, NodeId, NodeKind, TextObject};
|
||||
use vectorcraft_geom::{Point, Rect};
|
||||
use vectorcraft_geom::{Point, Rect, Shape};
|
||||
use vectorcraft_text::test_fonts::{HEIGHT_FAMILY, height_font};
|
||||
|
||||
/// The largest distance between the edges of `a` and `b`.
|
||||
fn off(a: Rect, b: Rect) -> f64 {
|
||||
[a.x0 - b.x0, a.y0 - b.y0, a.x1 - b.x1, a.y1 - b.y1].iter().fold(0.0f64, |m, v| m.max(v.abs()))
|
||||
}
|
||||
|
||||
/// "Type" at 48 pt in a face the test adds, so its glyphs draw on a machine without craft-fonts or
|
||||
/// system fonts.
|
||||
fn type_in_test_face() -> TextObject {
|
||||
assert!(vectorcraft_text::FontDb::global().add_font(height_font(true).unwrap()) > 0, "the test face loads");
|
||||
TextObject::point(Point::new(10.0, 60.0), "Type", CharStyle { font_family: HEIGHT_FAMILY.into(), size: 48.0, ..Default::default() })
|
||||
}
|
||||
|
||||
/// The box of the outlines `t`'s glyphs draw, in document space, measured glyph by glyph.
|
||||
fn outline_box(t: &TextObject) -> Rect {
|
||||
let laid = vectorcraft_text::layout(vectorcraft_text::FontDb::global(), t);
|
||||
let outlines: Vec<Rect> = laid.glyphs.iter().filter(|g| !g.outline.elements().is_empty()).map(|g| (t.xf * &g.outline).bounding_box()).collect();
|
||||
assert_eq!(outlines.len(), 4, "every glyph of \"Type\" draws an outline");
|
||||
outlines.into_iter().reduce(|a, b| a.union(b)).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reading_an_ai_file_measures_type_in_envelopes_by_its_glyphs() {
|
||||
let t = TextObject::point(Point::new(10.0, 60.0), "Type", CharStyle { size: 48.0, ..Default::default() });
|
||||
let t = type_in_test_face();
|
||||
let n = Arc::new(Node::new(NodeId(1), NodeKind::Text(Box::new(t.clone()))));
|
||||
let laid = n.geometric_bounds().unwrap();
|
||||
let ink = t.xf.transform_rect_bbox(vectorcraft_text::layout(vectorcraft_text::FontDb::global(), &t).ink_bounds().unwrap());
|
||||
let ink = outline_box(&t);
|
||||
assert!(laid.height() - ink.height() > 1.0, "the laid-out box {laid:?} reaches past the glyphs {ink:?}");
|
||||
let measured = vectorcraft_text::envelope_ink(&t, t.xf, None).unwrap();
|
||||
assert!(off(measured, ink) < 1e-6, "the envelope measure gives the glyphs' box: {measured:?} vs {ink:?}");
|
||||
let before = vectorcraft_doc::live::envelope_content_bounds(std::slice::from_ref(&n)).unwrap();
|
||||
assert!(off(before, laid) < 1e-6, "with nothing registered, type keeps its laid-out box: {before:?} vs {laid:?}");
|
||||
|
||||
|
||||
@@ -7,20 +7,38 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use vectorcraft_doc::{CharStyle, Node, NodeId, NodeKind, TextObject};
|
||||
use vectorcraft_geom::{Point, Rect};
|
||||
use vectorcraft_geom::{Point, Rect, Shape};
|
||||
use vectorcraft_text::test_fonts::{HEIGHT_FAMILY, height_font};
|
||||
|
||||
/// The largest distance between the edges of `a` and `b`.
|
||||
fn off(a: Rect, b: Rect) -> f64 {
|
||||
[a.x0 - b.x0, a.y0 - b.y0, a.x1 - b.x1, a.y1 - b.y1].iter().fold(0.0f64, |m, v| m.max(v.abs()))
|
||||
}
|
||||
|
||||
/// "Type" at 48 pt in a face the test adds, so its glyphs draw on a machine without craft-fonts or
|
||||
/// system fonts.
|
||||
fn type_in_test_face() -> TextObject {
|
||||
assert!(vectorcraft_text::FontDb::global().add_font(height_font(true).unwrap()) > 0, "the test face loads");
|
||||
TextObject::point(Point::new(10.0, 60.0), "Type", CharStyle { font_family: HEIGHT_FAMILY.into(), size: 48.0, ..Default::default() })
|
||||
}
|
||||
|
||||
/// The box of the outlines `t`'s glyphs draw, in document space, measured glyph by glyph.
|
||||
fn outline_box(t: &TextObject) -> Rect {
|
||||
let laid = vectorcraft_text::layout(vectorcraft_text::FontDb::global(), t);
|
||||
let outlines: Vec<Rect> = laid.glyphs.iter().filter(|g| !g.outline.elements().is_empty()).map(|g| (t.xf * &g.outline).bounding_box()).collect();
|
||||
assert_eq!(outlines.len(), 4, "every glyph of \"Type\" draws an outline");
|
||||
outlines.into_iter().reduce(|a, b| a.union(b)).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_new_renderer_measures_type_in_envelopes_by_its_glyphs() {
|
||||
let t = TextObject::point(Point::new(10.0, 60.0), "Type", CharStyle { size: 48.0, ..Default::default() });
|
||||
let t = type_in_test_face();
|
||||
let n = Arc::new(Node::new(NodeId(1), NodeKind::Text(Box::new(t.clone()))));
|
||||
let laid = n.geometric_bounds().unwrap();
|
||||
let ink = t.xf.transform_rect_bbox(vectorcraft_text::layout(vectorcraft_text::FontDb::global(), &t).ink_bounds().unwrap());
|
||||
let ink = outline_box(&t);
|
||||
assert!(laid.height() - ink.height() > 1.0, "the laid-out box {laid:?} reaches past the glyphs {ink:?}");
|
||||
let measured = vectorcraft_text::envelope_ink(&t, t.xf, None).unwrap();
|
||||
assert!(off(measured, ink) < 1e-6, "the envelope measure gives the glyphs' box: {measured:?} vs {ink:?}");
|
||||
let before = vectorcraft_doc::live::envelope_content_bounds(std::slice::from_ref(&n)).unwrap();
|
||||
assert!(off(before, laid) < 1e-6, "with nothing registered, type keeps its laid-out box: {before:?} vs {laid:?}");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user