Skip to content

fix(pptx): suppress layout/master placeholder prompt text in html preview#81

Merged
goworm merged 1 commit intomainfrom
fix/pptx-layout-placeholder-prompt-text
Apr 28, 2026
Merged

fix(pptx): suppress layout/master placeholder prompt text in html preview#81
goworm merged 1 commit intomainfrom
fix/pptx-layout-placeholder-prompt-text

Conversation

@goworm
Copy link
Copy Markdown
Contributor

@goworm goworm commented Apr 28, 2026

Summary

  • Stop layout/master content placeholders from leaking their edit-prompt text ("Click to add title", "单击此处添加正文") onto the rendered HTML slide.
  • Apply ECMA-376 §19.3.1.36 default explicitly: <p:ph> with no type attribute defaults to obj. Open XML SDK reports Type.HasValue == false here, which is the root cause behind PPTX HTML preview renders inherited placeholder prompt text #79 — the previous denylist never matched the very common "type-less body placeholder" shape and let its prompt text through.
  • Keep the chrome (fill / outline / geometry) of suppressed placeholders so layout-themed backgrounds still render.

Fixes #79.
Supersedes #80 — same intent, narrower fix that aligns with how Apache POI handles inheritance (SlideShowExtractor.java:179-183 skips boiler-plate placeholder text on master sheets; XSLFShape.java:369-370 handles the missing-type default).

Why this differs from #80

#80 takes an allowlist approach (only render date/footer/header/slide-number), which:

  1. Drops the entire <p:sp> for content placeholders — losing themed background fills and outlines that legitimate layouts carry.
  2. Doesn't make the root cause visible — the fix works only as a side effect of IsVisibleInheritedPlaceholder returning false when Type.HasValue == false. A future reader has to re-derive the ECMA default rule.
  3. Leaves the existing skipIndices type: check after the early continue as effectively dead code without explaining why.

This PR splits text from chrome: a layout's placeholder still contributes its visual frame, only its <p:txBody> is suppressed. The ECMA default is written as ?? PlaceholderValues.Object with a comment pointing at the spec section.

Test plan

Validated locally with a regression test that:

  • Builds a presentation with a real slide (title + body textbox).
  • Injects a <p:sp> into every <p:spTree> in the slide layouts. Three variants:
  • Calls PowerPointHandler.ViewAsHtml() and asserts the prompt text is not in the rendered HTML.
  • Counter-tests: a Footer-type placeholder's text does appear; a SlideNumber-type placeholder's text does appear; a Body-type placeholder with a themed solidFill keeps its fill in the rendered HTML even though its text is suppressed.

All 6 cases pass. The 9 existing HtmlPreviewBugTests_Round1 tests also pass.

  • dotnet build src/officecli/officecli.csproj clean
  • dotnet test --filter HtmlPreviewBugTests_Round1 — 9/9 pass
  • Local regression suite for this PR — 6/6 pass

…view

Layout and master content placeholders carry editor prompt boilerplate
("Click to add title", "单击此处添加正文") in their <p:txBody>. Real
Office never renders that text; it shows up only in edit mode. Open XML
SDK exposes the layout's <p:txBody> directly, and the previous renderer
forwarded it onto the slide whenever the placeholder slipped past the
type denylist.

Two issues with the old denylist approach:

1. ECMA-376 §19.3.1.36 says a <p:ph> with no `type` attribute defaults
   to `obj`. Open XML SDK reports `Type.HasValue == false` for the
   absent attribute, so the entire denylist branch was skipped — and a
   layout body placeholder authored without an explicit type leaked its
   prompt text onto the slide. This is the shape behind issue #79.

2. Picture/Chart/Table/Media placeholders weren't on the denylist
   either, so their prompt text ("Click icon to add picture") leaked
   the same way.

Fix: model the rule the way Apache POI does
(SlideShowExtractor.java:179-183, XSLFShape.java:369-370). Layout and
master placeholders never contribute text to the rendered slide — only
the four metadata slots (date/footer/header/slide number) carry
genuine layout-supplied content. Everything else is suppressed at the
text level but still renders chrome (fill / outline / geometry), so a
layout's themed placeholder background survives.

The ECMA default is now applied explicitly (`Type.HasValue == false`
=> Object) instead of relying on a side effect of the SDK's missing
HasValue.

Validated with a local functional test that injects a layout
placeholder with no `type` attribute and asserts the prompt text does
not appear in ViewAsHtml() while the layout-supplied footer text and
themed fill do.

Fixes #79
Supersedes #80

Co-Authored-By: pojian <lijianlin6868@gmail.com>
@goworm goworm merged commit 42f7cc4 into main Apr 28, 2026
8 checks passed
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.

PPTX HTML preview renders inherited placeholder prompt text

1 participant