Skip to content

Improve PDF rendering for nested and split tables#171

Merged
hackerwins merged 3 commits into
wafflebase:mainfrom
kokodak:pdf-export
May 1, 2026
Merged

Improve PDF rendering for nested and split tables#171
hackerwins merged 3 commits into
wafflebase:mainfrom
kokodak:pdf-export

Conversation

@kokodak

@kokodak kokodak commented May 1, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Render nested tables during Docs PDF export instead of skipping them
  • Align PDF table rendering with the Canvas renderer for split table rows
  • Preserve visible table content when a long cell spans across page boundaries
  • Document the PDF export parity plan and remaining work

Why

Imported DOCX documents can represent complex layouts with nested tables and long table cells. The previous PDF exporter skipped nested table lines and treated consecutive table PageLines too broadly as duplicates, which caused some table content to disappear in exported PDFs.

Linked Issues

Related to #113

Verification

CI automatically posts a verification summary comment on this PR with
per-lane results for both verify:self and verify:integration.

  • verify:self — CI comment shows ✅
  • verify:integration — CI comment shows ✅ (or explicit skip reason below)

Skip reason (if applicable):

Risk Assessment

  • User-facing risk:
  • Data/security risk:
  • Rollback plan:

Notes for Reviewers

  • UI changes (screenshots/gifs if applicable):
  • Follow-up work (if any):

Summary by CodeRabbit

Bug Fixes & Improvements

  • Bug Fixes

    • Fixed PDF export rendering of nested tables and merged cells across page breaks
    • Improved table fragment row-range filtering in PDF output for consistent pagination
  • Tests

    • Added regression test coverage for nested table rendering and split-row scenarios in PDF export

kokodak added 2 commits May 1, 2026 16:57
PDF table export was skipping nested table lines and some split-row fragments, which made imported DOCX table content disappear. Reuse a shared table row painter and align the PDF render-start rules with the Canvas renderer so visible table fragments are painted.
@coderabbitai

coderabbitai Bot commented May 1, 2026

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 03dc4d22-5c17-4aa9-a2ed-50f8e0b93e10

📥 Commits

Reviewing files that changed from the base of the PR and between b4cd578 and 0464917.

📒 Files selected for processing (2)
  • docs/tasks/active/20260501-pdf-export-parity-todo.md
  • packages/docs/test/export/pdf-painter.test.ts

📝 Walkthrough

Walkthrough

Introduces documentation for PDF export parity lessons and a phased improvement plan. Refactors PDF table rendering to conditionally start based on split-row boundaries and row-range filtering. Adds support for nested table rendering with proper cell-content recursion. Improves merged-cell filtering and border clipping for paginated tables.

Changes

Cohort / File(s) Summary
Documentation
docs/tasks/active/20260501-pdf-export-parity-lessons.md, docs/tasks/active/20260501-pdf-export-parity-todo.md
New task documentation recording PDF-Canvas parity lessons for table rendering and a multi-phase improvement plan with fixture categories, parity expectations, regression coverage targets, and known issues.
PDF Painter Control Flow
packages/docs/src/export/pdf-painter.ts
Refactors table-fragment rendering to conditionally start via shouldStartTableRender predicate at split-row boundaries. Extends paintCellContent callback with pageStartRow/endRowIndex to filter merged-cell fragments. Adds nested table recursion instead of skipping; resolves nested blocks and paints them via paintTableRows.
PDF Table Painter Refactoring
packages/docs/src/export/pdf-table-painter.ts
Extracts new paintTableRows helper for table chrome painting. Refactors paintTablePageRange to use row-range options and conditionally apply clip rectangles. Updates PaintCellContent callback signature with row-range parameters; adjusts border rendering and clip state management to use provided bounds.
Table Rendering Tests
packages/docs/test/export/pdf-painter.test.ts
Adds collectPaintedText helper to extract rendered text from PDF pages. Implements two new regression tests: one verifies nested table text is painted, the other exercises split-row scenarios and asserts follow-up row markers render correctly on continuation pages.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant PdfPainter
    participant TablePainter
    participant NestedTable as Nested Block
    
    Client->>PdfPainter: paintPage(pageLines)
    PdfPainter->>PdfPainter: shouldStartTableRender(current line)?
    alt Start Table Rendering
        PdfPainter->>TablePainter: paintTablePageRange(table, pageStartRow, endRowIndex)
        TablePainter->>TablePainter: paintTableRows(with clip if split)
        TablePainter->>TablePainter: Filter merged cells by ownerRow
        TablePainter->>TablePainter: Paint borders with clipped bounds
        TablePainter->>PdfPainter: paintCellContent(callback with row range)
        PdfPainter->>NestedTable: Detect nestedTable in cell
        alt Nested Table Found
            PdfPainter->>TablePainter: paintTableRows(nested table, full row range)
            TablePainter->>TablePainter: Recurse: paintCellContent for nested cells
            TablePainter-->>PdfPainter: Nested content rendered
        end
        PdfPainter-->>TablePainter: Content painted
    else Skip (not a start boundary)
        PdfPainter->>PdfPainter: Continue to next line
    end
    TablePainter-->>Client: Table rendered with parity
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 Tables split across pages, nested deep inside,
With row-range filters keeping merged cells in stride,
Canvas and PDF now render side by side—
No more skipped lines, no more clipping to hide!
Hop, hop! Export parity achieved! 📄✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the primary changes: improving PDF rendering for nested tables (previously skipped) and split tables (now aligned with Canvas renderer behavior).

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/docs/src/export/pdf-painter.ts (1)

786-794: ⚡ Quick win

Share this predicate with the Canvas renderer instead of duplicating it.

This is now the same parity-critical rule that already exists in packages/docs/src/view/doc-canvas.ts. Keeping two copies reintroduces the exact drift that caused the split-row regression in the first place, so it would be safer to move it into a shared helper and import it from both renderers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/docs/src/export/pdf-painter.ts` around lines 786 - 794, Duplicate
predicate shouldStartTableRender should be centralized into a single exported
helper and imported where needed: extract the existing function
(shouldStartTableRender) from pdf-painter.ts into a shared module (export it)
and replace the local copy in pdf-painter.ts and the copy in doc-canvas.ts with
imports from that shared helper; keep the exact logic (plIndex check,
prev/blockIndex, pl.rowSplitOffset, prev.rowSplitOffset) and ensure the helper
is exported with the same name and used by the table-rendering code paths in
both PdfPainter and the Canvas renderer so behavior remains identical.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/design/docs/docs-pdf-export-parity.md`:
- Around line 175-178: Remove the "Nested tables inside cells" item from the
deferred/unsupported lists (the bullet that reads "Nested tables inside cells")
in this document and the other occurrence mentioned (the similar list at the
later block corresponding to lines 261-263), since nested-table rendering is
implemented; ensure both lists no longer mention nested tables and adjust
surrounding text if it implies the feature is unimplemented.

---

Nitpick comments:
In `@packages/docs/src/export/pdf-painter.ts`:
- Around line 786-794: Duplicate predicate shouldStartTableRender should be
centralized into a single exported helper and imported where needed: extract the
existing function (shouldStartTableRender) from pdf-painter.ts into a shared
module (export it) and replace the local copy in pdf-painter.ts and the copy in
doc-canvas.ts with imports from that shared helper; keep the exact logic
(plIndex check, prev/blockIndex, pl.rowSplitOffset, prev.rowSplitOffset) and
ensure the helper is exported with the same name and used by the table-rendering
code paths in both PdfPainter and the Canvas renderer so behavior remains
identical.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7e362255-91b3-46f2-b998-76391c3d7b9b

📥 Commits

Reviewing files that changed from the base of the PR and between 83c46b0 and b4cd578.

📒 Files selected for processing (6)
  • docs/design/README.md
  • docs/design/docs/docs-pdf-export-parity.md
  • docs/tasks/active/20260501-pdf-export-parity-lessons.md
  • docs/tasks/active/20260501-pdf-export-parity-todo.md
  • packages/docs/src/export/pdf-painter.ts
  • packages/docs/src/export/pdf-table-painter.ts

Comment thread docs/design/docs/docs-pdf-export-parity.md Outdated
@kokodak kokodak changed the title Improve PDF export rendering for nested and split tables Improve PDF rendering for nested and split tables May 1, 2026
@codecov

codecov Bot commented May 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.72848% with 14 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
packages/docs/src/export/pdf-painter.ts 84.33% 11 Missing and 2 partials ⚠️
packages/docs/src/export/pdf-table-painter.ts 98.52% 0 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@hackerwins

Copy link
Copy Markdown
Collaborator

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

The parity doc lived under docs/design/ but it was really a phased
in-progress plan — checklists, exit criteria, deferred items — which
belongs in docs/tasks/active/. The architectural details it duplicated
(pipeline, font strategy, table draw order) already live in
docs-pdf-export.md.

Consolidate the phased fixture plan, feature requirements, exit
criteria, and risk list into the active todo so the design folder
stays focused on stable architecture.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@hackerwins
hackerwins merged commit a008f65 into wafflebase:main May 1, 2026
1 check passed
@hackerwins hackerwins mentioned this pull request May 1, 2026
3 tasks
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