Skip to content

fix(html): put a frame where its style says, and keep its image inside - #684

Merged
andiwand merged 5 commits into
mainfrom
fix/frame-image-placement
Aug 11, 2026
Merged

fix(html): put a frame where its style says, and keep its image inside#684
andiwand merged 5 commits into
mainfrom
fix/frame-image-placement

Conversation

@andiwand

Copy link
Copy Markdown
Member

about.odt rendered as a full-page cow: the image covered the whole page instead of sitting in the text.

What was wrong

A frame's <img> is written as position:absolute;left:0;top:0;width:100%;height:100%, but nothing in the frame's own markup made it a containing block — that came only from *{position:relative} in the shipped document.css. Read without that sheet (externalized resources, page moved away from its resources/ dir), the image resolved against the initial containing block: top left of the page, full viewport size. Every image in the document landed there, stacked.

Separately, ODF places a frame either by an offset (svg:x) or by naming a side (style:horizontal-pos). Only the offset was read, so a centred image — the letterhead logo in style-various-2.odt — sat hard left where LibreOffice centres it.

What changed

  • A frame states position:relative itself, so it is a containing block regardless of the stylesheet.
  • style:horizontal-pos is read into a new GraphicStyle::horizontal_position and applied as auto margins (block frames) or left:0;right:0 (absolute frames), only where no svg:x already places the frame.
  • Drive-by in the same function: frame.width()->to_string() was an unchecked optional dereference in the wrap-before branch while the block below it guards the same optional.

Verification

about.odt measured as img rect vs. its frame rect, in all four combinations of text_document_margin and stylesheet:

before after
margin on, no stylesheet img 0,0 1200x900, frame at 495,977 img 495,977 171x171 = frame
margin off, no stylesheet img 0,0 1200x900, frame at 419,766 img 419,766 171x171 = frame
margin on, with stylesheet 690,993 690,993 — unchanged
margin off, with stylesheet 411,758 411,758 — unchanged

Where the stylesheet loads, geometry is untouched. Full suite green (861 tests); of all regenerated output, 41 files differ and every one is accounted for by the added position:relative and the auto margins — no other rendering moved. Reference output regenerated and the pins advanced.

Not addressed here: WMF/EMF images are still inlined as data:image/wmf, which no browser decodes, so they render as a broken-image icon (style-various-2.odt, journal_Word_template.docx, 15-MB-docx-file-download.docx, sample.xlsx). That needs a metafile decoder, like SVM already has.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QJ7vyWPCg1oaGoQ1dirNYT

andiwand and others added 2 commits August 11, 2026 08:48
A frame's image is absolutely positioned against the frame, but nothing
in the frame's own markup made it a containing block - that came from
`*{position:relative}` in the shipped stylesheet. Read without that
sheet, every image resolved against the initial containing block and
covered the page at full size. The frame now states its own position.

ODF also places a frame by naming a side (`style:horizontal-pos`) rather
than an offset, which was ignored, so a centred image sat hard left.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QJ7vyWPCg1oaGoQ1dirNYT
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QJ7vyWPCg1oaGoQ1dirNYT

@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: 08cc2008d4

ℹ️ 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/style.hpp
andiwand and others added 3 commits August 11, 2026 09:05
…d one

`style:horizontal-pos="from-left"` names no side, so it read as nothing
and left a side inherited from the parent style standing. It now assigns,
so the frame's own declaration wins. No rendered output moves - the
renderer already ignores a side where an offset places the frame.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QJ7vyWPCg1oaGoQ1dirNYT
`GraphicStyle::horizontal_position` stopped at the C++ API; the python,
java and objc bindings still ended at `text_wrap`, so no binding consumer
could read it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QJ7vyWPCg1oaGoQ1dirNYT
gcc 14 flags the nullopt branch of the ternary as a maybe-uninitialized
read of the optional's payload, which -Werror turns into a build failure.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QVkpzsGS6YASMqm3NwmWib
@andiwand
andiwand merged commit 734b6cc into main Aug 11, 2026
36 checks passed
@andiwand
andiwand deleted the fix/frame-image-placement branch August 11, 2026 18:34
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