feat(doc): per-run character formatting from CHPX#608
Merged
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 91404264d3
ℹ️ 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".
andiwand
added a commit
that referenced
this pull request
Jul 16, 2026
Per [MS-DOC] 2.6.1 an sprmCRgFtc0 operand of 0 is valid when SttbfFfn has no entries; the style-sheet default font (unmodelled) applies, so leave the font unset instead of throwing. Genuinely out-of-range indexes still throw. Addresses Codex review feedback on PR #608. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AEvWWwe1EyeWH7ANHoAvPH
andiwand
added a commit
that referenced
this pull request
Jul 21, 2026
Per [MS-DOC] 2.6.1 an sprmCRgFtc0 operand of 0 is valid when SttbfFfn has no entries; the style-sheet default font (unmodelled) applies, so leave the font unset instead of throwing. Genuinely out-of-range indexes still throw. Addresses Codex review feedback on PR #608. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AEvWWwe1EyeWH7ANHoAvPH
andiwand
force-pushed
the
feat/doc-character-formatting
branch
from
July 21, 2026 18:28
a4042cb to
e1e681e
Compare
Implement Direct Character Formatting ([MS-DOC] 2.4.6.2): read the PlcBteChpx and its ChpxFkp pages, split the decoded piece text at every formatting-run boundary, and emit styled span elements carrying bold, italic, underline, strike, font size, font name (SttbfFfn), font color (sprmCCv/sprmCIco) and highlight (sprmCHighlight). Replaces the flat 11pt placeholder; unformatted text now defaults to 10pt (the sprmCHps default). Paragraphs store the style of their first run so empty paragraphs keep their height. Equal Chpx byte sequences share one resolved style and adjacent equal-style runs merge. Field-code hiding is now stateful across runs and paragraphs. Pcd.Prm modifications and STSH style layering remain open (documented in AGENTS.md). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R9Z3kyUaHNkJacAEggevHH
Per [MS-DOC] 2.6.1 an sprmCRgFtc0 operand of 0 is valid when SttbfFfn has no entries; the style-sheet default font (unmodelled) applies, so leave the font unset instead of throwing. Genuinely out-of-range indexes still throw. Addresses Codex review feedback on PR #608. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AEvWWwe1EyeWH7ANHoAvPH
Mirror the xls module: a StyleRegistry owns the resolved character
TextStyles (index 0 = default) and the interned font names, while the
ElementRegistry stores only a per-element style index. CharacterStyles
shrinks to a runs-only CharacterRuns; the SPRM/font-table resolution
moves to doc_style.{hpp,cpp}.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PvbJYsLLST3hkCgkcHBoFb
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PvbJYsLLST3hkCgkcHBoFb
andiwand
force-pushed
the
feat/doc-character-formatting
branch
from
July 21, 2026 18:58
7070e5e to
46d3a07
Compare
Mirror the xls StyleRegistry: set_font_names stores the SttbfFfn table in a vector that is never modified afterwards, so the font-name strings cannot move; apply_character_sprms reads them as a span and read_character_runs takes the fonts from the registry it already gets. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PvbJYsLLST3hkCgkcHBoFb
StyleRegistry now takes its font names and resolved styles in the constructor (mirroring the xls registry); set_font_names/add_style are gone, read_character_runs collects styles into a plain vector and no longer depends on the registry, and the default style moved into a named default_character_style() factory. Also review cleanups across the branch: - emplace_back for aggregate push_backs (C++20 parenthesized init) - intern cache: single try_emplace instead of find + emplace with a second std::string(grpprl) allocation - fixed-size integer types instead of plain int - drop the local read_u16 in favor of util::byte::from_little_endian - shared append_u16/append_u32 test helpers in oldms_test_util.hpp - doc_helper.cpp: definitions moved into the namespace block Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WJRDZcksAtKnXyhDTeMkMK
andiwand
enabled auto-merge (squash)
July 21, 2026 21:48
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 Generated with Claude Code
Implements Direct Character Formatting ([MS-DOC] 2.4.6.2) for the legacy
.docdecoder: text now renders with per-run bold, italic, underline, strikethrough, font size, font name, font color, and highlight, replacing the flatfont_size = 11ptplaceholder. This is Open Work §1 fromtext/AGENTS.md, implemented as planned there.How
PlcBteChpx(table stream) → 512-byteChpxFkppages (WordDocument stream) → per-runChpx.grpprlSPRMs, applied over a 10pt default (thesprmCHpsdefault of 20 half-points). Font names come fromSttbfFfnand are interned soTextStyle::font_namestays valid.root → paragraph → span → text: the piece decode walks style-uniform chunks (runs are keyed by stream offset, so a boundary inside a 2-byte UTF-16 CP is pushed past it), each run becomes a styled span, and each paragraph stores the style of its first run so empty paragraphs keep their height.Chpxbyte sequences share one resolved style; adjacent equal-style runs merge.ToggleOperand0x80/0x81 resolve against the (unmodelled, default-off) style value.sprmCCvCOLORREFwithfAutoclears the color;sprmCIco/sprmCHighlightuse theIcopalette.TextCleaner) is now stateful across runs and paragraphs — a field can span both.Pcd.Prmpiece modifications and STSH style layering — style-sheet-derived properties fall back to defaults.Tests
OldMs.doc_apply_character_sprms— every modelled SPRM, toggle semantics, cvAuto reset, unknown fixed/variable SPRM skipping, malformed-grpprl throws.OldMs.doc_read_font_names— syntheticSttbfFfn.OldMs.doc_character_formatting— end-to-end over a synthetic inline-bytes.doc(FIB + piece table +ChpxFkp): span splitting, defaults, bold + font-name run, paragraph style.OldMs.*and the real-file.docHTML output tests pass.Note: reference HTML
Rendered
.docHTML changes structurally (styled spans instead of flat 11pt text), e.g.SampleDOCFile_100kb.doc's heading:The
.docreference outputs undertest/data/reference-output/odr-public/output/doc/need regenerating for thecompare-htmlCI step (flagged separately, same as #606).