Skip to content

fix(xlsx): advance bottom-legend entries by the row's measured clearance without a width floor - #1750

Merged
developer0hye merged 2 commits into
mainfrom
fix/issue-1616-legend-entry-floor
Sep 15, 2026
Merged

developer0hye merged 2 commits into
mainfrom
fix/issue-1616-legend-entry-floor

Conversation

@developer0hye

Copy link
Copy Markdown
Owner

File submission policy

Summary

A worksheet axis chart's bottom legend held every entry at the 78pt LEGEND_ENTRY_W floor and skipped the visible-row trim and centre correction when the last entry fell under it, so the 6pt legend of the public Gift Budget workbook started 12.27 printed points left of native with a flat 78pt pitch where native advances 77.23 and 75.50.

Native Excel for Mac 16.112 one-factor exports (all four series renamed to one string at twelve widths at 9pt, five at 6pt and four at 18pt, plus the unchanged four-name row at 6, 9 and 18pt, each against a layout-identical re-zip control) show that an entry advances by key + gap + its own label + one clearance shared by the row, 6.617 + 0.16 x mean(label design advances), with no floor. Twenty-four of the twenty-five rows fit within 0.016pt. The earlier per-face slope table and terminal-glyph term were this share of each row's mean label width, so both are replaced by the rule. The floor and the generic GAP remain for other hosts and unmeasured faces.

On the 6pt package the three filled keys now land at 586.967 / 650.277 / 712.172 printed points against native 586.950 / 650.275 / 712.185; the 9pt row moves by under 0.006pt.

Related: #1616. Vertical seat of the 6pt row is #1748; the constrained clearance above 23pt is #1749; the line-sample box is #1617.

Related issue

Fixes #1616

Testing

  • Red: an_excel_legend_entry_advances_by_its_own_label_with_no_width_floor, an_excel_legend_row_shares_one_clearance_from_its_mean_label and the compiled gift_budget_compiled_six_point_legend_keys_match_native_bounds fail on main (78pt pitch; first key 574.49 against 586.95).
  • The seven-face 9/18pt gutter table and the 9pt Calibri pitch test pass unchanged under the new rule.
  • cargo test --locked -p office2pdf --lib: 3085 passed.
  • cargo test --locked --workspace: see the run recorded below.
  • cargo clippy --locked --workspace --all-targets -- -D warnings on stable and 1.97, cargo fmt --all --check, git diff --check: passed.
  • Fresh native/current PDFs of the 6pt package: compare_layout.py --audit --fine-shift 0.5 --noise-floor 0.5, compare_text_layer.py, compare_render.py --dpi 300 --strict-clusters on page 2; the text-layer census (3 fewer spaces, extraction order) is identical to the pre-fix output.
  • Required delegated read-only documentation freshness audit: PASS.
  • Probe specs, package and export hashes, and the measured rows: validation.

Visual impact

  • No rendered PDF change
  • Rendered PDF change or visual evidence added

Visual audit

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
  • Used Codex/Claude vision to inspect the full GT/output pages, diff, and matched crops
  • Inspected matched region crops at full resolution
  • Ran compare_layout.py --audit --fine-shift PT and dispositioned every fine/large text-instance shift, rectangle geometry deviation, painted-text visibility mismatch, and visible-fill occlusion
  • Ran compare_render.py --cluster-report PATH --strict-clusters and dispositioned every material 5% fuzz diff cluster by explicit ID
  • Inventoried hairlines and border dash styles
  • Inventoried font weight, italic, and underline emphasis

Deviation audit

Check Result
Page count/order Matches GT: two fitted pages
Element presence Matches GT
Position/size Remaining: #1748 6pt legend label seat; #1617 line-sample marker; #1719 sidebar B4 block; #1659 long-string drift (legend keys and labels now on native x)
Rotation/flip Matches GT
Fill Matches GT
Stroke/border Remaining: #1745 unclipped zero-value line under the category axis
Shape outline geometry Matches GT
Text content Matches GT: baseline/current extraction identical
Font family/weight/style Matches GT
Text color Matches GT
Alignment Remaining: #1748 6pt label baseline (visible legend row now centred on native)
Line/paragraph spacing Matches GT
Clipping/overflow Remaining: #1745

Checklist

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

🤖 Generated with Claude Code

developer0hye and others added 2 commits September 15, 2026 22:12
…nce without a width floor

A worksheet axis chart's bottom legend held every entry at the 78pt
LEGEND_ENTRY_W floor and skipped the visible-row trim and centre shift
when the last entry fell under it, so the 6pt legend of the public Gift
Budget workbook started 12.27 printed points left of native with a flat
78pt pitch where native advances 77.23 and 75.50pt.

Native Excel for Mac 16.112 one-factor exports of the same workbook (all
four series renamed to one string at twelve widths at 9pt, five at 6pt
and four at 18pt, plus the unchanged row at 6, 9 and 18pt) show that an
entry advances by key + gap + its own label + one clearance shared by
the row, 6.617pt + 0.16 x the mean label design advance, with no floor.
Twenty-four of the twenty-five rows fit within 0.016pt. The per-face
slope table and the terminal-glyph term were this share of each row's
mean label width, so both are replaced by the rule; other hosts and
unmeasured faces keep the generic gap and the #827 floor.

The 6pt package's filled keys now land within 0.02 printed points of
native and the 9pt row moves by under 0.006pt. The row's vertical seat
at 6pt (#1748), the constrained clearance above 23pt (#1749) and the
line-sample box (#1617) are tracked separately.

Related: #1616

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Yonghye Kwon <developer.0hye@gmail.com>
…e table

The seven-face gutter table measured each row through the runner's own
font resolution; a runner without Century Gothic installed resolves a
substitute whose labels are narrower, and the shared-clearance rule then
reports that substitute's clearance. Record each source face's design
advance of the probe label and skip a face that resolves to another
design, keeping the in-tree Calibri row mandatory, as the PowerPoint
legend-key face sweep already does.

Related: #1616

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Yonghye Kwon <developer.0hye@gmail.com>
@developer0hye
developer0hye merged commit b58d19f into main Sep 15, 2026
18 checks passed
@developer0hye
developer0hye deleted the fix/issue-1616-legend-entry-floor branch September 15, 2026 14:08
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.

XLSX: small-font bottom legends use an incorrect entry-width floor

1 participant