Skip to content

Read where an annotation sits in its document's structure tree - #100

Merged
bobsingor merged 1 commit into
embedpdf/mainfrom
embedpdf/feature/structure-position
Nov 1, 2026
Merged

bobsingor merged 1 commit into
embedpdf/mainfrom
embedpdf/feature/structure-position

Conversation

@bobsingor

Copy link
Copy Markdown
Contributor

Adds EPDFAnnot_GetStructurePosition(): where an annotation sits in its document's logical structure (the tags, ISO 32000-2 14.7), as the index of each step from the structure tree root down to its object reference (/OBJR). Compared index by index, two positions give the tags' reading order, which a page's /Tabs /S asks annotations to take focus in. Most tagged forms ask for it: the USCIS forms, Acrobat's, Word's, a browser's print.

  • Found from the annotation up: its /StructParent, the parent tree, then each element's /P. No page is loaded, and nothing else in the tree is read.
  • An annotation the tree doesn't reach has no position: no /StructParent, a parent tree that doesn't lead to an element listing it, or a broken way up (a missing /P, a parent that doesn't list its kid, a cycle, more than 256 levels).
  • PDFium's own structure tree API can't answer this. FPDF_StructTree_GetForPage() needs the page loaded, builds only from the page's content (a /Form element holding just a widget's /OBJR isn't in it), and can't read an object reference's target.

On the USCIS I-140, all 33 page-1 widgets resolve, and their positions give the form's printed order. Its /Annots order starts with a barcode and puts the attorney's box after Part 1.

Tests

  • structure_position.in: a nested parent tree, a /K that is one kid, and an /OBJR after a marked-content kid; plus untagged, unlisted, cyclic and missing entries.
  • Read from raw and loaded pages, a buffer shorter than the position, an untagged document.
  • The C API list.
  • Layer mode: the reads write nothing.

The engine side, structurePosition on every annotation and tabOrderOf(), is in embedpdf/embed-pdf-viewer feature/structure-tab-order. It needs this released and pinned.

EPDFAnnot_GetStructurePosition() gives an annotation's place in the logical structure (the tags, ISO 32000-2 14.7): from the structure tree root down to its object reference (/OBJR), the index of each step among its parent's /K kids. Compared index by index, two positions give the tags' reading order, the order a page's /Tabs /S gives its annotations focus in, which most tagged forms ask for (the USCIS forms, Acrobat's, Word's, a browser's print). It's found from the annotation up: its /StructParent, the parent tree, then each element's /P, so no page is loaded and nothing else in the tree is read. An annotation the tree doesn't reach has none: no /StructParent, a parent tree that doesn't lead to an element listing it, or a broken way up (a missing /P, a parent that doesn't list its kid, a cycle, more than 256 levels).

PDFium's structure tree API can't answer this: FPDF_StructTree_GetForPage() needs the page loaded, builds the page's tree only from its content (a /Form element holding just a widget's /OBJR isn't in it), and has no way to read an object reference's target.

Tests: structure_position.in (a nested parent tree, a /K that is one kid, an /OBJR after a marked-content kid; untagged, unlisted, cyclic and missing entries), read from raw and loaded pages, a buffer shorter than the position, an untagged document; the C API list. Layer mode: the reads write nothing.
@bobsingor
bobsingor merged commit 28b8b80 into embedpdf/main Nov 1, 2026
1 check passed
@bobsingor
bobsingor deleted the embedpdf/feature/structure-position branch November 1, 2026 23:00
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