Split a container across a sheet, and place 4 260 fields that were never a splitting problem - #13
Merged
Merged
Conversation
The splittable predicate is now asked of the whole CHAIN rather than of one node, as pdf.js asks it (Subform[$isSplittable], template.js:4940-4975): the container above first, the recursion ending at the <template> element which answers yes, and every other kind of node — an <area> above all — inheriting the base answer, no. The keep intact clause belongs to a subform and not to an exclGroup, which was read at template.js:2405-2429 rather than assumed. What that predicate refuses is not dropped. pdf.js's checkDimensions returns true outright while the sheet has had nothing that moves in one piece (layout.js:266-268), and the one that claims that pass switches noLayoutFailure on before its own check runs, so it cannot fail either, and neither can anything inside it. Everything after it on the sheet is checked, and what does not fit sends the whole chain to the next content area — which is what splitting the containers above it means. There it is first in its turn and goes down whatever its height. So a container taller than a whole content area is no longer a refusal: it comes out one per sheet, overflowing, as pdf.js draws it. Over the corpus that places 4 260 more fields — 75 490 of 81 750 on 2 864 sheets — and every one of them is a positioned subform the size of a page, which no rule would ever have split. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The package comment and the README described a slice that did not split containers and reported a too-tall one unplaced. Both now say the rule as pdf.js states it — the chain, its four clauses, the <area> terminus, and the exclGroup's missing keep clause — and say plainly that what moves whole is still put on the paper, one per sheet, hanging over the bottom. The judge tables carry the new population, and the pairing audit with them: of 156 574 body boxes on the agreeing forms, 149 433 paired and NONE were dropped because the two sides counted differently. 460 of the 461 keyed but missing from pdf.js's dump are presence="hidden". 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.
The number, and the disagreement first
75 490 of the 81 750 body fields, on 2 864 sheets. Slice 5 placed 71 230 on
2 737.
"Most of the 6 208 want a container broken across a sheet" is not what they
wanted. All 4 214 of the largest bucket are positioned subforms, and a
positioned layout fails clause 2 of
$isSplittable— no rule anywhere wouldever have split one of them. They are whole-page subforms (
form1.Page1,topmostSubform.Page5), six to thirty points taller than the content area theyare drawn for, one per printed sheet, which is how LiveCycle writes a
multi-page form.
What was refusing them was not the absence of a splitter. It was a fit-check
this package applied and pdf.js does not: the first thing on a sheet that
moves in one piece is never measured against anything (
checkDimensionsreturns true while
firstUnsplittableis null,layout.js:266-268, and thenode that claims that pass switches
noLayoutFailureon before its own checkruns,
template.js:313-319). Because the first whole-page subform wasrejected, the flow never turned the page at all and every later one was
rejected against the same sheet.
us-irs__fw9came out on one sheet with321 fields unplaced, against pdf.js's six.
The reconciliation, field by field
Every field's disposition dumped before and after and paired on
(form, path)— 81 750 of them, no length mismatch:71 230 + 4 260 = 75 490. This is the first slice where the honest count did
not go down anywhere. 9 430 fields placed both times are on a different sheet
now, which is what turning pages that were never turned looks like.
lr-tb1 887 past the last sheet did not move, which is worth saying: turning more
pages exhausted no page set that was not exhausted before.
What is in it
The splittable predicate is asked of the whole chain.
flowable(n)became(*placer).splittable(n), which recurses upward as pdf.js does(
template.js:4943-4946) rather than relying on the chain being enforced byconstruction. Four clauses, read rather than assumed:
<template>,which answers yes (
template.js:5401-5403), and every other kind of nodeinherits the base answer, no (
xfa_object.js:214-216). The one thatmatters is
<area>: it holds body content, it is not a subform, and$getSubformParentdoes not skip it, so nothing inside an area is eversplit;
positionnor anything containingrow;<keep intact>isnone— and anexclGrouphas the same predicatewithout this clause (
template.js:2405-2429), checked there as asked;-tb/numberInLineclause is quoted in full in the doc comment andis not code, which is a measurement rather than an omission: no
container this package flows through has a layout ending in
-tb, so itcannot change an answer, and it needs
numberInLine, which thelr-tbslice will bring.
Clause 1 cannot be reached from the flow — the flow only descends through
containers that already passed — so
TestSplittabilityIsAskedOfTheWholeChainAndNotOfOneNodeis its witness, andthe guard for a flow that one day descends somewhere else. It pins all nine
answers,
<area>and theexclGroup's missing keep clause included.The pass, and what it means for splitting. The first container of each
sheet that moves in one piece is placed unconditionally, and nothing inside it
is checked either (
noLayoutFailureis cleared only on the way out of thatsame node,
template.js:5075-5178). Everything after it on the sheet ischecked, and what does not fit sends the whole chain to the next content area —
which is what splitting the containers above it means. There it is first in its
turn. The pass is handed out once per sheet, not once per content area:
pdf.js clears
firstUnsplittablein the page loop, before the loop over thatsheet's content areas (
template.js:5536-5538).tooTallForAPageis gone, because pdf.js never refuses a container for beingtoo tall.
The judge, with the pairing re-audited
The pairing itself was re-audited, not only the rate, because splitting is
exactly the change that alters which boxes are comparable. Of 156 574 body
boxes on the 469 agreeing forms: 149 433 paired, 6 680 unnamed and so never
keyed, 461 keyed but absent from pdf.js's dump — 460 of those 461 are
presence="hidden", which pdf.js emits asdisplay:noneand the dump doesnot carry — and 0 dropped because the two sides produced a different number
of boxes for one key. That last zero is the one that matters: splitting
created no new mispairing.
Four forms disagree on the sheet count, and two are new.
us-opm__sf813andus-opm__sf39aare the same two as before and are notpagination: they have a positioned outermost subform, whose fit-check
(
layout.js:355-364) has never been done here.us-uscis__i-600aandus-uscis__i-821are newly visible —i-600acame out on one sheet beforethis change against pdf.js's fourteen, and comes out on thirteen now. In both,
every box agrees up to a
<breakBefore targetType="pageArea" startNew="1"/>and is one sheet behind after it. That is a question about breaks, not about
splitting, and it is not diagnosed to the line here.
What none of this covers, unchanged: where inside a container the children
ended up; borders, margins and insets on positioned layouts; anything under a
rotated ancestor; where a break inside a container that moves whole would have
sent the page; real per-glyph advances, which neither side has. Still 77 of 560
forms pdf.js cannot lay out.
Gate
go vet,gofmt -lempty, exactly 100% statement coverage,-race, ninecross-compile targets,
CGO_ENABLED=0,GOWORK=off, all against Go 1.27.1 viaGOTOOLCHAIN.