Character Styles: Style Options leaves Figure unset for figure tags no menu entry matches

A style whose features turn on pnum or lnum alone, or pair a figure tag with
one the shown entry turns off (onum with lnum, tnum with pnum), showed a Figure
entry that does not match its tags. Choosing that entry then left the field
unchanged, so the tags could not be cleared. Figure now opens unset for these
lists, and choosing Default Figure writes -tnum, -onum, -pnum and -lnum.
This commit is contained in:
dotCooCoo
2026-11-03 16:03:39 +07:00
committed by bflatastic
parent 84e344c475
commit c79fd5c132
@@ -189,7 +189,8 @@ fn bare(tag: &str) -> &str {
}
/// The OpenType Features fields for a style's `features`: each control is unset unless the list
/// names one of its tags, on or off.
/// names one of its tags, on or off. Figure is also unset when the list turns one of its tags on
/// or off against every Figure menu entry, for example `pnum` alone.
fn opentype_fields(features: Option<&Value>) -> Map<String, Value> {
let tags: Vec<&str> = features.and_then(Value::as_array).into_iter().flatten().filter_map(Value::as_str).collect();
let names = |set: &[&str]| tags.iter().any(|t| set.contains(&bare(t)));
@@ -199,7 +200,11 @@ fn opentype_fields(features: Option<&Value>) -> Map<String, Value> {
let last = tags.iter().rev().find(|t| bare(t) == *tag);
fields.insert((*field).into(), last.map_or(Value::Null, |t| json!(!t.starts_with('-'))));
}
let figure = names(&FIGURE_TAGS).then(|| FIGURE_VALUES.get(crate::panels::opentype::figure(&f))).flatten();
let last_on = |tag: &str| tags.iter().rev().find(|t| bare(t) == tag).map(|t| !t.starts_with('-'));
let figure = names(&FIGURE_TAGS)
.then(|| FIGURE_VALUES.get(crate::panels::opentype::figure(&f)))
.flatten()
.filter(|v| figure_tags(v).iter().all(|t| last_on(bare(t)).is_none_or(|on| on != t.starts_with('-'))));
fields.insert("ot_figure".into(), figure.map_or(Value::Null, |v| json!(v)));
let position =
names(&crate::panels::opentype::POSITION_TAGS).then(|| crate::panels::opentype::position(&f).and_then(|i| POSITION_VALUES.get(i))).flatten();
@@ -1310,6 +1315,21 @@ mod tests {
assert_eq!(edited_attrs(&d).unwrap(), Map::new());
}
#[test]
fn figure_tags_no_menu_entry_matches_leave_the_figure_unset() {
for features in [json!(["pnum"]), json!(["lnum"]), json!(["onum", "lnum"]), json!(["tnum", "pnum"])] {
let mut d = dialog_for(json!({ "features": features }));
assert!(d.fields["ot_figure"].is_null(), "{features}");
assert_eq!(edited_attrs(&d).unwrap(), attrs(json!({ "features": features })), "{features}");
d.fields.insert("ot_figure".into(), json!("default"));
assert_eq!(edited_attrs(&d).unwrap()["features"], json!(["-tnum", "-onum", "-pnum", "-lnum"]), "{features}");
}
for (features, shown) in [(json!(["tnum"]), "tabularLining"), (json!(["-pnum"]), "default"), (json!(["pnum", "lnum"]), "proportionalLining")]
{
assert_eq!(dialog_for(json!({ "features": features })).str("ot_figure"), shown, "{features}");
}
}
#[test]
fn color_tint_and_weight_outside_their_limits_are_errors() {
let linked = json!({"type": "solid", "color": {"model": "gray", "k": 0.5}, "swatch": "Ink"});