mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-24 10:08:00 -06:00
M12: a flowed subform's repeated top margins give way to a child that fits a fresh content area only without them
This commit is contained in:
@@ -649,15 +649,17 @@ impl Layouter<'_> {
|
||||
if self.frames.is_empty() || !placed || y + h <= rect.bottom() + 0.01 || h > rect.h + 0.01 {
|
||||
return Ok(());
|
||||
}
|
||||
self.break_frames()
|
||||
self.break_frames(h)
|
||||
}
|
||||
|
||||
/// Break the flowed subforms being laid out ([`Self::frames`]) across content areas, as
|
||||
/// another viewer breaks such a section on a synthetic form: each one's part here ends after
|
||||
/// its content and its bottom margin (the innermost first, each inside the next), the flow
|
||||
/// moves to the next content area, and each starts a new part there after its top margin
|
||||
/// (the outermost first).
|
||||
fn break_frames(&mut self) -> Result<(), XfaError> {
|
||||
/// (the outermost first). The top margins take only what the `need` points of the child that
|
||||
/// comes next leave of the new area: a child that fits a fresh area but not after the margins
|
||||
/// would otherwise run past its bottom, out of its border.
|
||||
fn break_frames(&mut self, need: f64) -> Result<(), XfaError> {
|
||||
let (rect, mut y, _) = self.cursor();
|
||||
let page = self.pages.len().saturating_sub(1);
|
||||
let here: Vec<bool> = self.frames.iter().map(|f| self.on_area(&f.part)).collect();
|
||||
@@ -671,11 +673,15 @@ impl Layouter<'_> {
|
||||
}
|
||||
}
|
||||
self.next_area()?;
|
||||
let (rect, y, _) = self.cursor();
|
||||
let mut room = (rect.bottom() - y - need).max(0.0);
|
||||
for i in 0..self.frames.len() {
|
||||
let Some(mark) = self.flow_mark() else { break };
|
||||
let Some(f) = self.frames.get_mut(i) else { break };
|
||||
f.part = mark;
|
||||
let top = f.margin.top;
|
||||
// `max` before `min`: a NaN margin counts as none and leaves `room` a number.
|
||||
let top = f.margin.top.max(0.0).min(room);
|
||||
room = (room - top).max(0.0);
|
||||
self.advance(top);
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -2117,6 +2117,16 @@ fn a_flowed_subform_is_drawn_with_its_border_under_its_content() {
|
||||
assert!(form.pages.len() >= 2, "the long text runs onto another page");
|
||||
assert!(form.pages.iter().all(|p| !p.items.iter().any(|i| matches!(i, Item::Fill { .. }))), "no fill drawn");
|
||||
assert_eq!(form.warnings.iter().filter(|w| w.contains("bordered section")).count(), 1, "{:?}", form.warnings);
|
||||
// A field that fits a fresh page (720pt) but not after the 7.2pt top margin: the margin
|
||||
// gives way, so the field ends at the content area's bottom, inside the second part.
|
||||
let tall = r#"<field name="tall" w="3in" h="715pt"><ui><textEdit/></ui></field>"#;
|
||||
let form = lay(&boxed(&(field("a") + tall)));
|
||||
assert_eq!(form.pages.len(), 2);
|
||||
let tall = form.pages[1].items.iter().find_map(|i| if let Item::Widget(w) = i { (w.name == "tall").then_some(w.rect) } else { None }).unwrap();
|
||||
assert!(tall.bottom() <= 756.01, "the field stays in the content area: {tall:?}");
|
||||
let part = form.pages[1].items.iter().find_map(|i| if let Item::Fill { rect, .. } = i { Some(*rect) } else { None }).expect("the second part");
|
||||
assert!(part.y <= tall.y + 0.01 && part.bottom() >= tall.bottom() - 0.01, "the border holds the field: {part:?} {tall:?}");
|
||||
assert!(form.warnings.is_empty(), "{:?}", form.warnings);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user