Skip to content

feat(ooxml): pptx slide size + tables, xlsx merged cells + value types, docx table merges#607

Merged
andiwand merged 5 commits into
mainfrom
ooxml-low-hanging-fruits
Jul 17, 2026
Merged

feat(ooxml): pptx slide size + tables, xlsx merged cells + value types, docx table merges#607
andiwand merged 5 commits into
mainfrom
ooxml-low-hanging-fruits

Conversation

@andiwand

@andiwand andiwand commented Jul 16, 2026

Copy link
Copy Markdown
Member

🤖 Generated with Claude Code

A batch of low-hanging fruits from the ooxml module AGENTS.md open-work lists, plus one latent shared-code bug they exposed.

pptx

  • Real slide size: slide_page_layout reads p:presentation/p:sldSz (EMUs, resolved once in the Document ctor; ECMA-376 default 10in × 7.5in when absent) instead of a hardcoded 11.02in × 8.27in. Slide names come from p:cSld@name.
  • Tables actually parse now: a:tbl sits inside p:graphicFrame/a:graphic/a:graphicData, which the parser never descended into — tables were silently absent from the element tree. Now: p:graphicFrame→frame (with p:xfrm positioning), a:tbl wired through create_table_element/append_column (a:tblGrid/a:gridCol), rows/cells from a:tr/a:tc, spans from gridSpan/rowSpan, covered cells from hMerge/vMerge, column widths and row heights from w/h EMUs. The dead ODF-name table_dimensions copy-paste is gone.

xlsx

  • Merged cells: mergeCells is parsed per sheet into anchor span + is_covered flags on the SheetCell side map; sheet_cell_span/sheet_cell_is_covered report them and merged ranges render as colspan/rowspan. Ranges whose anchor cell is absent from sheetData are dropped to keep the renderer's cursor bookkeeping consistent.
  • Cell value types: sheet_cell_value_type derives number-vs-string from c/@t (default "n" → float_number when <v> exists), so numeric cells get the odr-value-type-float class.

docx

  • Table adapter rewritten against w: names (the methods previously queried ODF names and were dead code): dimensions from w:tblGrid/w:gridCol + w:tr; colspan from w:gridSpan; w:vMerge continuations report covered, and the restart cell computes its rowspan by walking following rows at the same grid column.
  • bookmark_name reads w:name instead of ODF's text:name.

TableCursor: latent infinite loop (exposed by xlsx merges, affects ODF too)

handle_rowspan_ assumes each row's pending covered ranges are sorted by column, but add_cell appended them. A long-rowspan cell followed in a later row by new rowspan anchors at smaller columns (e.g. F4:F9 then A6:A7 — real pattern in ruski.xlsx) produced an unsorted list; the skip missed the covered position and translate_sheet's covered-cell continue never advanced the cursor → infinite loop. Fixed with sorted insertion + a tolerant skip, a TableCursor regression test, and a defensive one-column advance on the (normally unreachable) covered branch in the renderer. ruski.xlsx went from hanging forever to 0.13s.

Verification

  • Hand-crafted xlsx (merged range incl. absent covered cells, shared/numeric cells) and docx (gridSpan + vMerge chain, bookmark) verified end-to-end through odr_test: correct colspan/rowspan, covered cells skipped, float classes, bookmark anchors.
  • style-various-1.pptx renders its slide-8 table with real column widths; the 16:9 deck renders 10in × 5.625in slides.
  • Suites pass: pptx, docx, xlsx, odt/ods/odp/odg, xls, csv, TableCursor.*.
  • Note: CI reference-output comparison will show expected diffs (slide sizes, new pptx tables, xlsx merges/value classes) — reference submodules need regenerating.

…s, docx table merges

pptx:
- read the real slide size from p:presentation/p:sldSz (ECMA-376 default
  10in x 7.5in when absent) instead of a hardcoded 11.02in x 8.27in;
  slide names from p:cSld@name
- parse tables: a:tbl sits inside p:graphicFrame/a:graphic/a:graphicData,
  which the parser never descended into; wire create_table_element +
  append_column (a:tblGrid/a:gridCol), rows/cells, spans from
  gridSpan/rowSpan, covered cells from hMerge/vMerge, column widths and
  row heights, and p:xfrm positioning for graphic frames

xlsx:
- merged cells: parse mergeCells into anchor span + covered flags on the
  SheetCell side map; ranges whose anchor cell is absent from sheetData
  are dropped to keep the renderer's cursor consistent
- cell value types: derive number-vs-string from c/@t so numeric cells
  get the odr-value-type-float class

docx:
- replace dead ODF-name code in the table adapter: dimensions from
  w:tblGrid/w:gridCol + w:tr, colspan from w:gridSpan, vMerge
  continuations report covered and restart cells compute their rowspan
  by walking following rows at the same grid column
- bookmark_name reads w:name instead of ODF's text:name

TableCursor: fix a latent infinite loop exposed by xlsx merges — the
per-row pending covered ranges were appended unsorted, so handle_rowspan_
missed them when a long-rowspan cell was followed by later rowspan
anchors at smaller columns and the sheet renderer never advanced (hung
on ruski.xlsx). Insert sorted, skip tolerantly, advance the cursor on
the (normally unreachable) covered-cell branch, and add a regression
test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KH4XvPFfdUvH7HMp8rmqZT

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

ℹ️ 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/presentation/ooxml_presentation_parser.cpp
andiwand and others added 3 commits July 16, 2026 21:25
Table cell text sits under a:tc/a:txBody/a:p, but only p:txBody was
registered in the tag dispatch table, so cell text was dropped.
Addresses review feedback on #607.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AEvWWwe1EyeWH7ANHoAvPH
@andiwand
andiwand enabled auto-merge (squash) July 16, 2026 21:30
@andiwand
andiwand merged commit 7ec0c6f into main Jul 17, 2026
11 checks passed
@andiwand
andiwand deleted the ooxml-low-hanging-fruits branch July 17, 2026 11:27
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