diff --git a/crates/pptx/src/custgeom.rs b/crates/pptx/src/custgeom.rs index 0eeb37cd5..449654c80 100644 --- a/crates/pptx/src/custgeom.rs +++ b/crates/pptx/src/custgeom.rs @@ -156,6 +156,8 @@ pub fn read_cust_geom(cg: &El, w_emu: f64, h_emu: f64) -> Vec { let mut out = vec![]; let Some(pl) = cg.child("pathLst") else { return out }; let mut spaces: HashMap<(u64, u64), Guides> = HashMap::new(); + // The cap on cached spaces saves guide evaluation: a geometry without guides has none to save. + let guided = ["avLst", "gdLst"].iter().any(|n| cg.child(n).is_some_and(|l| l.elements().next().is_some())); for p in pl.children_named("path").take(1000) { let pw = p.f64("w").unwrap_or(0.0); let ph = p.f64("h").unwrap_or(0.0); @@ -164,7 +166,7 @@ pub fn read_cust_geom(cg: &El, w_emu: f64, h_emu: f64) -> Vec { // The guide lists are evaluated once per coordinate space, not once per path. let key = (gw.to_bits(), gh.to_bits()); if !spaces.contains_key(&key) { - if spaces.len() >= MAX_SPACES { + if guided && spaces.len() >= MAX_SPACES { continue; } let mut g = Guides::new(gw, gh); @@ -499,6 +501,14 @@ mod tests { assert!(out[MAX_SPACES].d.starts_with("M 5 1"), "{}", out[MAX_SPACES].d); } + #[test] + fn guide_free_geometries_are_not_capped_by_space() { + let paths: String = (1..=40).map(|i| format!(r#""#, 10 * i)).collect(); + let x = format!(r#"{paths}"#); + let d = parse(x.as_bytes()).unwrap(); + assert_eq!(read_cust_geom(&d.root, 1.0, 1.0).len(), 40); + } + #[test] fn write_then_read_path() { let p = CustomPath { w: 100.0, h: 50.0, d: "M 0 0 L 100 0 C 100 10 90 50 50 50 Q 0 50 0 0 Z".into(), fill: FillMode::Norm, stroke: true };