mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-07 12:13:19 +00:00
SVG: centred and right-aligned type on a path keeps its place
Squashed from #5977 onto main.
This commit is contained in:
@@ -208,7 +208,7 @@ sync_github_name = true
|
||||
[people.sadkotheguest]
|
||||
real_name = "Alexander Buraga"
|
||||
display_name = "Alexander Buraga"
|
||||
sync_github_name = false
|
||||
sync_github_name = false
|
||||
|
||||
[people.adikshan11]
|
||||
real_name = "Adithya Shankaran"
|
||||
@@ -216,3 +216,7 @@ sync_github_name = true
|
||||
|
||||
[people.slafebre]
|
||||
real_name = "Sven Lafebre"
|
||||
|
||||
[people.kylekanouse]
|
||||
real_name = "Kyle Kanouse"
|
||||
sync_github_name = true
|
||||
|
||||
@@ -519,14 +519,24 @@ impl Writer<'_> {
|
||||
let space = (lay.bounds, self.xf * t.xf);
|
||||
let base = self.char_props(&t.first_style(), space);
|
||||
let mut props = base.clone();
|
||||
match t.para_at(0).justify {
|
||||
Justify::Center | Justify::JustifyCenter => props.push(("text-anchor", "middle".into())),
|
||||
Justify::Right | Justify::JustifyRight => props.push(("text-anchor", "end".into())),
|
||||
_ => {}
|
||||
}
|
||||
let (from, to) = t.kind.path_span().unwrap_or((start, 1.0));
|
||||
// The anchor sits where the layout aligns the line within its span.
|
||||
let at = match t.para_at(0).justify {
|
||||
Justify::Center | Justify::JustifyCenter => {
|
||||
props.push(("text-anchor", "middle".into()));
|
||||
(from + to) / 2.0
|
||||
}
|
||||
Justify::Right | Justify::JustifyRight => {
|
||||
props.push(("text-anchor", "end".into()));
|
||||
to
|
||||
}
|
||||
_ => from,
|
||||
};
|
||||
// A closed path's span runs past its start point; `startOffset` can't, so wrap it.
|
||||
let at = if at > 1.0 { at - 1.0 } else { at };
|
||||
props.extend(css::transparency(n));
|
||||
let a = self.attrs(&props);
|
||||
let offset = fmt_num(start * 100.0, 3);
|
||||
let offset = fmt_num(at * 100.0, 3);
|
||||
let mut s = format!("<text{id} xml:space=\"preserve\"{a}><textPath xlink:href=\"#{pid}\" startOffset=\"{offset}%\">");
|
||||
for run in &t.runs {
|
||||
let mut diff = run_diff(&base, self.char_props(&run.style, space));
|
||||
|
||||
@@ -444,6 +444,40 @@ fn text_on_path_roundtrip() {
|
||||
assert!(close_rect(doc_path, PathData::from_bezpath(&curve).bounds().unwrap(), 0.01), "{doc_path:?}");
|
||||
}
|
||||
|
||||
/// Centred and right-aligned type on a path anchors where the layout aligns it: the middle or the
|
||||
/// end of its span, wrapped on a closed path. It reads back drawn where it was.
|
||||
#[test]
|
||||
fn aligned_text_on_path_anchors_within_its_span() {
|
||||
use vectorcraft_doc::Justify;
|
||||
use vectorcraft_geom::Shape;
|
||||
let mut curve = vectorcraft_geom::BezPath::new();
|
||||
curve.move_to((20.0, 150.0));
|
||||
curve.curve_to((60.0, 40.0), (140.0, 40.0), (180.0, 150.0));
|
||||
let circle = vectorcraft_geom::kurbo::Circle::new((100.0, 100.0), 60.0).to_path(0.01);
|
||||
let drawn = |t: &TextObject| t.xf.transform_rect_bbox(vectorcraft_text::layout(vectorcraft_text::FontDb::global(), t).bounds);
|
||||
for (path, start, justify, offset) in [
|
||||
(&curve, 0.25, Justify::Center, "62.5%"),
|
||||
(&curve, 0.25, Justify::Right, "100%"),
|
||||
(&curve, 0.25, Justify::Left, "25%"),
|
||||
(&circle, 0.7, Justify::Center, "20%"),
|
||||
] {
|
||||
let mut d = Document::new(200.0, 200.0);
|
||||
let mut t = TextObject::point(Point::ZERO, "Aligned", CharStyle { size: 14.0, ..CharStyle::default() });
|
||||
t.kind = TextKind::OnPath { path: PathData::from_bezpath(path), start, end: None };
|
||||
t.para.justify = justify;
|
||||
let before = drawn(&t);
|
||||
let id = d.alloc_id();
|
||||
let d = doc_with(vec![Node::new(id, NodeKind::Text(Box::new(t)))]);
|
||||
let svg = export(&d, &ExportOptions::default());
|
||||
assert!(svg.contains(&format!("startOffset=\"{offset}\"")), "{justify:?} at {start}: {svg}");
|
||||
if path == &curve {
|
||||
let r = import(&svg).unwrap();
|
||||
let NodeKind::Text(t) = &art(&r)[0].kind else { panic!() };
|
||||
assert!(close_rect(drawn(t), before, 0.5), "{justify:?}: {:?} {before:?}", drawn(t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An end bracket, Align to Path or Spacing, which `<textPath>` can't express, keep their look as
|
||||
/// outlines (#429).
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user