Draw what a document says it shows, and no more - #18
Merged
Conversation
Optional content is how a document says that some of what it contains is a layer, and which layers are on when it is opened. A page's content is not a promise that all of it is to be drawn. None of it was read here: every layer was drawn, whatever the document said. What is read is the default configuration, /OCProperties/D — /BaseState, /ON and /OFF — and then the three places a layer is named: an /OC on a form or image XObject, an /OC on an annotation, and BDC /OC around a run of marks in a content stream, looked up through the page's /Resources/Properties or written out in place. A membership dictionary combines several groups under /P, whose four policies are all implemented. Options.AllLayers asks for the old behaviour, for a tool with a layer panel or an archive comparing what a file holds against what it displays. WHAT THE CORPUS SAYS, WHICH IS LESS THAN IT FIRST APPEARED Optional content is common. 275 of the 1 633 real forms carry an /OCProperties, as do 151 of 6 667 arXiv files; 161 of those forms hide at least one group, and all 123 that name a /BaseState name /OFF, which says nothing is shown unless it is listed as on. 155 XObjects and 1 373 annotations on the forms' first three pages carry an /OC of their own. Reading all of that moves not one pixel. Walking every page of all 8 300 files and counting the operators that mark the page, **not one falls inside a layer the document's own configuration hides**: the layers are declared and left empty, which is what an authoring tool leaves behind. Rendering the 1 633 forms before and after gives identical pages and the same total ink to the unit — 88 770 158 either way. One arXiv figure came closest: 2603.24071/Figure2.pdf declares five groups, hides all five, and does name one of them in a BDC. The renderer identifies that section as hidden — and the section contains none of the page's 165 marking operators. Empty as well. So this is not a fix for anything the corpus shows going wrong, and it is not written up as one. It is here because a document's statement about what it shows should be obeyed, and because this corpus is forms and figures: layers are how a CAD drawing, a map, a multilingual overlay and a print-only mark are written, and none of those are in it. The measurement says the corpus does not exercise the mechanism, which is a different claim from the mechanism not mattering. The tests are therefore the only thing holding the behaviour up, and they are written accordingly: a page for every path, and the policies unit by unit. TWO DECISIONS WORTH ARGUING WITH /OFF wins over /ON where a document names a group in both. The specification leaves it open; hiding is the safer reading, since showing what a document tried to hide is the worse mistake. A /VE visibility expression is not read. It takes precedence over /P where a document has both, and not one file in the corpus carries one — so reading it would be guesswork tested against nothing. A document that has one is treated as visible, which is what this did before. Suppression is of marks only. A clip narrowed inside a hidden layer still narrows, because clipping is not marking; the operators that move the text pen still move it. Otherwise a hidden layer would shift everything after it. readOptional drops the error from Catalog(): reader.Open refuses a file whose trailer does not lead to a catalogue, so it cannot happen. An unreachable branch cannot be tested, and an untested branch in the code that decides what a reader is shown is worse than no branch — so it is gone rather than covered by a contrived case. 100% statement coverage, go vet and -race clean, nine cross-compile targets. 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.
Optional content is how a document says that some of what it contains is a
layer, and which layers are on when it is opened. A page's content is not a
promise that all of it is to be drawn. None of it was read here: every layer
was drawn, whatever the document said.
What is read is the default configuration, /OCProperties/D — /BaseState, /ON
and /OFF — and then the three places a layer is named: an /OC on a form or
image XObject, an /OC on an annotation, and BDC /OC around a run of marks in a
content stream, looked up through the page's /Resources/Properties or written
out in place. A membership dictionary combines several groups under /P, whose
four policies are all implemented. Options.AllLayers asks for the old
behaviour, for a tool with a layer panel or an archive comparing what a file
holds against what it displays.
WHAT THE CORPUS SAYS, WHICH IS LESS THAN IT FIRST APPEARED
Optional content is common. 275 of the 1 633 real forms carry an /OCProperties,
as do 151 of 6 667 arXiv files; 161 of those forms hide at least one group, and
all 123 that name a /BaseState name /OFF, which says nothing is shown unless it
is listed as on. 155 XObjects and 1 373 annotations on the forms' first three
pages carry an /OC of their own.
Reading all of that moves not one pixel. Walking every page of all 8 300 files
and counting the operators that mark the page, not one falls inside a layer
the document's own configuration hides: the layers are declared and left
empty, which is what an authoring tool leaves behind. Rendering the 1 633 forms
before and after gives identical pages and the same total ink to the unit —
88 770 158 either way.
One arXiv figure came closest: 2603.24071/Figure2.pdf declares five groups,
hides all five, and does name one of them in a BDC. The renderer identifies
that section as hidden — and the section contains none of the page's 165
marking operators. Empty as well.
So this is not a fix for anything the corpus shows going wrong, and it is not
written up as one. It is here because a document's statement about what it
shows should be obeyed, and because this corpus is forms and figures: layers
are how a CAD drawing, a map, a multilingual overlay and a print-only mark are
written, and none of those are in it. The measurement says the corpus does not
exercise the mechanism, which is a different claim from the mechanism not
mattering. The tests are therefore the only thing holding the behaviour up, and
they are written accordingly: a page for every path, and the policies unit by
unit.
TWO DECISIONS WORTH ARGUING WITH
/OFF wins over /ON where a document names a group in both. The specification
leaves it open; hiding is the safer reading, since showing what a document
tried to hide is the worse mistake.
A /VE visibility expression is not read. It takes precedence over /P where a
document has both, and not one file in the corpus carries one — so reading it
would be guesswork tested against nothing. A document that has one is treated
as visible, which is what this did before.
Suppression is of marks only. A clip narrowed inside a hidden layer still
narrows, because clipping is not marking; the operators that move the text pen
still move it. Otherwise a hidden layer would shift everything after it.
readOptional drops the error from Catalog(): reader.Open refuses a file whose
trailer does not lead to a catalogue, so it cannot happen. An unreachable
branch cannot be tested, and an untested branch in the code that decides what a
reader is shown is worse than no branch — so it is gone rather than covered by
a contrived case.
100% statement coverage, go vet and -race clean, nine cross-compile targets.