Skip to content

fix(docx): let the list's own block carry its spacing#471

Merged
developer0hye merged 1 commit into
mainfrom
fix/docx-list-block-spacing
Jul 26, 2026
Merged

fix(docx): let the list's own block carry its spacing#471
developer0hye merged 1 commit into
mainfrom
fix/docx-list-block-spacing

Conversation

@developer0hye

Copy link
Copy Markdown
Owner

Summary

  • emit one block per list, carrying both the Word line box and the list's w:spacing edge gaps
  • generate_list takes the line-height settings instead of a bool and builds the wrapper itself

Related issue

Fixes #463

Details

A list was wrapped in two blocks: an outer one holding the Word line box, and an inner one holding the edge gaps. Typst does not apply block spacing at a container's edges, so the inner gaps never reached the boundary and the outer wrapper — which set neither above nor below — fell back to Typst's own 1.2em block.spacing.

Baseline-to-baseline pitch from a numbered item to the shaded code line after it, page 1:

Boundary Word GT before after
item 1 to $ office2pdf report.docx 15.64 pt 25.83 pt 15.64 pt
item 2 to $ office2pdf slides.pptx … 15.64 pt 25.83 pt 15.64 pt
item 3 to $ office2pdf *.xlsx … 15.64 pt 25.83 pt 15.64 pt

Mean absolute vertical drift on that file falls from 12.67pt to 1.43pt, and across the business corpus from 13.52pt to 12.88pt.

02_contract_ko moves the other way, 4.20pt to 9.11pt. That is the leaked default having masked a deficit rather than helped: its w:spacing w:after there really is 4pt, matching Word's 22.32pt pitch against an 18pt line box, and the ~8pt the document is short by accumulates earlier — its first three paragraphs are already 2.79pt, 7.52pt, and 7.76pt high before any list appears, which is the title-paragraph defect #402 tracks.

Testing

  • cargo fmt --all -- --check
  • cargo test --workspace
  • cargo clippy --workspace --all-targets --all-features
  • python3 scripts/validate_business_golden_mocks.py
  • pdftotext -bbox pitch comparison against all 10 Word-produced DOCX golden PDFs
  • pdftoppm -r 150 rendering, matched region crops, and magick compare -metric AE -fuzz 5%

Visual impact

  • No rendered PDF change
  • Rendered PDF change or visual evidence added
  • Reason: the gap between a list and its neighbours changed on every DOCX with a list.

Visual audit

  • Issue: DOCX: list blocks inherit Typst's default block spacing instead of w:spacing #463
  • Fixture: tests/golden_mocks/business/sources/docx/05_technical_manual_en.docx
  • Page(s): page 1 of the Word GT and of the office2pdf output
  • Renderer and DPI: pdftoppm, 150 DPI
  • Evidence mode: fix
  • New follow-up issues found in this audit: None
  • GT: assets/bugfixes/issue-463/gt.jpg
  • Before: assets/bugfixes/issue-463/before.jpg
  • After: assets/bugfixes/issue-463/after.jpg

Visual comparison

GT Before After
GT Before After

Required inspection

  • Rendered all evidence at 150 DPI or higher
  • Stored progressive JPEG quality 86 assets with metadata stripped
  • Inspected matched region crops at full resolution
  • Ran the 5% fuzz pixel-difference sweep
  • Inventoried hairlines and border dash styles
  • Inventoried font weight, italic, and underline emphasis

The 5% fuzz sweep against the size-normalized GT falls from 88,314 to 57,544 differing pixels. The residual clusters are the 12pt code-paragraph indent tracked in #464 plus font antialiasing. The page's only hairline is the header rule, which matches GT in position, width, and weight on the full-resolution crop; there are no dashed or dotted borders. Bold headings, the monospace runs, and the italic disclaimer all keep the same emphasis as GT.

Deviation audit

Check Result
Page count/order Matches GT - two pages in the same order
Element presence Matches GT - every heading, paragraph, command line, and the exit-code table are present
Position/size Remaining: #464 - the shaded command paragraphs still lose their 12pt w:ind w:left; the page box and text column match GT
Rotation/flip No deviation observed - the fixture contains no rotated or flipped elements
Fill Matches GT - the F4F4F4 code shading is the same color, though its left edge inherits #464
Stroke/border No deviation observed - the header rule matches GT and there are no other strokes
Text content Matches GT - all strings on both pages are preserved
Font family/weight/style Matches GT - Arial body, Courier New code, bold headings, and the italic disclaimer all match
Text color Matches GT - the navy headings, grey header, and black body all match
Alignment Matches GT - the justified body paragraphs and centered footer match
Line/paragraph spacing Fixed - every list-to-code pitch is now Word's 15.64pt against the previous 25.83pt, and the file's mean absolute drift falls from 12.67pt to 1.43pt
Clipping/overflow No deviation observed - no glyph is clipped and nothing overflows the text column

Checklist

  • Commits include a Signed-off-by line
  • PR scope contains one root cause
  • Remaining visual deviations each reference an open issue

A list was wrapped in two blocks: an outer one holding the Word line box,
and an inner one holding the list's `w:spacing` edge gaps. Typst does not
apply block spacing at a container's edges, so the inner gaps never reached
the boundary and the outer wrapper - which set neither `above` nor `below` -
fell back to Typst's own 1.2em `block.spacing`. Every numbered item in the
technical manual opened 10.19pt too far from the shaded code line after it,
accumulating to +30pt by section 3.

Emit one block instead, carrying both the line box and the gaps.
`generate_list` now takes the line-height settings rather than a bool and
builds the wrapper itself, so there is nowhere for a default to leak in.

On page 1 of `05_technical_manual_en` the item-to-code pitch goes from
25.83pt to Word's 15.64pt, mean absolute vertical drift falls from 12.67pt
to 1.43pt, and the 5% fuzz pixel difference against the Word export drops
from 88,314 to 57,544.

`02_contract_ko` moves the other way, from 4.20pt to 9.11pt, because the
leaked default had been masking a deficit rather than helping: Word's gap
there really is the 4pt `w:spacing w:after` this change now emits, and the
~8pt the document is short by accumulates earlier, in the title paragraph
that #402 tracks.

Fixes #463

Signed-off-by: Yonghye Kwon <developer.0hye@gmail.com>
@developer0hye
developer0hye merged commit 3010b47 into main Jul 26, 2026
17 checks passed
@developer0hye
developer0hye deleted the fix/docx-list-block-spacing branch July 26, 2026 00:59
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.

DOCX: list blocks inherit Typst's default block spacing instead of w:spacing

1 participant