Skip to content

fix(layout): keep-with-next page breaks, column flex fit-content, flex automatic minimum + page-break guide - #382

Merged
raroche merged 2 commits into
mainfrom
fix/corpus-visual-review-2026-09-30
Sep 30, 2026
Merged

raroche merged 2 commits into
mainfrom
fix/corpus-visual-review-2026-09-30

Conversation

@raroche

@raroche raroche commented Sep 30, 2026

Copy link
Copy Markdown
Owner

Fixes from the 2026-09-30 visual review of the NetPdf-tester corpus, plus a user guide for page breaks.

Fixes

Corpus doc Problem Fix
12-terms-and-conditions h2 { break-after: avoid } left alone at the page bottom Keep-with-next lookahead in BlockLayouter (all four block break sites + the mid-split entry). The greedy resolver never weighed the avoid flag.
11-course-completion-certificate Certificate ID not centered under the seal A non-stretched auto-width item in a column flex is now fit-content wide (it was placed as 0 wide; its background was culled).
06-travel-voucher "What's Included" lines wrapped with room to spare A flex item's own text re-applied its width: 50%, wrapping at 25%. The item-content pass no longer re-applies the item's width / min / max.
01-cruise-booking-confirmation Email value overlapped the "Email" label min-width: auto on row flex items is now the CSS Flexbox §4.5 automatic minimum (min-content), measured lazily only when a line shrinks. The value now overflows the row (browser behavior) instead of overlapping.
— overflow: hidden ignored The overflow shorthand now expands to overflow-x / overflow-y (AngleSharp.Css keeps it unexpanded; beta.144 did too). Needed for the §4.5 opt-out.

Keep-with-next rules: chains up to three avoids; the first block on a page never moves; dropped when the two can't share a fresh page (no wasted page). The "next piece" follows how the next sibling actually paginates (text block whole; split-able container chrome + first child; table / grid / flex ≈ two lines). AnonymousBlock children don't inherit the parent's break-*.

08-sales-report's "Highlights" is a div.section-title with no break rule — a browser leaves it at the page bottom too. The fix is in the HTML (.section-title { break-after: avoid; }), now documented.

Docs

  • New docs-site/page-breaks.md ("Controlling page breaks"): how NetPdf picks each break, forced / avoided breaks and their limits, recipes, troubleshooting. Added to the site TOC; linked from README (ships in the NuGet package) and the site compatibility page.
  • README page-break section: recommends h1…h6 { break-after: avoid }, explains the paragraph behavior.
  • docs/compatibility-matrix.md, docs/deferrals.md (fragmentation-control + flex entries), CHANGELOG [Unreleased].

Tests

  • 9 new W3C fragmentation cases (21/21 pass): keep-with-next top-level / nested / chain / break-before / legacy alias / kept first child of a section / split-able next section / fresh-page fallback / page-start guard.
  • KeepWithNextPaginationTests (13, real fonts): paragraph, list, table, wrapper, chain, limits, anonymous-block guard, and a 40-section document where no page ends with a heading.
  • CorpusVisualReviewTests (8, real fonts) + flex production / §9.7 unit tests + overflow shorthand tests.
  • Revert check: without the src/ changes, 21/27 flex + corpus tests, 7/13 keep-with-next tests and 6/9 new W3C cases fail; the rest are control cases.
  • Full suite green locally (UnitTests 8,700+, RealDocuments, W3C, RenderingCorpus, LayoutSnapshots, PaginationGolden, PdfValidation). No golden changed. Corpus page counts unchanged except terms-50page 50 → 51 (headings now kept with their text; no page ends with a heading).

Follow-ups logged separately

  • Measure pass uses page width for nested content (narrow boxes drawn short; can cause a one-line orphan).
  • Per-character font fallback (✔ renders as tofu on macOS).
  • PAGINATION-FORCED-OVERFLOW-001 fires on every page for wrapped documents.

🤖 Generated with Claude Code

…o minimum

Fixes from the 2026-09-30 visual review of the NetPdf-tester corpus.

- break-after: avoid / break-before: avoid now keep a block with its next
  sibling (12-terms-and-conditions heading left alone at the page bottom).
  The greedy resolver ignores the avoid cost, so BlockLayouter adds a
  keep-with-next lookahead at all four block break sites and the mid-split
  entry. Chains up to three; never moves the first block on a page; dropped
  when both can't share a fresh page.
- A non-stretched auto-width item in a column flex container is sized
  fit-content (11-course-completion-certificate ID was placed 0 wide).
- A flex item's own text no longer re-applies its percentage width
  (06-travel-voucher li width:50% wrapped at 25%).
- min-width:auto on row flex items is the CSS Flexbox 4.5 automatic
  minimum size (01-cruise email overlapped its label). Measured lazily,
  only when a line shrinks; shared by emission and the pre-measure.
- The overflow shorthand now expands to overflow-x / overflow-y.

Tests: 9 new fragmentation conformance cases, 13 keep-with-next facade
tests, flex unit and production tests, overflow shorthand tests.
Docs: new docs-site/page-breaks.md guide, README page-break section,
compatibility matrix, deferrals, CHANGELOG.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings September 30, 2026 16:36

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Flex sizing, forced-break precedence, shorthand validation, and documentation contain unresolved correctness issues.

Review effort: Balanced
Findings: 4 Medium severity · 1 Low severity

Open (5)
What changed in this PR

Improves pagination and flex sizing fidelity based on corpus visual regressions, with corresponding tests and documentation.

Changes:

  • Adds keep-with-next pagination for avoided sibling breaks.
  • Fixes flex sizing, automatic minimums, and overflow shorthand expansion.
  • Adds regression coverage and a page-break guide.
File Description
tests/​NetPdf.W3cConformance/​README.md Updates fragmentation results.
tests/​NetPdf.W3cConformance/​FragmentationCases.cs Adds keep-with-next cases.
tests/​NetPdf.UnitTests/​Rendering/​KeepWithNextPaginationTests.cs Tests pagination behavior.
tests/​NetPdf.UnitTests/​Rendering/​CorpusVisualReviewTests.cs Covers corpus regressions.
tests/​NetPdf.UnitTests/​Phase3/​FlexLayouterTests.cs Tests automatic flex minimums.
tests/​NetPdf.UnitTests/​Phase3/​FlexLayouterProductionTests.cs Tests production flex geometry.
tests/​NetPdf.UnitTests/​Css/​Parser/​CssParserAdapterPreprocessTests.cs Tests overflow expansion.
src/​NetPdf.Layout/​Layouters/​FlexLayouter.cs Implements flex sizing fixes.
src/​NetPdf.Layout/​Layouters/​BlockLayouter.cs Implements keep-with-next and width handling.
src/​NetPdf.Css/​Parser/​Preprocessing/​OverflowShorthandExpander.cs Expands overflow shorthand.
src/​NetPdf.Css/​Parser/​Preprocessing/​CssPreprocessor.cs Registers overflow recovery.
README.md Expands page-break guidance.
docs/​deferrals.md Updates implementation status.
docs/​compatibility-matrix.md Documents fragmentation support.
docs-site/​toc.yml Adds the guide to navigation.
docs-site/​page-breaks.md Adds the page-break guide.
docs-site/​compatibility.md Links the new guide.
CHANGELOG.md Records fixes and documentation.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/NetPdf.Css/Parser/Preprocessing/OverflowShorthandExpander.cs
Comment thread src/NetPdf.Layout/Layouters/BlockLayouter.cs
Comment thread src/NetPdf.Layout/Layouters/FlexLayouter.cs
Comment thread src/NetPdf.Layout/Layouters/FlexLayouter.cs Outdated
Comment thread docs/deferrals.md Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2eed7f69f8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/NetPdf.Layout/Layouters/BlockLayouter.cs
Comment thread src/NetPdf.Layout/Layouters/FlexLayouter.cs Outdated
Comment thread src/NetPdf.Layout/Layouters/FlexLayouter.cs Outdated
Comment thread src/NetPdf.Css/Parser/Preprocessing/OverflowShorthandExpander.cs Outdated
- overflow shorthand: a CSS-wide keyword is valid only as the whole value
  (`overflow: inherit hidden` is rejected).
- Flex automatic minimum: `overflow: clip` is not a scroll container, so it
  keeps the content-based minimum; only hidden / scroll / auto opt out.
- Column flex fit-content width is clamped by the item's min-/max-width,
  and the BlockLayouter column pre-measure uses the same fit-content width.
- A padded inline-only flex item's text was laid out at border box minus
  twice its chrome: the nested root-inline dispatch subtracts the item's
  border + padding itself (the grid / abspos contract), so flex now hands it
  the border box (ItemContentLayoutInlineSize), in emission and both
  pre-measures.
- A forced break at the same boundary overrides keep-with-next.
- deferrals.md: per-paragraph orphans/widows are not "missing".

Tests: overflow CSS-wide cases, clip keeps the minimum, fit-content
min/max clamp, padded fit-content and row items keep one line, forced break
overrides a keep (W3C 22/22). All fail without the fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@raroche
raroche merged commit 881533c into main Sep 30, 2026
13 of 14 checks passed
@raroche
raroche deleted the fix/corpus-visual-review-2026-09-30 branch September 30, 2026 17:30
@raroche raroche mentioned this pull request Sep 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants