Settle t657 against pdfium, stop turning the sheet for a hidden container's break, and place the last 24 - #18
Merged
Merged
Conversation
pdfium gates the whole of break handling on presence: ProcessBreakBeforeOrAfter returns nullopt when the break's container does not require space (cxfa_viewlayoutprocessor.cpp:922-928), and the forced page end that would otherwise catch an overflowing child is gated the same way (cxfa_contentlayoutprocessor.cpp:1922-1927). PresenceRequiresSpace is true only for "visible" and "invisible" (cxfa_node.cpp:5348-5353). It is the other half of a rule this package already kept: a hidden container is given no room by the flow above it, and a container that takes no room has no reason to turn the page. One instance in 560 templates, and it is a control rather than a theory. us-irs__f4797 writes three page-sized subforms under a tb root, the third presence="hidden" carrying <breakBefore targetType="pageArea" startNew="1"/>. pdfium lays it out on 2 sheets; this package made 3. After this, 2 — and all six leaves under the hidden subform agree with pdfium on x AND y to the point, at y=810.5301, 810.0000, 821.9990, 858.4554, 857.9991 and 882.0000 on an 11-inch sheet. pdf.js is no help here: it cannot lay the form out at all. Corpus: 3091 sheets to 3090. No other form moves, no field changes hands, and the 72 unplaced are unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…st 24
A container anchored by a corner other than its top left is moved by its own
size, and a container that writes no size is as tall as its contents. That
measurement was named and left in v0.13.0 as a new capability rather than a
fix. It is not new: [placer.heightOf] already computes exactly the number
pdfium uses. Its positioned arm is max(y + h) over the children and
[placer.measure] adds the container's own margin, which is
DoLayoutPositionedContainer's fContentCalculatedHeight
(cxfa_contentlayoutprocessor.cpp:1192-1204) handed to
CalculateContainerComponentSizeFromContentSize (:543-560). It was only never
asked for at the anchor. CalculatePositionedContainerPos (:588-650) then takes
the anchor off it, which [transformedBBox] already did.
Width is a different quantity and is still refused. Only an anchor along the
middle or the right edge moves a box by its width, no container of the corpus
is one, and nothing here computes a container's content width — so it is named
rather than guessed at. A turned container is refused before its size is asked
for at all, which is the true reason where both apply.
## What it is worth
unplaced over the 560 forms 72 -> 48
anchored by a corner 24 -> 0
page area never used 48 -> 48 (unchanged)
fields placed 85 446 -> 85 455
draws placed 155 995 -> 156 010
All 24 are one node: ca-cra__t183-fill-25e's
<subform name="Part_A" anchorType="bottomLeft" y="55.034mm"> with no w and no
h. Its children reach 13.758mm + 8.467mm = 22.225mm = 63pt; 55.034mm is 156pt;
156 - 63 = 93, and the content area's 18 makes 111.
pdfium puts Part_A_Heading at y=111.0019. So does this, and so do the other 23:
every one of the 24 agrees with pdfium's dump on the sheet, x, y, w and h, to
the last place a float carries. Five of them pair only by hand — pdfium spells
them Part_A[0].SIN_Line4[1] and so on, indexing a name that also occurs deeper
in the same subtree, which the judge's somPath rewrite does not reproduce; it
drops such keys rather than mis-pairing them, so the agreement rate was never
wrong, only blind to these five.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tannevaled
added a commit
that referenced
this pull request
Sep 5, 2026
* Bring the corpus census back to what the corpus says doc.go's census block quoted 81 734 fields placed on 3 090 sheets, and both numbers went stale before v0.16.0: every field of every body has been placed since #18, and the corpus has come to 3 088 sheets since #21. The third line counted the 16 fields that were left over, and there are none. Measured by TestPlacementOverTheCorpus on the 560-template corpus, which is where all four numbers come from and which reports them itself. The line that replaces the leftover count is the one thing in the block that is still not in one-to-one correspondence with the paper: 12 elements of the page areas' own furniture belong to a page area no sheet of their form ever is. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Reach a page area a break names, whose <occur max> is spent Six forms of the corpus lay their body on sheets pointing the wrong way. ca-cra t2042, t2121 and t2125, each in two years, write a portrait Pg1 with <occur max="1"/> and a landscape page area beside it, and every body subform carries <breakBefore targetType="pageArea" target="Pg1" startNew="1"/>. This package refused the target once Pg1's max was spent and let the sequence answer instead, which is the landscape page area — 612 points tall where the form wants 792 — so 403 leaves fell off the bottom of the paper. pdfium reads a page area's <occur max> in exactly one place: the branch of GetNextAvailPageArea that REPEATS the page area in hand (cxfa_viewlayoutprocessor.cpp:1552-1578). Every other route runs through FindPageAreaFromPageSet_Ordered, which scans the siblings after the page area in hand FOR THE TARGET and, finding none, starts the page set again from its first child and takes the target there (:1582-1607). That function never reads a page area's occur at all; the only max it reads is the page SET's (:1329-1341). An instrumented pdfium says the same at runtime, on t2125: BREAKNODE breakBefore on subform:Page2 target="Pg1" resolved=pageArea:Pg1 | GNAPA advancing: scan siblings after pageArea:Pg1 | | FPAS_ORD startAfter=pageArea:Pg1 target=pageArea:Pg1 (no match) | | FPAS_ORD startAfter=- target=pageArea:Pg1 (restart) | | GNAPA -> pageArea:Pg1 (RESTART of page set pageSet:) So a page area's max bounds how often the SEQUENCE runs into it and not how often a break may ask for it by name. This package already held the other half of that rule — starting a page set again forgets the counts of the page areas below it, see pager.cleanKids — and pager.reach is that same restart, asked for by a target rather than by running off the end of the set. What is NOT changed is the break that names nothing. Two thousand of the corpus's two and a half thousand breaks are <breakBefore targetType="pageArea" startNew="1"/>, whose page area is only the one in hand standing in for a target; pdfium's scan accepts any page area there, so the sequence moves on and a max still means something. Getting that wrong first cost 2 367 leaves on four other forms, which is why breakTo now carries whether the template NAMED it. Measured over the 559 forms pdfium lays out, hidden excluded from both sides: before after body leaves off the paper 1378 1000 forms with one 37 34 sheets whose SIZE disagrees 13 7 ...of those, orientation 6 0 agree on x 173806/177676 unchanged agree on sheet+y 162200/177676 unchanged corpus sheets 3088 3088 Six forms move and none is worse. t2125-24e 129 -> 0, t2042-24e 94 -> 0, t2121-24e 17 -> 0, t2125-25e 178 -> 66, t2121-25e 96 -> 71, t2042-25e 67 -> 66; the remainder on the 25e forms is this package's text measurement, not this rule. t2125-25e's page-area sequence is now pdfium's sheet for sheet. The judge did not move by one leaf, and that is worth writing down: it compares x and sheet+y, so a leaf at the same place on a sheet of the wrong ORIENTATION counts as full agreement. Nothing in this repository compares a sheet's size. Nine forms in all carry a pageArea <occur max> a break names — the six above, ca-cra t1135 in two years and us-uscis i-612 — and 60 carry one at all. Two tests changed their expectation with the rule and are renamed for it, and three are added: the untargeted break that must still move on, a page set whose own <occur> is spent, and a <pageArea> written outside every page set, which a target can reach by id and which has no page set to start again. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What I could not settle
Why pdfium's own pagination is what it is for the twenty subforms it piles up. I settled that it does it and why the form makes it do it — the mechanism is three lines of pdfium quoted below — but I ran no controlled pdfium experiment. The dump was read, not re-produced under a variant, so the causal chain rests on pdfium's source and on the geometry agreeing with it, not on a subject I moved.
Where a hidden container's leaves belong. pdfium places them at the cursor, off the paper if that is where the cursor is, and
us-irs__f4797's six agree with it to the point. Whether that is right — as against reporting them unplaced — is not something either reference settles, and this changes nothing about it.The remaining nine sheet-count disagreements with pdfium are untouched and undiagnosed.
us-uscis__g-1055(64 against 96) is the loudest of them now.t657: not a layout disagreement at allOurs 27, pdf.js 27, pdfium 7 — and two references agreeing settled nothing. What settled it was that the body leaf sets are identical: 2 300
(kind, path)pairs each side,diffempty, and every one agrees on x to the point. The only count difference is 20 extra copies of the page area's own furniture field, one per extra sheet.So it is neither a repeat count nor a fit.
form1islayout="tb"with 27 page-sized children, each exactly the content area. pdfium's sheets:Page1…Page4QuerySheetSub2015a…Sub2024b— all twentyPage26,Page27774 is the bottom edge of the content area. The 1 701 leaves under those twenty are at exactly our y + 756.0, every one, reaching y=1530 on a 792-point sheet.
Every one of those twenty, and no other top-level subform, carries an
initializescript that writesform1.Sub20NNx.presence = "hidden".Page1…Page4,QuerySheet,Page26andPage27have zero.presenceassignments anywhere in the template. pdfium is built withpdf_enable_v8and runs them; hidden then does three things:PresenceRequiresSpace()is true only forvisibleandinvisible(cxfa_node.cpp:5348-5353);ProcessBreakBeforeOrAfterreturnsstd::nulloptwhen the break's container does not require space (cxfa_viewlayoutprocessor.cpp:922-928), so nineteen<breakBefore targetType="pageArea" startNew="1"/>never create a page;cxfa_contentlayoutprocessor.cpp:1922-1927), so a cursor already past the bottom does not end the sheet either.Cursor never advances, breaks never fire. 7 is right for the document as its scripts leave it; 27 is right for the document with scripts unrun, which is what this package and pdf.js lay out. Nothing to change in the placer for
t657.The control the corpus handed back: one form, no scripts needed
Censused: exactly one container in 560 templates writes
presence="hidden"and carries a live break.us-irs__f4797, three page-sized subforms under atbroot, the thirdpresence="hidden"with<breakBefore targetType="pageArea" startNew="1"/>. pdfium: 2 sheets. This package: 3. pdf.js: cannot lay the form out at all, so pdfium alone.Followed: pdfium, by the standard that decided
px,mp,=0mm, the per-run occur bound and the root's absentlayout. It is also the other half of a rule this package already kept — a hidden container is given no room by the flow above it, and a container that takes no room has no reason to turn the page.After: 2 sheets, and all six leaves under the hidden subform agree with pdfium on x AND y to the point — 810.5301, 810.0000, 821.9990, 858.4554, 857.9991, 882.0000 on an 11-inch sheet.
Corner anchors: 24 of 24, and the number is 72 → 48
Not a new capability after all.
heightOfalready computes exactly pdfium's number — its positioned arm ismax(y + h)over the children andmeasureadds the margin, which isDoLayoutPositionedContainer'sfContentCalculatedHeight(cxfa_contentlayoutprocessor.cpp:1192-1204) handed toCalculateContainerComponentSizeFromContentSize(:543-560). It was never asked for at the anchor.All 24 are
ca-cra__t183-fill-25e's<subform name="Part_A" anchorType="bottomLeft" y="55.034mm">with now, noh. Children reach 22.225mm = 63pt; 55.034mm = 156pt; 156 − 63 = 93, plus the content area's 18 = 111. pdfium putsPart_A_Headingat 111.0019. So does this — and so do the other 23, on sheet, x, y, w and h, to the last place a float carries.Width is still refused. Only an anchor along the middle or the right edge moves a box by its width, no container of the corpus is one, and nothing here computes a container's content width.
The judge, re-audited because the population moved
24 boxes entered it. The pdfium control goes 167 632 → 167 651 paired and 163 753 → 163 772 agreeing: +19 and +19, reconciling exactly.
The other five pair only by hand. pdfium spells them
Part_A[0].SIN_Line4[1]…[1], indexing a name that also occurs deeper in the same subtree, whichsomPath's rewrite does not reproduce. The judge drops such keys rather than mis-pairing them, so the agreement rate was never wrong — only blind to those five. Checked by hand: all five agree with pdfium to float precision.Every judge still passes: pdf.js placement 176/176 exact, container heights 7 794/7 794, pagination 151 309 boxes all on the same sheet across 476 forms, pdfium x under a table row 19 522/19 522 and under a wrapping container 959/959.
Gate
100% of statements,
go vet,gofmt -lempty,-race, nine cross-compile targets — all under Go 1.27.1 viaGOTOOLCHAIN,CGO_ENABLED=0,GOWORK=off.🤖 Generated with Claude Code