Repository navigation
Conversation
… bottom (storytold#6593) The look-ahead for keep with next counted only eight kept paragraphs, so the cut-short chain always fit on a fresh page and moved there from about ten lines above the bottom. A paragraph now stays when the whole chain, measured from the paragraph that starts it, cannot fit on one page. A chain also ends at a paragraph with a page break before it, so a kept paragraph just above one no longer moves alone to a blank page.
|
No actionable comments were generated in the recent review. Walkthrough
Merge Risk:
|
Fixes #6593
Root cause
next_first_line(crates/layout/src/flow.rs, called fromFlow::keep_together,flow.rs:348on main) measures the room a keep-with-next paragraph needs: its own height plus the paragraphs it is kept with. It recursed onlydepth < 8kept paragraphs deep and then counted the next one as an unkept paragraph. In a chain of 69 kept one-line paragraphs, every paragraph therefore "needed" about ten lines. Once those ten lines no longer fitted, the cut-short chain did fit on an empty page (need <= pb.next_room(..)), so the paragraph moved there. The page broke about ten lines short of the bottom, and the rest of the chain moved to the next page (case 1). It is the same in case 2: item 31 sees items 32 to 40 plus the 500 pt picture, which fits on a new page, so the items move with the picture.The blank page (third case in the comments) comes from the same look-ahead. It counted the heading after the empty kept paragraph and the items after the heading. The heading has
w:pageBreakBefore, so it starts a new page anyway. Moving the empty paragraph left it alone on a blank page.Fix
In
crates/layout/src/flow.rs:next_first_lineis now a bounded loop (chain_room) instead of recursion. It keeps the same eight-paragraph look-ahead (MAX_KEPT_AHEAD), so chains that fit behave as before.keep_together: before moving a keep-with-next paragraph,chain_overflowswalks back to the paragraph that starts the chain. The walk stops at a paragraph whose predecessor is not kept, or at a page break before. From there it measures the whole chain against the room on a fresh page. If the chain cannot fit on one page, keep with next gives way and the chain breaks at the page bottom. Only keep lines together can still move that paragraph.MAX_CHAIN); a longer chain is treated as too long for one page. Paragraph layouts come from the existing look-ahead cache (Ctx::para_ahead).docs/layout-parity.md: status line, the keep-with-next row and a revision-history row.Tests
New tests in
crates/layout/src/tests.rs:keep_with_next_chain_longer_than_the_page_breaks_at_the_bottom(case 1): the page of every paragraph matches the same document without keep with next.keep_with_next_chain_before_a_tall_picture_keeps_its_list_on_the_page(case 2 and the blank-page case): heading and items stay together, the 400 × 500 pt picture goes to the next page alone. With 36 body lines, the empty kept paragraph stays on page 1.The test document's default font fits 40 lines on a page, so case 2 uses 30 items instead of 40 to keep heading plus items on one page.
Without the fix (
flow.rsfromupstream/main, tests in place):With the fix:
test result: ok. 3 passed(thekeep_with_next_chainfilter, including the existing #966 chain test).Checks run
cargo test -j 4 -p wordcraft-layout: 716 passed, 3 failed:auto_hyphenation_breaks_long_words,fragmented_hidden_text_lays_out_like_the_visible_textandhyphenation_and_proofing_follow_each_runs_language. All three need hyphenation patterns fromCRAFT_I18N_DIR, which this machine does not have. They are hyphenation tests; this change does not touch hyphenation.cargo test -j 4 -p wordcraft-engine --no-fail-fast: everything passes exceptcmd::packs::tests::swiss_german_and_portugal_portuguese_keep_their_languages_rules, which also needs German hyphenation patterns.cargo clippy -j 4 -p wordcraft-layout --all-targets -- -D warnings: clean.cargo fmt -p wordcraft-layout --check: clean.Not run
cargo xtask ci(wasm, assets, layers) and the other crates' tests. CI covers them.Summary by CodeRabbit