mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-29 04:07:12 -06:00
Align Stroke inside or outside on live type (#2294)
The characters' stroke takes Align Stroke like an object stroke: CharStyle keeps stroke_align (written only when not centred), stroke.set and text.setRangeStyle strokeOptions apply align to type, and the Stroke panel enables the buttons for type. Canvas, PDF and EPS draw it around the glyphs through stroke_layer(); SVG keeps the text live and writes the aligned stroke on the glyph outlines, clipped or masked. Type's visual bounds grow with its character strokes.
This commit is contained in:
@@ -1217,6 +1217,13 @@ impl Node {
|
||||
let o = self.appearance.outset() + symbols.map_or(0.0, |s| s.brush_pad(symbol));
|
||||
self.projected(Some(b)).map(|b| b.inflate(o, o))
|
||||
}
|
||||
NodeKind::Text(t) => {
|
||||
// The characters' strokes paint around the glyphs, scaled with the type.
|
||||
let k = Scaling::factor(t.xf).unwrap_or(1.0);
|
||||
let chars = t.runs.iter().map(|r| r.style.stroke_outset()).fold(0.0, f64::max) * k;
|
||||
let o = self.appearance.outset().max(chars);
|
||||
self.geometric(symbols).map(|b| b.inflate(o, o))
|
||||
}
|
||||
_ => {
|
||||
let o = self.appearance.outset();
|
||||
self.geometric(symbols).map(|b| b.inflate(o, o))
|
||||
@@ -2336,6 +2343,25 @@ mod tests {
|
||||
assert_eq!(p.visual_bounds(), Some(Rect::new(-0.5, -0.5, 10.5, 10.5)));
|
||||
}
|
||||
|
||||
/// Type's visual bounds grow by how far its character strokes paint past the glyphs: half the
|
||||
/// weight centred, the whole weight outside, nothing inside; scaled with the type.
|
||||
#[test]
|
||||
fn type_visual_bounds_grow_with_the_character_stroke() {
|
||||
use crate::appearance::StrokeAlign;
|
||||
use crate::text::{CharStyle, TextObject};
|
||||
let style = CharStyle { stroke: vectorcraft_color::Paint::solid(vectorcraft_color::Color::BLACK), stroke_width: 4.0, ..Default::default() };
|
||||
let mut t = TextObject::point(vectorcraft_geom::Point::new(0.0, 0.0), "Ab", style);
|
||||
t.xf = Affine::scale(2.0) * t.xf;
|
||||
let node = |t: &TextObject| Node::new(NodeId(1), NodeKind::Text(Box::new(t.clone())));
|
||||
let g = node(&t).geometric_bounds().unwrap();
|
||||
for (align, grow) in [(StrokeAlign::Center, 4.0), (StrokeAlign::Outside, 8.0), (StrokeAlign::Inside, 0.0)] {
|
||||
t.runs[0].style.stroke_align = align;
|
||||
assert_eq!(node(&t).visual_bounds(), Some(g.inflate(grow, grow)), "{align:?}");
|
||||
}
|
||||
t.runs[0].style.stroke = vectorcraft_color::Paint::None;
|
||||
assert_eq!(node(&t).visual_bounds(), Some(g), "no stroke, no growth");
|
||||
}
|
||||
|
||||
/// A group holding a path, a compound, an image and a nested group, as a file writes it.
|
||||
fn nested_group() -> Node {
|
||||
let path = |id| Node::path(NodeId(id), shapes::rectangle(Rect::new(0.0, 0.0, 10.0, 10.0)), Appearance::default_art());
|
||||
|
||||
Reference in New Issue
Block a user