feat(pptx): resolve theme colour, and paint the ground it needs - #747
Merged
Conversation
A pptx states most of its colour as `a:schemeClr` — a slot name, not a value — so reading only the literal `a:srgbClr` sees almost nothing: the deck that prompted this carries 1066 scheme references and not one literal. A slot now resolves along slide → layout → master → theme, folding the theme's `a:clrScheme` together with the master's `p:clrMap` into a `ColorScheme`. Colour had been held back because a run colour is unsafe until something is painted behind it: a deck puts white text on a coloured master, and on our white page it simply vanished. So the ground arrives with it — `p:bg` from the slide, its layout or its master onto the new `PageLayout::background_color`, and a shape's own `p:spPr/a:solidFill` onto the frame. `a:bodyPr` anchor, `a:lnSpc` line height, `a:spcBef`/`a:spcAft` and `@baseline` come along. Painting a frame's fill exposed an odf bug it had been hiding: `draw:fill` and `draw:fill-color` cascade independently, and the colour outlives the fill, so boxes the file leaves blank were about to come out coloured. The fill state now rides in the resolved colour's alpha. Master and layout shape trees are still not drawn, so a deck whose only ground is a shape on its master keeps its white text unreadable. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G6qVWb1ky168K4FrBpyZeA
`-Wmissing-field-initializers` is an error on the linux builds, and both `ppt_document` and `iwork_document` spell every member out. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G6qVWb1ky168K4FrBpyZeA
…misses
The style resolution moves out of the document into
`ooxml_presentation_style.{hpp,cpp}`, the way `ooxml/text` already keeps
it, so the layout/master/theme walk and the `a:rPr`/`a:pPr` readers are
drivable from inline xml and an in-memory filesystem.
- every layout, master and theme part is read behind `is_file` and a
catch, so a missing or non-xml part leaves a slide unstyled instead of
failing the open
- a relationship target that is absolute, empty or escaping resolves
rather than throwing
- a `p:bg` we do not model ends the inheritance walk instead of falling
through to the master's colour
- `p:clrMap` resolves against the theme, not against itself
- xlsx drops the argb alpha byte again: excel ignores it, producers write
`00`, and `html::color` started honouring it
- a layout is read once, not once per slide, and its master's scheme is
shared rather than copied per slide
- `PageLayout::background_color` reaches the jni and apple bindings
Reference output is byte-identical across both corpora.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VR6FrcYaNnr5vi9kt9qUD7
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
Follow-up to #746. The colour reading deferred there turned out to be worth
nothing on its own and actively harmful, so this does the version that works.
Why literal colour was not the change to make
a:srgbClr— the literal form — is barely used. Across the four pptx fixtures:a:schemeClr)Shipping literal-only would have done nothing for the deck that started this and
turned 36
tuesday_d6runs invisible. Colour in a pptx means theme colour.What this does
Resolves the theme. A slot (
tx1,bg1,accent1, …) resolves alongslide → layout → master → theme: the theme's
a:clrSchemeholds the values, themaster's
p:clrMapsays which slot each name stands for, andColorSchemeisthe two folded together. Masters are shared, so one is read once, not once per
slide. This is the first time the module walks past the slide at all.
Paints the ground, because colour is unsafe without it. Text a deck puts on
a coloured master is white; on our white page it vanishes. So
p:bg— from theslide, else its layout, else its master — lands on a new
PageLayout::background_color, and a shape'sp:spPr/a:solidFillon the frame.The reported deck's footers are white on its red master and are now readable.
Along with:
a:bodyPr/@anchor,a:lnSpcline height,a:spcBef/a:spcAft(absolute
a:spcPtsonly — the percent form is of the text size, which csswould resolve against the width), and
@baselinesub/superscript.The odf bug this uncovered
A frame is a plain
<div>, so its fill has to be abackground-color— thefill:we were writing only ever reached the<svg>a shape carries, and wasinert on every frame. Painting it revealed that odf's
draw:fill-colorcascades independently of
draw:filland outlives it: LibreOffice writes<style:graphic-properties draw:fill-color="#729fcf" …/>with nodraw:fillanywhere, and boxes the file leaves blank were about to come out blue. Verified
against a LibreOffice render of
odp/image-1.odpandodg/sample.odg— neitherpaints those fills. The fill state now rides in the resolved colour's alpha.
That is what moves the odf files in the reference output: stale fills correctly
becoming transparent.
odg/sample.odgrenders pixel-identically before andafter.
What still does not match
Master and layout shape trees are not drawn.
tuesday_d6.pptxputs itswhite titles on a gradient-filled
custGeombanner that lives in its master, sothose 36 runs stay unreadable — neither custom geometry, nor gradients, nor
master shape trees are modelled. This is the honest residual of the trade-off,
called out in
presentation/AGENTS.md. Images and bullets are also stillmissing.
Test data
Reference output regenerated; the pins move to:
f211f75eacdb50Full suite: 1194 passed, 6 skipped. 70 public / 153 private output files change
— pptx from the new styling, odf from the fill fix.