diff --git a/crates/doc/src/text.rs b/crates/doc/src/text.rs index 62bca0ba1..5add7b34c 100644 --- a/crates/doc/src/text.rs +++ b/crates/doc/src/text.rs @@ -1713,18 +1713,17 @@ impl TextObject { /// How far the characters' strokes paint past their glyphs, in document space: they scale /// with the type. pub fn char_stroke_outset(&self) -> f64 { - self.char_strokes(CharStyle::stroke_outset) + let k = crate::node::Scaling::factor(self.xf).unwrap_or(1.0); + self.runs.iter().map(|r| r.style.stroke_outset()).fold(0.0, f64::max) * k } /// How far the characters' strokes can paint past their glyphs, their miter spikes and square /// caps included ([`StrokeLayer::reach`]), in document space: what a change of the type must - /// redraw. The visual bounds take [`Self::char_stroke_outset`]. + /// redraw. They stretch with the type, so this is as far as its transform takes them on either + /// axis. The visual bounds take [`Self::char_stroke_outset`]. pub fn char_stroke_reach(&self) -> f64 { - self.char_strokes(|style| if style.has_stroke() { style.stroke_layer().reach() } else { 0.0 }) - } - /// The farthest `outset` of the characters' styles, scaled with the type. - fn char_strokes(&self, outset: impl Fn(&CharStyle) -> f64) -> f64 { - let k = crate::node::Scaling::factor(self.xf).unwrap_or(1.0); - self.runs.iter().map(|r| outset(&r.style)).fold(0.0, f64::max) * k + let reach = self.runs.iter().filter(|r| r.style.has_stroke()).map(|r| r.style.stroke_layer().reach()).fold(0.0, f64::max); + let [a, b, c, d, ..] = self.xf.as_coeffs(); + reach * (a.abs() + c.abs()).max(b.abs() + d.abs()) } pub fn transform(&mut self, a: Affine) { self.xf = a * self.xf; diff --git a/crates/render/src/tests_changed.rs b/crates/render/src/tests_changed.rs index 21b75c158..108e7604e 100644 --- a/crates/render/src/tests_changed.rs +++ b/crates/render/src/tests_changed.rs @@ -235,3 +235,26 @@ fn an_edit_while_a_pattern_is_edited_changes_everything() { new.node_mut(loose).unwrap().transform(Affine::translate((7.0, 3.0)), false); assert_eq!(changed(&old, &new), Changed::Everything); } + +/// Type stretched more on one axis than its area grows: its characters' strokes stretch with it. +#[test] +fn moving_stretched_type_changes_where_its_stretched_strokes_reach() { + let mut old = Document::new(110.0, 80.0); + let l = old.layers[0].id; + let style = vectorcraft_doc::text::CharStyle { + size: 4.0, + stroke: Paint::solid(Color::BLACK), + stroke_width: 1.0, + stroke_join: vectorcraft_doc::LineJoin::Miter, + stroke_miter_limit: 10.0, + ..Default::default() + }; + let mut t = vectorcraft_doc::text::TextObject::point(Point::ZERO, "VAWV", style); + t.cached_bounds = Some(vectorcraft_text::layout(vectorcraft_text::FontDb::global(), &t).bounds); + // Its area stays, so its scale factor is 1, while it grows ten times as wide. + t.xf = Affine::translate((10.0, 40.0)) * Affine::scale_non_uniform(10.0, 0.1); + let text = old.insert(Some(l), 0, Node::new(NodeId(0), NodeKind::Text(Box::new(t)))).unwrap(); + let mut new = old.clone(); + new.node_mut(text).unwrap().transform(Affine::translate((9.0, 7.0)), false); + area(redraw(&old, &new)); +}