Files
figcraft/crates/vectordrawable/src/text.rs
T
Filip Strajnar 8b5441eb84 M6: figcraft-vectordrawable: an Android Vector Drawable writer
A new L4 crate that writes layers as an Android Vector Drawable (XML):
shapes, booleans and text as baked path data, solid and gradient fills
(linear, radial and sweep, exact for any handle frame via a group and a
2x2 SVD), native strokes where Android draws them the same and filled
stroke outlines otherwise, clip frames and masks as <clip-path> groups.

What a drawable can't hold is governed by Compat (bestEffort / exact /
ignore): layer opacity over overlapping shapes, even-odd fills and clips
(rewritten to non-zero via pathops), diamond gradients, alpha masks;
effects, image and pattern fills and blend modes are left out with a
warning. Output is pretty-printed, numbers are finite and short, names
(android:name) are optional, escaped and unique.
2026-10-18 20:24:19 +02:00

31 lines
1.2 KiB
Rust

//! Text layers as glyph outlines, one path per styled run.
use figcraft_color::Paint;
use figcraft_doc::{Node, NodeKind};
use figcraft_geom::{Affine, BezPath};
/// Text layer `n`'s glyph and decoration outlines grouped by style, in layer space, each with the
/// fills it paints in (its own, else the layer's). `None` for other layers and text that doesn't
/// lay out.
pub(crate) fn runs(n: &Node) -> Option<Vec<(BezPath, Vec<Paint>)>> {
let NodeKind::Text(_) = &n.kind else { return None };
let (layout, dy) = figcraft_text::layout_node(n)?;
let mut by_style: std::collections::BTreeMap<usize, BezPath> = std::collections::BTreeMap::new();
for g in &layout.glyphs {
by_style.entry(g.style).or_default().extend(g.path().elements().iter().copied());
}
for d in &layout.decorations {
by_style.entry(d.style).or_default().extend(d.path().elements().iter().copied());
}
Some(
by_style
.into_iter()
.map(|(k, mut path)| {
path.apply_affine(Affine::translate((0.0, dy)));
let fills = layout.styles.get(k).and_then(|s| s.fills.clone()).unwrap_or_else(|| n.fills.clone());
(path, fills)
})
.collect(),
)
}