Type: a text.setStyle stroke gives unstroked characters 1 pt

A stroke color given without strokeWidth left characters at weight 0, so
nothing was drawn. As paint.setStroke does, a painted stroke now gives a
run with no weight 1 pt, for the characters and for the label styles a
graph keeps; an explicit strokeWidth still sets the weight.
This commit is contained in:
dotCooCoo
2026-11-03 16:03:38 +07:00
committed by bflatastic
parent b1dc20b811
commit 58e6ce9f02
4 changed files with 39 additions and 2 deletions
+12
View File
@@ -2588,6 +2588,18 @@ fn formatting_the_whole_graphs_text_survives_it_being_drawn_again() {
assert_eq!(spec(&s, id).label_styles, vectorcraft_doc::LabelStyles::default());
}
/// A stroke given to all of a graph's text without a weight is kept at 1 pt, as `paint.setStroke` keeps it.
#[test]
fn a_stroke_given_to_the_whole_graphs_text_is_kept_at_1_pt() {
let mut s = Session::new();
s.execute("file.new", &json!({"width": 800, "height": 800})).unwrap();
let id = graph(&mut s, "column");
s.execute("select.set", &json!({"ids": [id.0]})).unwrap();
s.execute("text.setStyle", &json!({"stroke": "#ff0000"})).unwrap();
let legend = spec(&s, id).label_styles.legend.unwrap();
assert_eq!((legend.stroke.color().map(|c| c.to_hex()), legend.stroke_width), (Some("#ff0000".into()), 1.0));
}
#[test]
fn formatting_one_label_keeps_that_kind_of_label() {
let mut s = Session::new();
+8 -1
View File
@@ -123,7 +123,7 @@ pub fn specs() -> Vec<CommandSpec> {
"Character",
[],
None,
"{ids?|id?, font?, style? (font alone: the style is kept when the new family has it, else its closest), size?: pt, leading?: pt|\"auto\", tracking?: 1/1000 em, justify?: \"auto\" (the start of each paragraph's direction)|\"left\"|\"center\"|\"right\"|\"justifyAll\", fill?: colour|\"none\", stroke?: colour|\"none\", keepModel?: bool (fill and stroke, as paint.setFill), strokeWidth?: pt (the character stroke's weight, in document points as stroke.set), features?: [\"dlig\", \"-liga\", …] OpenType, featureChanges?: [\"tnum\", \"-onum\", …] (OpenType features turned on, or with - off, on top of each character's own; its other features are kept), start?: byte, end?: byte} (size/leading are document points after object scaling; with a range: the character attributes style that range and justify the paragraphs it touches; without: all the text) → {ids, overflow?: [id…] (area type and type on a path whose text no longer fits; left out when all fits), warning?: text (the font or style set isn't available: its type is drawn in the fallback font or the family's closest style)}",
"{ids?|id?, font?, style? (font alone: the style is kept when the new family has it, else its closest), size?: pt, leading?: pt|\"auto\", tracking?: 1/1000 em, justify?: \"auto\" (the start of each paragraph's direction)|\"left\"|\"center\"|\"right\"|\"justifyAll\", fill?: colour|\"none\", stroke?: colour|\"none\" (characters without a stroke weight get 1 pt), keepModel?: bool (fill and stroke, as paint.setFill), strokeWidth?: pt (the character stroke's weight, in document points as stroke.set), features?: [\"dlig\", \"-liga\", …] OpenType, featureChanges?: [\"tnum\", \"-onum\", …] (OpenType features turned on, or with - off, on top of each character's own; its other features are kept), start?: byte, end?: byte} (size/leading are document points after object scaling; with a range: the character attributes style that range and justify the paragraphs it touches; without: all the text) → {ids, overflow?: [id…] (area type and type on a path whose text no longer fits; left out when all fits), warning?: text (the font or style set isn't available: its type is drawn in the fallback font or the family's closest style)}",
has_doc,
set_style
),
@@ -858,6 +858,10 @@ fn set_style(s: &mut Session, p: &Value) -> Result<Value> {
st.fill = f.clone();
}
if let Some(f) = &stroke {
// A painted stroke on a run without a weight gets 1 pt, as with paint.setStroke.
if !f.is_none() {
super::gradient::run_stroke_weight(st);
}
st.stroke = f.clone();
}
if !stroke_weight.is_empty() {
@@ -920,6 +924,9 @@ fn set_style(s: &mut Session, p: &Value) -> Result<Value> {
st.fill = f.clone();
}
if let Some(f) = &stroke {
if !f.is_none() {
super::gradient::run_stroke_weight(st);
}
st.stroke = f.clone();
}
if !stroke_weight.is_empty() {
+17
View File
@@ -175,6 +175,23 @@ fn set_style_sets_the_character_stroke() {
assert!(obj(&s, id).runs.iter().all(|r| (r.style.stroke_width - 1.0).abs() < 1e-9), "{:?}", paints(&s));
}
/// `text.setStyle {stroke}` without `strokeWidth` gives type with no stroke weight 1 pt, as
/// `paint.setStroke` does, and keeps a weight the type already has.
#[test]
fn set_style_stroke_without_a_weight_draws_1_pt() {
use vectorcraft_color::Color;
let mut s = session();
let id = text(&mut s, "Hello");
assert_eq!(obj(&s, id).runs[0].style.stroke_width, 0.0);
s.execute("text.setStyle", &json!({"ids": [id.0], "stroke": "#ff0000"})).unwrap();
let st = &obj(&s, id).runs[0].style;
assert_eq!((st.stroke.color(), st.stroke_width), (Some(Color::rgb8(255, 0, 0)), 1.0));
assert!(st.has_stroke());
s.execute("text.setStyle", &json!({"ids": [id.0], "strokeWidth": 3})).unwrap();
s.execute("text.setStyle", &json!({"ids": [id.0], "stroke": "#0000ff"})).unwrap();
assert_eq!(obj(&s, id).runs[0].style.stroke_width, 3.0, "an existing weight is kept");
}
#[test]
fn optical_command_manual_pair_undo_redo_and_native_reopen() {
let mut s = session();
+2 -1
View File
@@ -2360,7 +2360,8 @@ characters as its place relative to the Characters row says. To stroke
some characters, use `text.setRangeStyle {id, start, end, strokeOptions: {weight?, cap?, join?, miterLimit?, align?,
dash?, dashOffset?, alignDashes?}}`. `text.setStyle {ids?, stroke?, strokeWidth?, start?, end?}` sets the stroke color
and weight of the characters of each object given (without `start` and `end`: all of its text), with its other keys in
one undo step; `strokeWidth` is in document points, as `stroke.set` gives the weight of scaled type.
one undo step; `strokeWidth` is in document points, as `stroke.set` gives the weight of scaled type. A `stroke` color
without `strokeWidth` gives characters that have no stroke weight 1 pt, as `paint.setStroke` does.
`align: "inside"|"outside"` keeps the characters' stroke on that side of the
glyph outlines, drawn at twice the weight and clipped, while the type stays editable (beyond Illustrator); SVG export
writes the text live and that stroke as glyph outlines over it. `inspect_document` reports each object's stroke as `strokeOptions` (type: its first