Repository navigation
Read content-stream operators through PdfOperatorVariant instead of PdfOperator - #589
Merged
Merged
Conversation
Most operator structs only held decoded operands, assigned them in new, and forwarded them to one backend method. They become struct variants of PdfOperatorVariant, read in one expression in PdfOperatorVariant::read and dispatched in PdfOperatorVariant::call. Line cap, line join and text rendering mode are read through new FromPdfObject decoders for the pdf-graphics enums, which ExtGState now uses for /LC and /LJ in place of its own validation. The stroking and non-stroking color operators share one ColorOperands type. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conformance readsDocuments that Safe-PDF reads differently from the base commit, compared with PDFium. A read pdf.js corpus1009 documents compared with Regressions
840 documents of the PDFium corpus read as on Details are in the job summaries of the workflow run. Rerun a case locally with |
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.
Summary
Removes the
PdfOperatortrait and most of the per-operator structs. Each operator becomes one arm inPdfOperatorVariant::readand one inPdfOperatorVariant::call.1. Remove
PdfOperator(dc8bdf5)The trait was closed and only used to fill the
operation_mapdispatch table:NAMEwas never read. It repeated the table's literals, which is howFended up unmapped.SC/scneeded placeholder types whosecallcould never run.BIneeded areadthat always failed, plus a parse-hook field used by no other operator.PdfOperatorVariant::read(name, operands)now matches(name, operand count)in one place, and the stream parser handlesBIitself. Recovery behaviour is unchanged. Without the per-operator function pointer, dispatch-heavy parsing is about 17% faster.2. Inline operator operands (
05b3fda)LineTo { x, y }). Each is read in one expression and dispatched in onecallarm. Their structs,new/read/callmethods and eleven emptied modules are deleted.LineCap,LineJoinandTextRenderingModegainFromPdfObjectdecoders inpdf-object-reader, with a newObjectError::InvalidEnumValue. TheJ,jandTroperators read them withoperands.at(0)?. ExtGState uses the same decoders for/LCand/LJ, replacing its own validation and two error variants.ColorOperands { components, pattern }type, replacing two identical structs and four duplicated readers.BeginMarkedContentWithPropskeeps a struct.About 1,810 lines removed and 755 added compared with
main.Performance
operator_parsing, median of 5 interleaved runs, shipped release profile:maindc8bdf5Commit 2 compared with
dc8bdf5:dc8bdf505b3fdaThree builds of
dc8bdf5with a no-op change set the noise floor at ±0.7% fordispatch_heavyand ±1.3% for the other two.The parse loop is inlined into one function, and at
opt-level = "z"its layout shifts whenever code elsewhere in it changes, even in arms a benchmark never runs. Merging the colour readers left them with two callers, so LLVM stopped inlining them. That reshaped the loop and slowed every operator by 2.4%.#[inline]on theColorOperandsreaders brings this back to the +1.6% above.dispatch_heavyonly parses zero-operand operators, none of whose arms changed, and the remaining cost is close to the noise floor. Other attempts (out-of-lineread, direct pushes, different decoder inlining) were all slower.Testing
cargo test,cargo clippy --all --workspace -- -D warnings,cargo fmt --check, and a wasm check ofweb-canvas-example.pdf-graphics-skiaandpdf-conformance, because their Skia build needs a download the local sandbox blocks. CI covers them./LCor/LJfrom an ExtGState dictionary.Follow-ups
FtoFillPathNonZero(issue pending).🤖 Generated with Claude Code