# Tagged-PDF boundary corpus The 26 tagged PDFs and 4 context-only PDFs are self-authored. They contain Standard-14 Helvetica text and vector paths, with no third-party document content. Regenerate the deterministic files and hashes with: ```sh python3 tests/fixtures/pdf/generate_headings.py ``` `manifest.json` records SHA-256, byte size, authored expectations and PDF-point regions `[left, bottom, right, top]`. Regions follow the source placements, font sizes and transforms; they are not copied from renderer output. None of the tagged files has bookmarks, so an outline cannot conceal missing tag extraction. `test_pdf::taggedBoundaryCorpus` checks every tagged file's hash, page count, title, level, structure order, destination precision, fallback reason and bbox. Exact targets must map inside the page and round-trip within 0.5 pt at scale 2 for user rotations 0, 90, 180 and 270 degrees. The PDFium drawing engine still provides character boxes; a shared worker-only qpdf context now supplies the source-qualified logical structure. | Files | Authored condition and expected behavior | | --- | --- | | `transformed-form.pdf` | Page wrapper MCID plus Form-owned MCR. Exact heading in `[70,102,240,130]`. | | `rotated-tags.pdf` | Rotate 90 and offset CropBox. H3 is drawn first but H1 precedes it in structure order; exact targets follow structure order. | | `cross-page-structure.pdf` | One H1 has interleaved nested Span and direct MCR children on two pages. Page-local fragments preserve K order without mixing reused MCID 0. | | `vector-heading.pdf` | H4 vector with ActualText but no glyph bbox. Title retained with page precision and a coordinate reason. | | `form-only-structure.pdf` | Only the Form has StructParents. One exact H2, `Form only heading`, in `[50,125,190,147]`. This is now a positive extraction case. | | `form-vector-mcid-collision.pdf` | Page vector heading and unrelated Form text both use MCID 0. Keep the heading title at page precision; never borrow Form paragraph bounds. | | `named-property-rolemap.pdf` | Form BDC references a named property and a custom RoleMap name. Extract actual text without a supplied title. | | `nested-form-matrix.pdf` | Nested Forms with a nonidentity Form Matrix and independent caller CTMs. Exact target uses PDFium page-space character boxes once. | | `different-form-same-mcid.pdf` | Two uniquely positioned Forms reuse MCID 0, with reverse structure order. Keep separate exact headings in that order. | | `ambiguous-form-matrix.pdf` | Different Forms share matrix and MCID signature. Use titles and explicit page precision instead of relying on enumeration order. | | `repeated-form.pdf` | One source Form is invoked twice. Preserve the heading at page precision with a repeated-Form reason. | | `unused-form-resource.pdf` | Uninvoked Form remains in Resources. It must not create an extra heading. | | `inline-image-before-form.pdf` | Inline image precedes a used Form. Skip image pixels and retain the exact heading. | | `cyclic-form.pdf`, `cyclic-rolemap.pdf`, `cyclic-parent.pdf`, `cyclic-children.pdf`, `cyclic-number-tree.pdf` | Explicit structure limitation, no fabricated destination. | | `broken-mcr-page.pdf`, `broken-mcr-stream.pdf`, `annotation-owned-mcr.pdf`, `broken-graphics-stack.pdf`, `conflicting-parent-tree-owner.pdf` | Invalid or unsupported ownership/graphics relation. Explicit limitation, no borrowed exact text or position. | | `stream-quota-at-limit.pdf`, `stream-quota-over-limit.pdf` | Compressed operator data expands to exactly 16 MiB or one byte more. The first succeeds; the second is limited, truncated and incomplete. | | `bounded-heading-response.pdf` | 70 vector headings have long Japanese ActualText. Return a nonempty validated prefix within 512 KiB CBOR and mark the response incomplete. | Context-only cases exercise the shared parser separately from PDFium: - `context-deep-tree.pdf`: a depth failure must remain sticky on retries; the valid later sibling must never become page zero. - `context-warnings-32.pdf` and `context-warnings-33.pdf`: one diagnostic occurs during initial parse and the remainder during lazy object reads. The 32-line boundary succeeds; crossing it remains limited after a new operation begins. - `context-warning-bytes.pdf`: one initial diagnostic exceeds 64 KiB. Opening stops without emitting its contents. The existing `../missing-first-page.pdf` separately checks that qpdf does not repair `[null, page]` into a shortened page list before validation. This caught the qpdf 12.4.1 `setMaxWarnings` startup side effect; diagnostics now use a bounded private sink instead. The production worker suite uses the real sandbox, IPC and font broker for Form-only/nested exact destinations, ambiguous/repeated page fallbacks, quota, partial response and cancellation. A temporary encrypted version checks wrong password rejection, the same borrowed QFile and unchanged source bytes. Worker cases compare original SHA-256 before and after. See the [recorded Linux results](../../../results/pdf-structure/README.md). Annotation-owned OBJR/StmOwn structures remain an explicit limitation. Repeated or ambiguous Form instances deliberately retain page precision. These synthetic cases do not establish native Windows behavior or general conformance for every producer's tagged PDFs.