mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-10 13:01:29 +00:00
M12: report rows cut from repeats in positioned containers
A repeating subform drawn inside a positioned container (a tb, lr-tb or rl-tb subform placed on a positioned page) was cut at its occur max or MAX_INSTANCES like a flowed one, but the rows past the cut were dropped without the layout warning that flowed subforms and tables give. Both drawing paths now call warn_truncated, so the README, the MAX_INSTANCES doc and the form.xfa-data note are true for these layouts too (XFA 3.3, "The occur element", p. 786). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0175FWj4xFhMhSH3UpMU8DSC
This commit is contained in:
1 parent
afdb368051
commit
4d467e1ba6
3 files changed
+29
-4
No files matched your search
@@ -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) {
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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#"<subform name="form" layout="tb">"#, r#"<subform name="form" layout="tb"><subform name="page" w="540pt" h="720pt">"#)
|
||||
.replace("</subform></template>", "</subform></subform></template>")
|
||||
.replace(r#"<subform name="list" layout="tb">"#, &format!(r#"<subform name="list" x="0pt" y="0pt" w="540pt" layout="{layout}">"#))
|
||||
.replace("<xfa:data><form><list>", "<xfa:data><form><page><list>")
|
||||
.replace("</list></form></xfa:data>", "</list></page></form></xfa:data>");
|
||||
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}");
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user