Text styles: loading skips a style whose sizes or scales are out of range

A loaded character style kept a size, scale, leading, shift or stroke width that
charStyle.new refuses. Such a style is now skipped and listed in the reply's skipped names.
This commit is contained in:
dotCooCoo
2026-11-08 12:59:33 +07:00
committed by bflatastic
parent dfb507b7b7
commit 8f14e2f0ec
3 changed files with 29 additions and 6 deletions
+9 -4
View File
@@ -125,7 +125,7 @@ macro_rules! style_cmds {
}
/// The params of `charStyle.load`, `paraStyle.load` and `textStyle.loadAll`.
const LOAD_PARAMS: &str = "{path? | data?: file text | dataBase64?, name?: file name (default: the path's)} copy the styles of this kind (textStyle.loadAll: character and paragraph styles) from a document VectorCraft opens (see document.formats) into this one, after its own, in one undo step, with the swatches and patterns they paint with and the styles of either kind that type in those patterns is set in, as Paste brings those of pasted type (a global or spot color whose name this document gives another color is this document's). A style that is the same as the style here of its name, or of its name with a number (`Body 2`), isn't added again; any other is added under a free name (`Body 2`). The file's Normal styles aren't loaded, and a style whose attributes don't read, or whose name is empty, is skipped → {added: [names here], existing: [names already here], skipped: [names]} (textStyle.loadAll: {charStyles: {…}, paraStyles: {…}})";
const LOAD_PARAMS: &str = "{path? | data?: file text | dataBase64?, name?: file name (default: the path's)} copy the styles of this kind (textStyle.loadAll: character and paragraph styles) from a document VectorCraft opens (see document.formats) into this one, after its own, in one undo step, with the swatches and patterns they paint with and the styles of either kind that type in those patterns is set in, as Paste brings those of pasted type (a global or spot color whose name this document gives another color is this document's). A style that is the same as the style here of its name, or of its name with a number (`Body 2`), isn't added again; any other is added under a free name (`Body 2`). The file's Normal styles aren't loaded, and a style whose attributes don't read or are out of the range charStyle.new takes, or whose name is empty, is skipped → {added: [names here], existing: [names already here], skipped: [names]} (textStyle.loadAll: {charStyles: {…}, paraStyles: {…}})";
pub fn specs() -> Vec<CommandSpec> {
let mut v = style_cmds!(
@@ -913,16 +913,21 @@ fn unused(s: &mut Session, kind: Kind) -> Result<Value> {
}
/// The styles of `kind` in `src` that load, with their source names so that art in the file keeps
/// referring to them: not the Normal style, and not one whose attributes don't read or whose name is empty,
/// which are skipped. → (the styles, the names in `src` of those skipped)
/// referring to them: not the Normal style, and not one whose attributes don't read, whose sizes,
/// scales, leading, shifts or stroke width are out of the range `charStyle.new` takes, or whose name
/// is empty, which are skipped. → (the styles, the names in `src` of those skipped)
fn loadable(src: &Document, kind: Kind) -> (Vec<TextStyleDef>, Vec<String>) {
const RANGED: [&str; 8] = ["size", "h_scale", "v_scale", "leading", "baseline_shift", "tcyUpDown", "tcyLeftRight", "stroke_width"];
let (mut defs, mut skipped) = (vec![], vec![]);
for def in kind.defs(src) {
let name = def.name.as_str();
if name.trim() == kind.normal() {
continue;
}
match attrs_param(src, &json!({ "attrs": def.attrs }), kind, "load", Some(&def.attrs)).ok().flatten().filter(|_| !name.trim().is_empty()) {
// Paints, features and language are taken as the file stores them; the ranged values are checked.
let mut kept = def.attrs.clone();
kept.retain(|k, _| !RANGED.contains(&k.as_str()));
match attrs_param(src, &json!({ "attrs": def.attrs }), kind, "load", Some(&kept)).ok().flatten().filter(|_| !name.trim().is_empty()) {
Some(attrs) => defs.push(TextStyleDef { name: name.to_string(), attrs }),
None => skipped.push(def.name.clone()),
}
+18
View File
@@ -819,6 +819,24 @@ fn load_all_styles_loads_both_kinds_in_one_step() {
assert_eq!(s.doc().unwrap().doc, before);
}
/// A loaded character style whose size, scale, leading, shift or stroke width is out of the range
/// `charStyle.new` takes is skipped.
#[test]
fn loaded_styles_out_of_range_are_skipped() {
let (mut s, _) = session_with_text("Title");
let file = [
("Huge", json!({"size": 2000.0})),
("Flat", json!({"h_scale": 0.5})),
("Shifted", json!({"baseline_shift": 5000.0})),
("Thick", json!({"stroke_width": -2.0})),
("Fine", json!({"size": 12.0, "h_scale": 50.0})),
];
let data = styles_file(&file, &[]);
let r = s.execute("charStyle.load", &json!({"dataBase64": data, "name": "Other.vectorcraft"})).unwrap();
assert_eq!(r, json!({"added": ["Fine"], "existing": [], "skipped": ["Huge", "Flat", "Shifted", "Thick"]}));
assert_eq!(listed(&mut s, "charStyle"), [NORMAL_CHAR, "Fine"]);
}
/// A loaded style brings the pattern it paints with, renamed when the document has another pattern
/// of that name, as Paste brings it; a global color whose name the document gives another color
/// is the document's.
+2 -2
View File
@@ -5939,8 +5939,8 @@ in, come along as Paste brings those of pasted type; a global or spot color whos
is the document's. A loaded style that is the same as the style of
its name, or of its name with a number (`Body 2`), is not added again; any other is added under a free name. The
document's styles and the type that uses them keep their attributes, and the file's Normal styles are not loaded. The
reply lists the names `added`, `existing` and `skipped` (a style whose attributes do not read, or whose name is
empty); `textStyle.loadAll` replies `{charStyles, paraStyles}`. A Return the Type tool types (or `text.editRange`
reply lists the names `added`, `existing` and `skipped` (a style whose attributes do not read or are out of the range
`charStyle.new` takes, or whose name is empty); `textStyle.loadAll` replies `{charStyles, paraStyles}`. A Return the Type tool types (or `text.editRange`
inserting `\n`) continues the style of the paragraph it splits; deleting a break keeps the first paragraph's style;
`text.setText` gives every paragraph the first one's attributes. Threaded text keeps each paragraph's attributes as
the story re-flows (a paragraph split between frames has them in both).