Skip to content

Layout: in a table cell a column break is ignored like a page break, and a list paragraph that opens with either shows no label (#6610) - #6611

Open
Menonro wants to merge 2 commits into
storytold:mainfrom
Menonro:fix/breaks-and-list-number-in-cells
Open

Menonro wants to merge 2 commits into
storytold:mainfrom
Menonro:fix/breaks-and-list-number-in-cells

Conversation

@Menonro

@Menonro Menonro commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #6610.

In a table cell Word ignores page breaks and column breaks: the text goes on in the same line. WordCraft ignored the page break but ended the line at a column break. And from Word 2013's layout on, a list paragraph in a cell that opens with such a break is shown by Word without its number or bullet, on a line no taller for it; WordCraft drew the label.

The cases of #6610's files (Word for Windows 16.0.20625; 8 pt text, 10 pt numbers): what the case's line shows, with each piece's left edge in pt, and its baseline below the baseline of the row before.

case Word main This branch
R1 a numbered paragraph 2. at 62, HEADING at 77; 11.5 the same; 11.6 the same; 11.6
R2 opens with a page break HEADING at 77; 9.8 2. at 62, HEADING at 77; 11.5 HEADING at 77; 9.7
R3 opens with a column break HEADING at 77; 9.7 2. alone, HEADING a line lower; 20.8 HEADING at 77; 9.7
R4 a space, then a page break 2. at 62, HEADING at 79; 11.5 the same; 11.6 the same; 11.6
R5 a bullet, opens with a page break HEADING at 77; 9.7 - at 62, HEADING at 77; 11.6 HEADING at 77; 9.7
R6 centred, opens with a page break HEADING at 287; 9.7 2. at 272, HEADING at 287; 11.6 HEADING at 287; 9.7
R7 centred 2. at 272, HEADING at 287; 11.5 the same; 11.6 the same; 11.6
R8 a column break in plain text BEFORE AFTER on one line BEFORE, AFTER a line lower BEFORE AFTER on one line
R9 a page break in plain text BEFORE AFTER on one line the same the same
mode 14, R2 2. at 57, HEADING at 71; 11.7 the same; 11.5 the same; 11.5
mode 14, R3 2. at 57, HEADING at 71; 11.6 2. alone, HEADING a line lower 2. at 57, HEADING at 71; 11.6

The item after the case's paragraph keeps its number in all of them.

What changes, in crates/layout/src/para/paragraph.rs:

  • Shaper::special: a column break in a cell becomes a marker, as a page break already did there. It keeps its place in the text and no longer ends the line.
  • list_label: in a cell, in compatibility mode 15 and later, a paragraph whose text starts with a page or column break gets a label that is its room alone: the width of the shaped label, no glyphs, no text and no ascent. So nothing is drawn, the first line's height comes from its text, and place_label still starts the text where it would after the label, tab and alignment included. The list counter has advanced before that, as for the label of a paragraph that holds only a page break.

Tests, in crates/layout/src/tests.rs:

  • a_list_paragraph_that_opens_with_a_break_in_a_cell_shows_no_label: a cell with a numbered list whose labels are three times the text's size. With a page break and with a column break at the start of the second item: no label text and no glyphs, the first and third items still "1." and "3.", the text starting where it does with the label, one line, and that line lower than the first item's by more than 5 pt. With a space before the break and in compatibility mode 14 the label is "2.". With a column break in the middle of the text the paragraph is one line. Without the change: "'\u{c}': the label is not drawn, left: ("2.", 2)".
  • break_only_list_has_no_label and the other label tests pass unchanged.

Checked:

  • cargo fmt -p wordcraft-layout -- --check
  • cargo clippy -p wordcraft-layout --all-targets -- -D warnings
  • cargo test -p wordcraft-layout --lib: 715 passed, 3 failed (auto_hyphenation_breaks_long_words, fragmented_hidden_text_lays_out_like_the_visible_text, hyphenation_and_proofing_follow_each_runs_language), the same three as on main in my container, which has no hyphenation patterns.
  • cargo test -p wordcraft-engine: 1455 passed, 5 failed: swiss_german_and_portugal_portuguese_keep_their_languages_rules, two fit_one_page tests, tracked_style_change_round_trips_through_docx and rejecting_a_reopened_style_change_keeps_style_metadata. The same five fail on main at 514085c.
  • I did not run the full cargo xtask ci; cargo fmt --all -- --check reports crates/docx/src/fit.rs on main itself.

Compared with Word's PDFs:

  • 28 synthetic files, the cases above and these: two breaks in a row, an empty run before the break, a tab after it, two such paragraphs in a row, a paragraph of nothing but the break, a table inside a cell, a text box, two columns with a numbered heading in each, a break in the second paragraph of a cell, a break at the end of the paragraph, a line break at the start. In 26 of the 28 every baseline is within 0.15 pt of Word's and the labels are shown or not as in Word. The other two differ as on main: after the table inside a cell the next line is 9 pt lower than in Word (the empty paragraph after a nested table, An empty paragraph after a nested table at the end of a cell takes a line; in Word the cell ends where the nested table does #6496), and the numbered paragraph in the body is the first case under "Not done".
  • 91 insurance documents filled with made-up data, each word's position compared with Word's PDF. On main 4 change: a heading in the left column of a two-column contract loses its "2.", as in Word, and the 420 words under it in two of the four move from 1.85 pt off Word's on average to 0.13 pt. The other 87 documents come out byte for byte as before. With my other open fixes under it, the same four documents change in the same way.

Not done here:

  • In the body a numbered paragraph that opens with a page break is right but for its first line's height on the new page: Word makes that line as tall as the label (the baseline 1.8 pt lower for a 10 pt number over 8 pt text), WordCraft as tall as the text.
  • I measured table cells of the body. A cell in a header or footer and a cell inside a text box take the same path; I did not measure them.

Summary by CodeRabbit

  • Bug Fixes
    • Page and column breaks at the start of numbered paragraphs in table cells no longer create a layout break; the text stays on one line.
    • In compatibility mode 15 and newer, a leading break hides the paragraph’s list label while preserving its indentation and advancing the list count. A space before the break or compatibility mode 14 keeps the label visible.
  • Documentation
    • Updated layout-parity notes to describe table-cell break and list-label behavior.

…and a list paragraph that opens with either shows no label (storytold#6610)

Word ignores page and column breaks in a table cell: the text goes on in the same line. A
column break still ended the line there.

From Word 2013's layout on, a list paragraph in a cell that opens with one of those breaks is
shown without its number or bullet: nothing is drawn and the line is no taller for it, but the
text starts where it would after the label and the count goes on. The label is kept as its
room alone then. A break that is not the first thing in the paragraph, a text box and the
layout before Word 2013 keep the label.
@coderabbitai

coderabbitai Bot commented Nov 14, 2026 •

Copy link
Copy Markdown

Explain Change →

Important

Review skipped

Review was skipped as selected files did not have any reviewable changes.

Run configuration

Commits

Reviewing files that changed from the base of the PR and between aa1f0e4 and 6da957e.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review

No actionable comments were generated in the recent review.

Walkthrough

Table-cell page and column breaks are handled as markers instead of layout breaks. In compatibility mode 15 and later, a list paragraph beginning with either break has no visible label but retains the label’s measured width. Tests and parity documentation cover the behavior and compatibility mode 14.

Changes: Table-cell list break handling

Layer / File(s) Summary
Break handling and label suppression
crates/layout/src/para/paragraph.rs, crates/layout/src/tests.rs, docs/layout-parity.md
Page and column breaks in table cells retain their source offsets without creating layout breaks. For list paragraphs that begin with either break, list_label returns an empty label with its measured width retained in compatibility mode 15 and later. The regression test and parity documentation cover break placement, line handling, numbering, and compatibility mode 14.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: vangel76, dkhlapov, benandez

Merge Risk: Minimal · previous review aa1f0

This change adjusts how table-cell breaks and list labels are laid out to match Word. It is narrowly scoped and covered by a regression test, and no concrete merge-blocking risk was found.

Pre-merge checks: Passed 4

Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title names the two behaviors the changeset implements: a column break in a table cell is treated like a page break (ignored, so text stays on one line), and a list paragraph that opens with eithe…
Linked Issues check Passed Issue #6610 has one direct linked issue with coding requirements. The diff in crates/layout/src/para/paragraph.rs implements each one: (1) In Shaper::special, COLUMN_BREAK now maps to ClKind::Marker…
Out of Scope Changes check Passed The paragraph.rs diff touches only the two code paths the issue names: break handling in cells and list-label handling for cell paragraphs that start with a break. Every new branch is guarded by cx.en…
Full details: Title check

Explanation

The title names the two behaviors the changeset implements: a column break in a table cell is treated like a page break (ignored, so text stays on one line), and a list paragraph that opens with either break shows no label. It also cites issue #6610. The summary and objectives confirm both behaviors in paragraph.rs and the regression tests in tests.rs. The title is long (135 characters, 26 words), but it is specific and accurate.

Full details: Linked Issues check

Explanation

Issue #6610 has one direct linked issue with coding requirements. The diff in crates/layout/src/para/paragraph.rs implements each one: (1) In Shaper::special, COLUMN_BREAK now maps to ClKind::Marker when cx.env.table is set, the same path PAGE_BREAK already used. Column breaks in cells no longer end the line. (2) In list_label, a new hidden check applies when the paragraph is in a table cell, compat_mode >= COMPAT_MODE_CURRENT, and p.text starts with PAGE_BREAK or COLUMN_BREAK. It returns a Label with empty text, ascent 0.0, no glyphs and no runs, and width x. So the label space and indentation remain, nothing is drawn, and the counter still advances. (3) A break later in the text or after a leading space does not match starts_with, so the label stays visible. (4) Compatibility mode 14 is below the current mode, so the label stays visible. The change is limited to the table-cell path, as the issue requires. The new tests in crates/layout/src/tests.rs cover these cases according to the PR description. I did not run the tests. The insurance-document figures are author-reported and were not reproduced.

Full details: Out of Scope Changes check

Explanation

The paragraph.rs diff touches only the two code paths the issue names: break handling in cells and list-label handling for cell paragraphs that start with a break. Every new branch is guarded by cx.env.table.is_some(), and the mode-15 branch is additionally guarded by the compatibility mode. Body and text-box behavior is therefore unchanged by the code, which matches the issue's scope. The tests and docs/layout-parity.md changes support the same behavior and are legitimate. The PR description's Not-done items (body paragraphs and header/footer or text-box cells not measured) are unimplemented gaps, not out-of-scope changes.

Finishing Touches

Generate unit tests (beta)

  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

Recent review info

Run configuration

Commits

Reviewing files that changed from the base of the PR and between 514085c and aa1f0e4.

Files selected for processing: 3

  • crates/layout/src/para/paragraph.rs
  • crates/layout/src/tests.rs
  • docs/layout-parity.md

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 8 remain after this review.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant