From 07e89ad30ab97d7e480033f320a5a7964f5fbed1 Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Sat, 14 Nov 2026 05:51:17 +0000 Subject: [PATCH] fix(idml): preserve transforms and text variable values --- crates/idml/src/model/document.rs | 5 +++-- crates/idml/src/value.rs | 10 +++++++++- crates/idml/tests/model.rs | 14 ++++++++++++++ crates/idml/tests/value.rs | 2 ++ 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/crates/idml/src/model/document.rs b/crates/idml/src/model/document.rs index 3937a4501..830b95a3f 100644 --- a/crates/idml/src/model/document.rs +++ b/crates/idml/src/model/document.rs @@ -346,11 +346,12 @@ impl TextVariableValues { settings: preference.map(|child| child.attrs.clone()).unwrap_or_default(), }, }; + let text = |key: &str| preference.and_then(|child| child.attr(key)).or_else(|| values.get(key)).unwrap_or("").to_owned(); Self { self_id: values.self_id().map(str::to_owned), name: values.get("Name").unwrap_or("").to_owned(), - before: values.get("TextBefore").unwrap_or("").to_owned(), - after: values.get("TextAfter").unwrap_or("").to_owned(), + before: text("TextBefore"), + after: text("TextAfter"), kind, } } diff --git a/crates/idml/src/value.rs b/crates/idml/src/value.rs index cb54644db..ab09cbaec 100644 --- a/crates/idml/src/value.rs +++ b/crates/idml/src/value.rs @@ -30,7 +30,15 @@ pub fn nums(s: &str) -> Vec { /// An `ItemTransform`: the six coefficients `a b c d tx ty`, or `None` when the value is not /// six finite numbers. pub fn matrix(s: &str) -> Option<[f64; 6]> { - <[f64; 6]>::try_from(nums(s)).ok() + let mut tokens = s.split_whitespace(); + let mut matrix = [0.0_f64; 6]; + for value in &mut matrix { + *value = tokens.next()?.parse().ok()?; + if !value.is_finite() { + return None; + } + } + tokens.next().is_none().then_some(matrix) } /// A transform as an `ItemTransform` value. diff --git a/crates/idml/tests/model.rs b/crates/idml/tests/model.rs index 98c94df1a..075a77c82 100644 --- a/crates/idml/tests/model.rs +++ b/crates/idml/tests/model.rs @@ -266,3 +266,17 @@ fn deeply_nested_groups_are_read_and_walked() { let again = Spread::from_el(&parse_part(&part_xml(&s.to_el())).unwrap()); assert_eq!(again, s); } + +#[test] +fn text_variable_decoration_uses_preference_and_falls_back_to_legacy_root_values() { + let preferred = parse_part( + br#""#, + ) + .unwrap(); + let variable = craft_idml::model::TextVariableValues::from_el(&preferred); + assert_eq!((variable.before.as_str(), variable.after.as_str()), ("of ", " pages")); + + let legacy = parse_part(br#""#).unwrap(); + let variable = craft_idml::model::TextVariableValues::from_el(&legacy); + assert_eq!((variable.before.as_str(), variable.after.as_str()), ("of ", " pages")); +} diff --git a/crates/idml/tests/value.rs b/crates/idml/tests/value.rs index 75ef55a08..236c13286 100644 --- a/crates/idml/tests/value.rs +++ b/crates/idml/tests/value.rs @@ -25,6 +25,8 @@ fn transforms_and_points() { assert_eq!(matrix("1 0 0 1 36"), None); assert_eq!(matrix("1 0 0 1 36 72 9"), None); assert_eq!(matrix("1 0 0 1 NaN 0"), None); + assert_eq!(matrix("0 1 x -1 0 0 5"), None, "invalid coefficients cannot shift later values"); + assert_eq!(matrix("1e1000 0 0 1 0 0"), None, "non-finite coefficients are rejected"); assert_eq!(matrix_str(&[1.0, 0.0, 0.0, 1.0, 36.0, -72.5]), "1 0 0 1 36 -72.5"); assert_eq!(point("3 4"), Some((3.0, 4.0))); assert_eq!(point("3 4 5"), Some((3.0, 4.0)));