Skip to content

Tag an inline image or form field where it falls among its line's text (#406) - #509

Open
jakejackson1 wants to merge 1 commit into
feature/pdfua-1-supportfrom
fix/406-pdfua-reading-order
Open

jakejackson1 wants to merge 1 commit into
feature/pdfua-1-supportfrom
fix/406-pdfua-reading-order

Conversation

@jakejackson1

Copy link
Copy Markdown
Member

Under PDF/UA, an image, barcode, list marker or form field in a line was tagged out of reading order. This fixes all three items in #406.

Cause. finishFlowingBlock() and WriteFlowingBlock() drew a line's text chunk by chunk, then drew the line's objects afterwards in a second pass (printobjectbuffer()). That caused three problems:

  1. The paragraph's marked content was still open at that point, so an image's /Figure <</MCID n>> BDC sat inside the paragraph's MCID. A barcode's Figure and a list marker's Lbl did the same.
  2. In content order, every object came after all of the line's text. An active form field's Form element is placed by how much content its parent had when the field was added. So Start <input type="checkbox"> Check read as "Start Check, checkbox".
  3. When the second pass ran, the structure stack and the link state were whatever the last chunk had left. An image inside <a href> got a Figure beside the Link, not inside it. If text followed the link, the image's link annotation lost its Link too, and the document failed with the "wraps no accessible content" exception.

Fix. Under PDF/UA, an object that marks its own content (image, barcode, text circle, a list marker with its Lbl, input, textarea, select) is now drawn right after its own chunk, by printLineObject():

  • The text's marked content is closed first. The next text chunk opens its own again, as it already does after an inline element.
  • The element the chunk belongs to (the inline element restoreFont() restores, otherwise the block's element) is pushed onto the structure stack while the object draws. Whatever the object tags therefore goes inside it, e.g. a Figure inside the Link around it.

The per-chunk marking that was copied in both loops is now markLineChunk().

Decisions:

  • An object's chunk can still draw a span's background or border before the object itself. When it does, that drawing stays in the text's marked content, as before. Otherwise an object chunk opens no marked content, so a line that starts with an image gets no empty paragraph MCID.
  • Inside an artifact nothing changes. Objects are still drawn after the text, within the artifact's marked content, because closing it would leave them unmarked.
  • Documents without PDF/UA are unaffected. The only snapshot that changes is pdfua: its bytes differ and its pages are identical, and it was refreshed with composer snapshot:update pdfua.

How this interacts with #496 (#404). #496 closes the block's marked content around a static form field inside printobjectbuffer() and reopens it afterwards. This PR does not touch that code. On the in-line path, the marked content is already closed before printobjectbuffer() runs, so #496's close does nothing and it does not reopen. #496's Form value element then lands in the paragraph between the text around it. I test-merged this branch with #496, #402 and #405: there were no conflicts, and the Ua suite (veraPDF included) passes. <p>Start <label><input type="checkbox" checked> I agree</label> end</p> then reads P [MCID 0, Form (☒), MCID 2]. Whichever PR lands second rebases.

Tests. tests/Mpdf/Ua/InlineObjectReadingOrderTest.php covers:

  • an image between text, on a single line and on a wrapped line
  • an image in a link (the Link holds the Figure and its OBJR, with text after it)
  • an active checkbox and text field between their label text
  • an image in a table cell, a barcode and list markers

The tests assert each element's /K order and that no MCID-bearing marked content opens inside other marked content. That check is assertNoNestedMarkedContent(), now in PdfUaTestCase. All five tests fail without the fix. The full suite, composer cs, PHPStan and the veraPDF conformance tests pass locally.

Fixes #406

🤖 Generated with Claude Code

Under PDF/UA an object in a line is drawn as its chunk is reached rather than after the
line's text, with the text's marked content closed around it. Its Figure or Form is then
read between the text before and after it instead of nested inside the text's MCID, and
what it tags goes in the element its chunk is in, so an image in a link is the Link's
content.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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