mirror of
https://github.com/storytold/wordcraft.git
synced 2026-10-29 04:47:10 -06:00
#3907: review — a kept paragraph low in a continuous section moves to the next page; a page break before a stacked mark keeps the new page's bottom
CodeRabbit (local): keep-lines compared its height with the room below the mid-page section start, so a paragraph that fits on a new page split instead. It now compares with the next column, or the next page's body when this is the last column. A stacked mark whose page break before starts a page no longer gets the previous page's bottom back. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CX1hMKX28764Lrx5moxs1o
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
7757828295
commit
f2fe7654e9
@@ -42,7 +42,10 @@ pub(crate) fn place_para(ctx: &mut Ctx, pb: &mut PageBuilder, p: &Paragraph, blo
|
||||
let (y, prev, bottom, content_bottom, at) = (pb.y, pb.prev.clone(), pb.bottom, pb.content_bottom, (pb.pages.len(), pb.col));
|
||||
pb.bottom = f32::MAX / 4.0;
|
||||
place_para_in_flow(ctx, pb, p, block, body_top);
|
||||
pb.bottom = bottom;
|
||||
// A break before it starts a page with its own bottom.
|
||||
if pb.pages.len() == at.0 {
|
||||
pb.bottom = bottom;
|
||||
}
|
||||
if (pb.pages.len(), pb.col) == at && pb.y > bottom + 0.01 {
|
||||
// At the bottom: nothing more fits on the page, even a line smaller than the mark's.
|
||||
(pb.y, pb.prev, pb.content_bottom) = (bottom.max(y), prev, content_bottom);
|
||||
@@ -176,8 +179,10 @@ fn place_para_in_flow(ctx: &mut Ctx, pb: &mut PageBuilder, p: &Paragraph, block:
|
||||
if pl.rp.keep_lines || (pl.rp.keep_next && pb.y + height <= pb.bottom + 0.01) {
|
||||
let need = height + if pl.rp.keep_next { next_first_line(ctx, block, width, 0, &mut ctx.counters.clone()) } else { 0.0 };
|
||||
// (Against the whole column: balanced columns grow to hold it.)
|
||||
// Room in the next column, or on the next page when this is the last.
|
||||
let next_top = if pb.col + 1 < pb.cols.len() { pb.top } else { pb.page_top };
|
||||
// With the 0.01 pt of slack the other fit checks take.
|
||||
if pb.y + need > pb.bottom + 0.01 && !pb.fresh() && need <= pb.uncapped_bottom() - pb.top {
|
||||
if pb.y + need > pb.bottom + 0.01 && !pb.fresh() && need <= pb.uncapped_bottom() - next_top {
|
||||
pb.advance(block, body_top);
|
||||
pb.y += pl.rp.space_before.min(0.0);
|
||||
applied_before = pl.rp.space_before.min(0.0);
|
||||
|
||||
@@ -11681,6 +11681,34 @@ fn a_row_leaves_room_for_the_border_below_it() {
|
||||
}
|
||||
}
|
||||
|
||||
/// A kept-together paragraph starting a continuous section low on a page, with room there for
|
||||
/// one of its lines, moves whole to the next page, where it fits (#3907 review).
|
||||
#[test]
|
||||
fn kept_lines_at_a_low_continuous_section_move_to_the_next_page() {
|
||||
use wordcraft_doc::props::LineSpacing;
|
||||
use wordcraft_doc::section::{SectionProps, SectionStart};
|
||||
let fill = 53; // 53 lines of 12 pt leave one line of a 648 pt body
|
||||
let text = format!("{}{}", "x\n".repeat(fill), "word ".repeat(40));
|
||||
let mut d = Document::from_text(&text);
|
||||
for i in 0..=fill {
|
||||
let p = d.para_mut(StoryRef::Body, &Path::top(i)).unwrap();
|
||||
p.props.line_spacing = Some(LineSpacing::Exactly(12.0));
|
||||
p.props.space_before = Some(0.0);
|
||||
p.props.space_after = Some(0.0);
|
||||
}
|
||||
d.para_mut(StoryRef::Body, &Path::top(fill - 1)).unwrap().section =
|
||||
Some(Box::new(SectionProps { start: SectionStart::Continuous, ..Default::default() }));
|
||||
d.last_section.start = SectionStart::Continuous;
|
||||
let kept = d.para_mut(StoryRef::Body, &Path::top(fill)).unwrap();
|
||||
kept.props.keep_lines = Some(true);
|
||||
kept.props.widow_control = Some(false);
|
||||
let l = lay(&d);
|
||||
let last_x = l.caret(&Pos::body(fill - 1, 0)).unwrap();
|
||||
let first = l.caret(&Pos::body(fill, 0)).unwrap();
|
||||
assert_eq!(last_x.page, 0, "the filler fits on page 1: {last_x:?}");
|
||||
assert_eq!(first.page, 1, "kept paragraph moves whole: {first:?}");
|
||||
}
|
||||
|
||||
/// Sections starting continuously one after another still go onto new pages: a paragraph that
|
||||
/// doesn't fit below the text above it moves on rather than running off the page (#3907). A
|
||||
/// hundred one-line sections lay out like a hundred plain paragraphs.
|
||||
|
||||
Reference in New Issue
Block a user