diff --git a/crates/xfa/src/layout/draw.rs b/crates/xfa/src/layout/draw.rs index f6520c1628..cc8ff5b670 100644 --- a/crates/xfa/src/layout/draw.rs +++ b/crates/xfa/src/layout/draw.rs @@ -97,8 +97,11 @@ impl Layouter<'_> { } let (w, h) = self.size_of(k, inner.w, &ctx, depth + 1); // A repeating subform here (a table in an area of a positioned page, - // say) gets its instances, as in a flowed one, one under another. - for instance in 0..self.instances(k, &ctx.som) { + // say) gets its instances, as in a flowed one, one under another, + // and the rows past them are reported as there. + let instances = self.instances(k, &ctx.som); + self.warn_truncated(k, &ctx.som, instances); + for instance in 0..instances { self.draw_node(k, Rect::new(inner.x, y, w, h), &ctx, depth + 1, sibs.at(i) + instance)?; y += h; } @@ -106,7 +109,11 @@ impl Layouter<'_> { } Layout::LrTb | Layout::RlTb => { // A repeating subform here (rows of fields under a heading) gets its - // instances, as in the other layouts. + // instances, as in the other layouts, and the rows past them are reported. + for k in s.children.iter().filter(|k| k.common().presence.occupies()) { + let instances = self.instances(k, &ctx.som); + self.warn_truncated(k, &ctx.som, instances); + } let (placed, _) = self.pack_instances(&s.children, inner.w, &ctx, depth, &ctx.som); for (i, instance, r) in placed { if let Some(k) = s.children.get(i) { diff --git a/crates/xfa/src/layout/flow.rs b/crates/xfa/src/layout/flow.rs index 36a2af9d3b..797ec6aa6c 100644 --- a/crates/xfa/src/layout/flow.rs +++ b/crates/xfa/src/layout/flow.rs @@ -295,7 +295,7 @@ impl Layouter<'_> { /// The data holds more instances of `node` than `laid_out`: say so, since calculations /// then see only those, and say why. (The template's own counts can't ask for more: the /// parser reads `initial` and `max` up to [`MAX_INSTANCES`].) - fn warn_truncated(&mut self, node: &Node, parent_som: &str, laid_out: usize) { + pub(super) fn warn_truncated(&mut self, node: &Node, parent_som: &str, laid_out: usize) { let Node::Subform(sf) = node else { return }; let from_data = match (&sf.common.name, self.data) { (Some(name), Some(d)) if sf.occur.max != Some(1) => d.count(&data_path(self.tpl, parent_som), name), diff --git a/crates/xfa/src/repeat_tests.rs b/crates/xfa/src/repeat_tests.rs index 810847c30b..bce2051838 100644 --- a/crates/xfa/src/repeat_tests.rs +++ b/crates/xfa/src/repeat_tests.rs @@ -100,3 +100,21 @@ fn an_initial_count_lays_out_whole_up_to_the_limit() { assert_eq!(crate::layout::instance_count(&unbounded, 0), MAX_INSTANCES); assert_eq!(crate::layout::instance_count(&unbounded, usize::MAX), MAX_INSTANCES); } + +#[test] +fn rows_cut_in_a_positioned_container_are_reported_too() { + // The list sits in a positioned subform, so it is drawn rather than flowed: its `tb`, + // `lr-tb` and `rl-tb` repeats are cut at the same bounds and must say so as a flowed one does. + for layout in ["tb", "lr-tb", "rl-tb"] { + let xml = rows_form("5", 60, false) + .replace(r#""#, r#""#) + .replace("", "") + .replace(r#""#, &format!(r#""#)) + .replace("
", "") + .replace("", "
"); + let form = layout_xml(&xml).unwrap(); + assert_eq!(values(&form), expected(5), "{layout}"); + let w = cut_warning(&form).unwrap_or_else(|| panic!("{layout}: the rows past occur max are reported: {:?}", form.warnings)); + assert!(w.contains("holds 60 rows") && w.contains("first 5"), "{layout}: {w}"); + } +}