Skip to content

Judge where a box goes across a line, and say what a property still cannot see - #16

Merged
tannevaled merged 3 commits into
mainfrom
intra-line-verification
Sep 4, 2026
Merged

Judge where a box goes across a line, and say what a property still cannot see#16
tannevaled merged 3 commits into
mainfrom
intra-line-verification

Conversation

@tannevaled

Copy link
Copy Markdown
Contributor

The blind spot is not blind any more: pdfium computes intra-line geometry, and it can be driven

Every release since v0.5.0 has carried the same sentence — the reference emits
no coordinate inside a line, so intra-line placement is unchecked in both
directions
. This closes it, and the disagreement goes first.

pdfium can be driven, and the negative I expected is not the answer

Its unit tests pin nothing: no test file anywhere in the tree references
CXFA_ContentLayoutItem, GetAbsoluteRect or CFX_RectF, its one XFA layout
test (cxfa_layoutitem_embeddertest.cpp) counts pages, and only 2 of the 116
fixtures under pixel/xfa_specific even contain the string lr-tb. Nothing
there is portable.

But CalculateRowChildPosition (cxfa_contentlayoutprocessor.cpp:2028-2160)
assigns every item on a line an x and accumulates its width, and
CXFA_ContentLayoutItem::GetAbsoluteRect adds the offsets above it. None of it
is exported — no entry point in public/ returns a layout item's rectangle,
and FPDFAnnot_GetFormFieldAtPoint reads the PDF's own AcroForm rather than
the XFA layout — so the dump comes from a source file added to pdfium's
embedder tests, built with pdf_enable_xfa. The probe is a nine-line walk
around GetAbsoluteRect; the recipe is in /Users/Shared/xfapdfium/probe.

It lays out 559 of the 560 corpus forms. pdf.js lays out 483. The one it
does not is us-uscis__i-956h, which aborts it (SIGTRAP) and is also one of
the 77 pdf.js cannot do.

What it says

paired agree on x
leaves under a container that wraps onto lines 959 959 — 100.00%
leaves under a table row 19 516 19 448 — 99.65%
leaves under neither — the control 167 632 160 022 — 95.46%

Leaves, because both sides emit a rectangle for one and a container placed at
the wrong x puts every leaf under it at the wrong x. The control is carried
beside the two because a disagreement under a line means nothing on a form
where x does not agree anywhere: 461 of the 559 forms agree on x for every
control leaf.

The 68 row disagreements split cleanly on that. 64 are on
ca-cra__rc1-fill-11-25e, where 552 of 804 control leaves disagree too — x on
that form is not comparable at all and none of it is the row's. The other 4 are
on fr-cerfa__cerfa_12818, whose control agrees entirely, and they are one
open question
: the row puts the cell Bouton at 28.3465, which is where
pdfium puts it, and pdfium then places the positioned children two levels
inside it 3.6 pt further right than their written x. I have not found the line
that adds the 3.6 and will not name a cause without one.

Zero disagreements under a wrapping container, of either kind.

pdfium runs the form's scripts and measures text with real fonts; this package
does neither. So y (44.53% under a line, 76.53% under a row) and which sheet a
box landed on are informative rather than a verdict. X survives because a
positioned box's x is its written attribute and a line member's is arithmetic
over written widths.

The property checks, and their population

Asked anyway, because a judge that agrees can still be wrong in the same way
twice, and because they cover the rl-tb arm no form exercises.

Which line a box went on comes from the packing and which cells are one row
from the tree, never from the coordinates being checked. They are asked twice:
of the packing in the container's own coordinates, where the room across the
page is known exactly, and of where the members came out on the paper — which
is the only thing that sees lineX, the offsets of the containers above, and
the second route a member alone on its line takes through the flowing chain.

THE PACKING     790 wrapping containers, 791 packings, 982 lines, 2 374 boxes
                791 of those lines hold MORE THAN ONE box
THE PAPER       972 lines, 2 361 members placed, 2 178 with a NEIGHBOUR
              3 820 table rows, 19 073 cells placed, 18 738 with a NEIGHBOUR
                 12 members on more than one sheet, not compared; 4 on no sheet
VIOLATIONS      2

Both are the same thing and neither is a placement fault. On
ca-cra__t777-fill-24e and -25e, the header row's first column is 33 pt and
Cell1 holds a button field written w="12.7mm" — 36 pt. The cell after it
begins at 24 + 33 = 57, which is right; the field overruns by 3. pdfium
places it identically
: Cell1 at x=24.0009 w=33.0000, Footnote5 at
x=24.0009 w=36.0000, Cell2 at 57.0009. The template overflows its own
column and both implementations reproduce it.

What is STILL not covered, in the same terms

  • A line packed in the wrong ORDER at the right widths satisfies every
    property. Order is checked against DOCUMENT order, so a swap would be caught
    — but the right boxes on the wrong LINE, each line well formed, would not.
    Against pdfium that is covered where the leaves pair; where they do not it is
    not.
  • rl-tb and rl-row occur zero times in 560 templates. The property
    checks carry the arm; nothing measures it.
  • hAlign inside a line. pdfium bands a line into left, centre and right
    groups by each item's hAlign and packs within the band; pdf.js maps
    hAlign to alignSelf, which in a row flexbox is the CROSS axis, so it
    moves a box down rather than across. This package follows neither. Measured:
    2 of 2 374 line children write an hAlign at all, both center, both on
    us-uscis__g-1055. Named rather than changed, because no judge separates the
    two references there.
  • A hidden box on a line. The packer gives one no width and puts it at the
    cursor; 0 of the 2 374 are hidden, so nothing measures that branch either.
  • 785 keys this package emits that pdfium does not, and 10 186 where one side
    emitted a key more than once, are dropped rather than guessed at. Under a
    line that is 35 and 190 against 959 paired; under a row, 141 and 230 against
    19 516.

The change to the package

Three lines: Place is now a wrapper over placeForm, which hands back the
placer it worked in. Which LINE a box went on is not derivable from the boxes
afterwards, and reading it off the coordinates would be asking the answer to
grade itself.

Gate: 100% of statements, go vet, gofmt -l empty against Go 1.27.1 via
GOTOOLCHAIN, -race, nine cross-compile targets, CGO_ENABLED=0,
GOWORK=off. The whole corpus suite, both judges included, is green.

🤖 Generated with Claude Code

tannevaled and others added 3 commits September 4, 2026 15:16
pdf.js emits no coordinate inside a line — an lr-tb container's children
go in a flexbox div of class xfaLr, a table row's cells in one of class
xfaRow — so intra-line placement has been unjudged in both directions
since v0.5.0. This asks what a correct line must satisfy instead.

Which line a box went on comes from the packing and which cells are one
row from the tree, never from the coordinates being checked. The
properties are asked twice: once of the packing in the container's own
coordinates, where the room across the page is known exactly, and once
of where the members came out on the paper, which is the only thing that
sees lineX, the offsets of the containers above and the second route a
line member alone on its line takes through the flowing chain.

The census is reported beside the violations because a check that
compared nothing reports no violation either.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
pdf.js hands a line to CSS flexbox and emits no coordinate inside one, so
this has been unjudged in both directions since v0.5.0. pdfium computes
the answer — CalculateRowChildPosition walks a line assigning each item
an x — and exports none of it: no entry point in public/ returns a layout
item's rectangle, and pdfium's own suite asserts no coordinate anywhere.
So the dump comes from a source file added to its embedder tests, built
with pdf_enable_xfa; the recipe is in /Users/Shared/xfapdfium/probe.

559 of the 560 forms lay out, against pdf.js's 483.

Leaves are compared, because both sides emit a rectangle for one and a
container placed at the wrong x puts every leaf under it at the wrong x.
The control — every leaf under neither a line nor a row — is carried
beside the two populations, because a disagreement under a line means
nothing on a form where x does not agree anywhere.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@tannevaled
tannevaled merged commit 7251c2f into main Sep 4, 2026
1 check passed
@tannevaled
tannevaled deleted the intra-line-verification branch September 4, 2026 13:33
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