mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-09 06:06:38 +00:00
An envelope mapped type from its laid-out box: ascent to descent for point type, the frame for area type. The distorted glyphs then filled less of the envelope than other art does, with room above the capitals and below the baseline. The envelope now maps type from the bounds of its glyph outlines, underlines and strikethroughs when the type is on its own, in groups and layers, or used as a clipping path. Inline graphics count by their boxes. Rotated type and type in perspective map from their outlines as they are drawn. Make with Mesh, Make with Top Object and Reset with Mesh without Maintain Shape use those bounds. Type that draws nothing keeps its laid-out box, and so does type inside any other object, such as a blend, a repeat or a symbol instance. Shrink Text to Fit type is measured as it is laid out on the page. vectorcraft-text's envelope_ink measures the type, and register_envelope_ink registers it with the document crate. The engine session, Renderer::new, live evaluation in vectorcraft-effects and the .ai reader register it. The document crate keeps the measured boxes per thread, by object and by a hash of the content, and measures again when the type, the fonts, the hyphenation exceptions or the transform's scale or rotation change. This is VectorCraft's own rule. Envelopes of type made in VectorCraft and in saved files map from the glyph outline bounds instead of the type's laid-out box, so they redraw differently.
31 lines
1.7 KiB
Rust
31 lines
1.7 KiB
Rust
//! A renderer made without an engine session makes envelopes measure type by its glyph outlines.
|
||
//! One test in its own process, so nothing else has registered the measure before the renderer is
|
||
//! made.
|
||
// Integration tests: unwrapping and panicking on failure is fine here, unlike in shipped code (AGENTS.md › Robustness).
|
||
#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
|
||
|
||
use std::sync::Arc;
|
||
|
||
use vectorcraft_doc::{CharStyle, Node, NodeId, NodeKind, TextObject};
|
||
use vectorcraft_geom::{Point, Rect};
|
||
|
||
/// 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()))
|
||
}
|
||
|
||
#[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 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());
|
||
assert!(laid.height() - ink.height() > 1.0, "the laid-out box {laid:?} reaches past the glyphs {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:?}");
|
||
|
||
let _ = vectorcraft_render::Renderer::new();
|
||
let after = vectorcraft_doc::live::envelope_content_bounds(&[n]).unwrap();
|
||
assert!(off(after, ink) < 1e-6, "after a renderer is made, type is measured by its glyphs: {after:?} vs {ink:?}");
|
||
}
|