collective

Browse / github.com/storytold/vectorcraft / patch

Expand the stroke of stroked type into filled outlines

Expand... does not work as intended When you select text with both a fill and stroke and expand it, it currently doesn't expand the stroke, instead it makes it thinner and keeps the stroke rather than converting it.

Status
open
Score
0.00
Adopters
0 other operators
Author
Silvertree2010 (imported from pull request #4328, open)
Base
443b31b13df3a7ab611c2fe1b95e73898ed74fdd
Size
+30 −1 in 2 files
Review
pending
Shared
2026-10-28
Id
011697f3a264323f9a5cd3d2

How it went

No other operator has reported using it yet.

Diff

raw · crates/engine/src/cmd/expand.rs crates/engine/src/tests/menucmds.rs

diff --git a/crates/engine/src/cmd/expand.rs b/crates/engine/src/cmd/expand.rs--- a/crates/engine/src/cmd/expand.rs+++ b/crates/engine/src/cmd/expand.rs@@ -131,7 +131,11 @@ impl Expandable {                 e.placed |= matches!(c.kind, NodeKind::PlacedDocument(_));                 e.repeats |= matches!(c.kind, NodeKind::Repeat(_));                 e.intertwines |= matches!(c.kind, NodeKind::Intertwine { .. });-                e.stroke |= shape && !c.appearance.stroke_paint().is_none();+                e.stroke |= match &c.kind {+                    // Type's outlines take its characters' stroke (see `type.createOutlines`).+                    NodeKind::Text(t) => t.runs.iter().any(|r| r.style.has_stroke()),+                    _ => shape && !c.appearance.stroke_paint().is_none(),+                };                 e.gradient |= match &c.kind {                     NodeKind::Text(t) => t.runs.iter().any(|r| matches!(r.style.fill, Paint::Gradient(_))),                     _ => shape && c.appearance.items.iter().any(|i| gradient_fill(i).is_some()),diff --git a/crates/engine/src/tests/menucmds.rs b/crates/engine/src/tests/menucmds.rs--- a/crates/engine/src/tests/menucmds.rs+++ b/crates/engine/src/tests/menucmds.rs@@ -645,6 +645,31 @@ fn expand_live_shape_and_text_in_one_undo_step() {     assert!(s.doc().unwrap().doc.node(t).is_some()); } +#[test]+fn expand_text_outlines_its_stroke_too() {+    let mut s = session();+    let t = text(&mut s, "Hi");+    sel(&mut s, &[t]);+    s.execute("paint.setStroke", &json!({"color": "#ff0000"})).unwrap();+    let info = s.execute("object.expand.info", &json!({})).unwrap();+    assert_eq!(info["stroke"], json!(true), "stroked type has a stroke to expand");+    let n = undo_len(&s);+    s.execute("object.expand", &json!({})).unwrap();+    assert_eq!(undo_len(&s), n + 1);+    let d = &s.doc().unwrap().doc;+    let (mut paths, mut stroked) = (0, 0);+    for id in &s.doc().unwrap().selection.objects {+        d.node(*id).unwrap().walk(&mut |c| {+            if matches!(c.kind, NodeKind::Path { .. } | NodeKind::Compound { .. }) {+                paths += 1;+                stroked += usize::from(!c.appearance.stroke_paint().is_none());+            }+        });+    }+    assert!(paths > 0);+    assert_eq!(stroked, 0, "every glyph's stroke became a filled outline ({paths} paths)");+}+ #[test] fn expand_nothing_errors() {     let mut s = session();