idml: one unusable CJK metric no longer refuses the whole file

Composite-font and mojikumi metrics were taken from the file with no
sanity check, and Document::check rejects a zero, NaN or infinite
relative_size / horizontal_scale / vertical_scale / baseline_shift — so
one attribute anywhere in the package (RelativeSize="0",
BaselineShift="NaN") failed the import with "invalid composite font
metrics" and left the file unopenable. Every neighbouring number in this
importer already filters; the metrics now do too and fall back to a
usable value.

Regression test: unusable_cjk_metrics_do_not_refuse_the_whole_file —
fails on main with Invalid("invalid composite font metrics: Rubies"),
passes with the fallback.
This commit is contained in:
midasmatterhorn
2026-10-15 15:42:25 +03:00
parent a930276fd7
commit 46a914dc4c
2 changed files with 35 additions and 7 deletions
+9 -7
View File
@@ -499,10 +499,12 @@ impl<'r> Importer<'r> {
characters: c.get("CustomCharacters").unwrap_or("").into(),
family: c.prop("AppliedFont").unwrap_or_default(),
style: c.get("FontStyle").unwrap_or("Regular").trim_start_matches("$ID/").into(),
relative_size: c.num("RelativeSize").unwrap_or(100.0) / 100.0,
horizontal_scale: c.num("HorizontalScale").unwrap_or(100.0) / 100.0,
vertical_scale: c.num("VerticalScale").unwrap_or(100.0) / 100.0,
baseline_shift: c.num("BaselineShift").unwrap_or(0.0) / 100.0,
// A metric `Document::check` refuses would make the whole file fail to
// open, so one that is unusable here falls back to full size / no shift.
relative_size: c.num("RelativeSize").filter(|v| v.is_finite() && *v > 0.0).unwrap_or(100.0) / 100.0,
horizontal_scale: c.num("HorizontalScale").filter(|v| v.is_finite() && *v > 0.0).unwrap_or(100.0) / 100.0,
vertical_scale: c.num("VerticalScale").filter(|v| v.is_finite() && *v > 0.0).unwrap_or(100.0) / 100.0,
baseline_shift: c.num("BaselineShift").filter(|v| v.is_finite()).unwrap_or(0.0) / 100.0,
scale_option: c.boolean("ScaleOption").unwrap_or(true),
})
.collect();
@@ -531,9 +533,9 @@ impl<'r> Importer<'r> {
target_class: r.num("TargetMojikumiClass").unwrap_or(0.0) as i16,
side_class: r.num("SideMojikumiClass").unwrap_or(0.0) as i16,
after: r.boolean("SideIsAfterTarget").unwrap_or(false),
minimum: r.num("Minimum").unwrap_or(0.0),
desired: r.num("Desired").unwrap_or(0.0),
maximum: r.num("Maximum").unwrap_or(0.0),
minimum: r.num("Minimum").filter(|v| v.is_finite()).unwrap_or(0.0),
desired: r.num("Desired").filter(|v| v.is_finite()).unwrap_or(0.0),
maximum: r.num("Maximum").filter(|v| v.is_finite()).unwrap_or(0.0),
priority: r.num("CompressionPriority").unwrap_or(0.0) as i16,
does_not_float: r.boolean("AkiDoesNotFloat").unwrap_or(false),
})
+26
View File
@@ -2443,6 +2443,32 @@ fn the_default_cjk_leading_model_applies_only_with_a_japanese_composer() {
assert_eq!(model("$ID/HL Single J"), Some(designcraft_doc::cjk::LeadingModel::AkiBelow));
}
/// A composite-font or mojikumi metric `Document::check` refuses (zero, NaN, infinity) must
/// not make the whole package fail to open: the entry falls back to a usable value instead.
#[test]
fn unusable_cjk_metrics_do_not_refuse_the_whole_file() {
let designmap = r#"<Document xmlns:idPkg="http://ns.adobe.com/AdobeInDesign/idml/1.0/packaging" Self="d">
<CompositeFont Self="cf" Name="Rubies">
<CompositeFontEntry Self="e1" Name="Dot" AppliedFont="Myriad Pro" RelativeSize="0"/>
<CompositeFontEntry Self="e2" Name="Bar" AppliedFont="Myriad Pro" BaselineShift="NaN"/>
</CompositeFont>
<MojikumiTable Self="mt" Name="Table">
<Properties><OverrideMojikumiAkiList>
<OverrideMojikumiAkiType Minimum="NaN" Desired="1" Maximum="2"/>
</OverrideMojikumiAkiList></Properties>
</MojikumiTable>
<idPkg:Spread src="Spreads/Spread_s.xml"/>
</Document>"#;
let spread = r#"<idPkg:Spread xmlns:idPkg="http://ns.adobe.com/AdobeInDesign/idml/1.0/packaging">
<Spread Self="s"><Page Self="p" GeometricBounds="0 0 100 100" ItemTransform="1 0 0 1 0 0"/></Spread>
</idPkg:Spread>"#;
let d = import_idml(&zip_files(&[("designmap.xml", &designmap), ("Spreads/Spread_s.xml", &spread)])).unwrap();
let entries = &d.styles.composite_fonts[0].entries;
assert_eq!(entries[0].relative_size, 1.0, "an unusable relative size falls back to full size");
assert_eq!(entries[1].baseline_shift, 0.0, "an unusable shift falls back to none");
assert_eq!(d.styles.mojikumi_tables[0].overrides[0].minimum, 0.0);
}
mod liquid_page_rules {
use super::*;
use designcraft_doc::LiquidRule as R;