main's Thai work (#6249, #3492) and the Type 3 and symbolic TrueType
metrics changed the code this PR bounds. Each conflict, and each read main
added that this PR's allowance must cover:
- crates/fonts/src/pdf.rs, the editor's program read: this PR's read is
kept, its stage-scaled limit and its check for an allowance already
spent; main's read had /DecodeParms by reference too, which it has.
- The editor's loop: main rebuilds a cmap for a composite subset without
one from its ToUnicode and /CIDToGIDMap, where this PR skipped Type 0.
main's composite support stays, with the metrics read within the
editor's allowance (`from_dict_within`) and no copy adapted from metrics
read past it, as for a simple font. The /CIDToGIDMap the cmap is rebuilt
from (`composite_glyph_maps`) reads as the font's other streams do
(`Reads::decode`): within the allowance, behind several filters too.
- Reads main added to the metrics read: a Type 3 font's glyph
descriptions (`type3_glyph_box`), and the program read that tells a
symbolic TrueType font's codes as Mac OS Roman
(`symbolic_mac_roman_texts`). Both are now paid for from the allowance
the metrics are read within, and a refusal sets `past_allowance`. The
glyph descriptions keep their own limits (64 KiB each, 4 MiB a font).
- Constants and helpers both sides added beside one another, and the
tests both appended, are all kept. Callers main added of
`unicode_map` pass a reading without a total, as `from_dict` does.
- crates/edit/src/rules.rs: the refusal of a page whose content didn't
all decode stays, and the operators come from main's `text::joined`.
Tests: `adapting_a_programs_cmap_is_paid_for` now expects a composite
font's ToUnicode, and a simple font's program read again for the Mac OS
Roman reading, to be paid for. Four are new:
`adapting_a_composite_subsets_cmap_is_paid_for`,
`a_full_cid_map_rebuilds_a_composite_subsets_cmap_behind_two_filters`,
`type3_glyph_boxes_are_paid_for_from_the_allowance` and
`the_symbolic_mac_roman_reading_is_paid_for`. The fixture of main's test
of a composite subset without a cmap moves into `cmapless_composite`,
which both use.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
Conflicts, and how they were resolved:
- cos writer.rs and lib.rs: main now numbers a full save in `full_save_order` and exports
`reachable_objects`, the object numbers a full save writes, for the pattern guard. This
branch had added the same walk as `walk` and `reachable`. Main's is kept, with its alias
handling, and this branch's is dropped: `globals::kept` is now `reachable_objects`, so the
JBIG2 cleanup and the pattern guard read one walk. `kept` returns the walk's error (a save
that can't number its objects), which redaction and Remove Hidden Information pass on. The
cos test of what is reachable, and two redaction tests, read `reachable_objects` instead.
The exports keep this branch's `DECODE_PARMS_KEYS` and main's `TextChars`,
`civil_from_days` and `new_file_id`.
- redact lib.rs: main unlinks pruned patterns from `/Pages` nodes after `unlink_doomed`; this
branch replaced `restore_shared_jbig2` with `globals::unshare`. Both stay, the unlink first:
an image a pruned pattern's cell drew leaves the file with it, and is a user of a dictionary
that left too.
- redact sanitize.rs: main's `strip_outline_actions` and this branch's `unshare_unmarked` both
stay. At the end of `remove_hidden`, `unshare_unmarked` runs after main's `unlink_undrawn`,
so an image unlinked for being drawn nowhere takes a shared dictionary with it, and is
followed by main's `require_full_save_with_new_id`.
- redact image.rs: `MAX_PIXELS` is `pub(crate)` on both sides; the comment names
`globals::without_dictionary`, where this branch moved `without_globals`.
Tests: `an_undrawn_image_unlinked_takes_a_shared_jbig2_dictionary_too` (Remove Hidden
Information, through `unlink_undrawn`) and
`an_image_a_pruned_patterns_cell_drew_takes_a_shared_jbig2_dictionary_too` (a redaction,
through `unlink_pruned_patterns`) pin the order of the two new routes before `unshare`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
Main reworked the redaction cleanups this branch changes: #5969 reads
each inherited form once for all names (`names_content_draws`), #5924
prunes the forms a surviving Type 3 glyph draws and passes the page to
`prune_type3_from_resources`, and #6474 reads a page's annotation
appearances toward one operator total and one byte allowance.
- `interp/prune.rs`: `names_content_draws` keeps main's one read per
form and takes this branch's three changes to `content_draws`: it
reads operators one at a time, holding no stream's whole and decoding
each form only in its turn; it reads forms with `/DecodeParms` given
by reference; and a `/Resources` that isn't a dictionary is none of
the form's own. It charges no allowance, as `content_draws` didn't:
it runs after the pages' walks, over every holder, where no page's
allowance is left to spend.
- `type3.rs`: `prune_type3_from_resources` takes both the page's
allowance and main's `page`. The appearances main reads are charged
to that allowance, which the content and its forms spend too, in
place of a fresh one of their own, so one page has one allowance.
Main's `record_used` serves this branch's one-operator-at-a-time read
of glyph programs, and `scan_stream_object`, which took over
`scan_xobject`'s read, reads with `/DecodeParms` by reference.
`prune_font_forms` gives each form's walk the allowance of a page, as
`prune_retired_properties` does for each content.
- `interp.rs`, `lib.rs`, `sanitize.rs`: both arguments at each call.
- `edit/src/rules.rs`: the refusal of incomplete content stays, with
main's `text::joined`.
- Tests: both sides' kept, in `edit/src/tests.rs` and
`redact/src/tests/surviving_references.rs`. A new one,
`a_page_s_appearances_spend_what_its_content_left_of_the_allowance`,
pins the shared allowance: 1 MiB of content and an appearance within
half a MiB of the allowance are refused together, though the
appearance alone fits.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY