Skip to content

feat(docx): space paragraphs and size table rows - #705

Merged
andiwand merged 2 commits into
mainfrom
feat/docx-spacing
Aug 18, 2026
Merged

feat(docx): space paragraphs and size table rows#705
andiwand merged 2 commits into
mainfrom
feat/docx-spacing

Conversation

@andiwand

Copy link
Copy Markdown
Member

🤖 Generated with Claude Code

A .docx was rendered with none of the spacing Word gives it: paragraphs sat
line against line and every table row collapsed onto its text. The renderer was
not at fault — html/document_style.cpp has emitted margin-top/bottom,
line-height and a row height all along. The docx style reader simply never
produced them: resolve_paragraph_style_ read w:jc and w:ind and nothing
else, and resolve_table_row_style_ was an empty // TODO.

What it reads now

  • w:spacingw:before/w:after as the paragraph's top and bottom
    margin, w:line as its line height, honouring w:lineRule: auto is
    240ths of a line and becomes a percentage, atLeast/exact are twips. A
    w:beforeAutospacing/w:afterAutospacing flag suppresses the value it
    shadows rather than applying a number Word would have ignored.
  • w:trPr/w:trHeight → the table row's height, skipped for
    w:hRule="auto". CSS gives a <tr> height minimum semantics, which is what
    atLeast means (Word omits the rule for it); an exact cap is not
    expressible on a row and is not attempted.

What had to come with it

Both alone would have been a net regression, so this PR also carries:

  • w:contextualSpacing — Word drops the spacing towards a neighbouring
    paragraph of the same style, which is what keeps a list tight. Without it
    every ListParagraph list gained 8pt between items. It is decided per
    paragraph rather than per style, so partial_paragraph_style compares the
    w:pStyle of the adjacent w:p siblings and zeroes the margin it applies
    to; Style carries the flag beside its ResolvedStyle so an inherited one
    is seen.
  • w:tblStyle resolution — a table style carries the paragraph and text
    properties of everything in the table (TableGrid sets w:spacing w:after="0"). Without it the doc defaults loosened every cell. A table now
    resolves its style reference the way a paragraph resolves w:pStyle and
    contributes the whole resolved style, which the existing element-tree cascade
    carries down. Its conditional formats (w:tblStylePr) are still ignored.

ooxml_util gains read_on_off_attribute for ST_OnOff in both its shapes.

Verification

  • Seven new cases in ooxml_text_style_test.cpp, inline XML, no fixtures.
  • Full suite green: 936 passed, the 8 usual skips.
  • Every .docx in the test data was rendered and compared against the previous
    reference output in a browser. Tables stay tight, lists stay tight, headings
    gain their real space-before, and sample1.docx's calendar table now renders
    right-aligned grey day numbers in tall rows — what Word shows, and what the
    old output missed entirely.

Reference output

Regenerated and pushed; both pins advanced. 16 files in odr-public, 3 in
odr-private, all docx/*/document.html — no other format moved.

`w:spacing` becomes the paragraph's top and bottom margin and its line
height, `w:trHeight` the table row's height, and `w:contextualSpacing`
drops the spacing towards a neighbour of the same style so a list stays
tight. A table now resolves its `w:tblStyle`, whose paragraph and text
properties the element cascade carries into the table — without it the
doc defaults would loosen every cell.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012jwYugqjwV6vTLJYRbFgtP

@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: b4d806978a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/odr/internal/ooxml/text/ooxml_text_style.cpp
Comment thread src/odr/internal/ooxml/text/ooxml_text_style.cpp Outdated
A `w:sdt` renders as nothing but its children and a `w:bookmarkEnd` is not
content at all, yet either sitting between two paragraphs of the same style
kept `w:contextualSpacing` from seeing them as neighbours. The lookup now
walks document order: it steps over marker elements, descends into the
wrappers and climbs back out of them, and stops at a `w:tbl` or the end of
the container so a paragraph never neighbours one outside it.

Also records what `w:lineRule="atLeast"` does not do: css has no minimum
line height, so it lowers to the same fixed `line-height` as `exact`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012jwYugqjwV6vTLJYRbFgtP
@andiwand
andiwand merged commit 9230ab3 into main Aug 18, 2026
27 checks passed
@andiwand
andiwand deleted the feat/docx-spacing branch August 18, 2026 19:14
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.

1 participant