Patch 82 sent every soft mask through the decoded-image cache, so a mask that patch 91 keeps failed inside its image's entry got a second entry and counted as another decode. Only a mask averaged down needs an entry of its own; any other decodes as it did before patch 82.
A cubic whose second control point is its end point (as the `y` operator builds,
ISO 32000-2 8.5.2.1 Table 58) has a zero derivative at its end. kurbo 0.13.1's
offset curve looks for cusps with a root search on the curvature, which grows
without bound towards that end; at some widths the search stops on the end point
and normalising the zero tangent there gives NaN. vello_common's fill drops any
outline with NaN, so the whole stroke vanished (a two-curve `y` path drew nothing
at 16, 32 and 63 pt; a PDFBox tracker file lost its 32 pt "XX" outline).
The NaN fallback that #4913 added to `flatten::stroke` now also moves such a
control point the stroke tolerance towards the previous control point before
stroking again (the curve moves by at most 4/9 of the tolerance). Outlines that
come back finite take the old path unchanged. The vendor ledger row also gets
back #4913's entry, which a merge had dropped.
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
Co-authored-by: mtlcl410 <chuanlin@niar.org.tw>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* M2: a form XObject that draws itself is drawn once (hayro-interpret patch 89)
A form whose content names itself, directly or through another form, a
pattern or a glyph, drew itself again at every level until the page's
nested-paint budget (50,000) ran out. PDFBOX-5782's poppler-748 page 2,
whose form names a /Pages dictionary as /X0 and so finds itself in the
page's resources, took 38 s.
hayro-interpret now keeps the forms being drawn on the context and skips
a form already on it, reporting ContentTruncated (ISO 32000-2 §8.10.1: a
form is a self-contained description). The lenient fallback from a form's
own resources to the page's stays: MuPDF, Poppler and PDFium all draw a
name from the page's resources when the form's /Resources has no
XObject subdictionary (MuPDF and Poppler also when it has an empty one).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn
* fix(render): a form that reaches itself through a pattern or a glyph is drawn once (hayro-interpret patch 89)
The forms being drawn are now kept per page and thread rather than per
context, so the tiling patterns, Type 3 glyphs, soft masks and groups
painted inside a form, which hayro interprets in contexts of their own,
see that the form is being drawn and skip it inside themselves. A form
drawn again after it has finished draws as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
* chore: re-run CI after the Fill & Sign save comparison failed on the clock (#6066)
`fill_sign_enter_adds_lines_outside_click_commits_and_escape_cancels`
compares two saves whose /ModDate fell in different seconds; it passes
locally on this commit. No change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
---------
Co-authored-by: mtlcl410 <chuanlin@niar.org.tw>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
TIFF predictor 2 (ISO 32000-2 §7.4.4.4, Table 10) went through the
bit-level BitChunks/BitWriter path for every bit depth, re-reading the
previous output pixel through a new BitReader per pixel. Whole-byte
samples (8 and 16 bits per component) are now undone on byte slices,
each sample added to the same component of the pixel to its left,
wrapping at its width; 1-, 2- and 4-bit samples keep the bit-level path.
The output is byte-identical, including the dropped partial last row.
A page of 45 full-page 8-bit grey images so predicted (PDFBOX-1350)
renders in about 4 s instead of 23 s with the same pixels.
Vendored hayro-syntax patch 42.
Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn
Co-authored-by: mtlcl410 <chuanlin@niar.org.tw>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A subset that counts its glyphs in order of first use (`/Differences [1 /C1
/C2 ...]`) names its own codes, so numbered_names_name_their_codes held and
`/C65` (the 65th glyph used) read as `A`. A numbered name at a C0 control
code, which no text shows, now gives the counter away and the font reads
nothing. The check sits in the one function both the Type 1/CFF and the
Type 3 paths call.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA