The Consumers review of ba28458ad..b7224cbc9:
- `recovered_thai_map` read the descendant's /CIDToGIDMap with
`Dict::name`, on the line after e9142b03b's /Encoding check, so a map
given by reference made Repair Thai maps pass the font over, and so
did a missing one, which is Identity (ISO 32000-2 Table 115), as
`composite_glyph_maps`, `LegacyThaiFont` and the renderer read it. It
now resolves the map and takes a missing one as Identity.
- `MAX_THAI_PROGRAMS` says what it pays for: the programs, and the CMaps
and glyph maps read to adapt their cmaps. The metrics read to find and
measure the subsets aren't charged to it. Its refusal ("MiB of font
data") still says what it counts.
Test: `recovered_thai_map_checks_every_kept_glyph_against_the_font_program`
recovers the same map with the font's /CIDToGIDMap given by reference and
with none.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
The Legal forms review of 8fb534ad4. A Type 0 font's /Encoding may be
given by reference (a name or a CMap stream, either indirect), and the
metrics read resolve it: an indirect /Identity-H reads two-byte codes.
The editor's check before reading a composite font's metrics, and
`main`'s `composite_glyph_maps` and `recovered_thai_map`, read it with
`Dict::name`, which doesn't resolve: such a font counted as another
encoding, so the editor adapted no copy of it and Repair Thai maps
passed it over. All three now read it through `identity_h`, which
resolves it as the metrics do.
Tests: `a_composite_fonts_encoding_given_by_reference_is_read` (the
editor adapts a copy of a composite subset with `/Encoding 5 0 R`, object
5 `/Identity-H`, that maps 'Ω', and its metrics read two-byte codes), and
`recovered_thai_map_checks_every_kept_glyph_against_the_font_program`
recovers the same map with the font's /Encoding by reference.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
The forms editor's test draft sets the focus's obj and list, which main added, and the focus scripts look up the focused field with focused_field so a same-name twin is read as main reads it.
Mutation testing of 063f8629e missed eight mutants in
`DecodeBudget::decode_stages_within`: nothing pinned what a read
stopped at a stage's limit, at the stages' total or at what is left of
the allowance charges, which limit it reports, or where one case gives
way to the next.
`a_stage_past_its_limit_charges_what_came_before_and_the_limit` reads
each way, and each boundary on both sides: a byte more room than the hex
stage and the limit (charged them, a byte left), exactly that (past the
allowance: all of it spent, its limit reported), a hex stage making
exactly the limit so the Flate stage reaches the stages' total with more
left (charged the total), with exactly the total left of a larger
allowance and with less (spent, the allowance's limit reported), and,
with nothing left, a stream with data that decodes to nothing (refused)
and an empty one (read).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
The Resources review of 8eead8ecd:
- `embedded_sfnt_within` read a composite font's metrics within the
editor's allowance before `composite_glyph_maps` refused any `/Encoding`
but Identity-H, so an Identity-V or UniJIS font spent its ToUnicode and
`/CIDToGIDMap` for nothing. Its `/Encoding` is now checked first; a
program with a cmap of its own is kept as it is, as when the rebuild
finds nothing.
- The Thai edit's allowance, `MAX_THAI_PROGRAMS`, now also pays for the
CMaps and glyph maps its subsets' metrics and codes are read from: its
doc and its refusal say "font data", not "font programs".
- `a_symbolic_truetype_font_without_an_encoding_reads_its_glyph_names`
also reads its font, whose `post` table names its glyphs, within an
allowance: the program is paid for by the glyph-name reading, by the
Mac OS Roman one and for the widths, and a byte short of the first the
names go unread.
Tests: `a_composite_font_that_cant_be_adapted_spends_only_its_program`,
and `adapting_a_programs_cmap_is_paid_for` again expects a composite font
whose codes aren't Identity-H to pay for its program only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
The Resources review of 8eead8ecd. The program read and the metrics reads
passed their limit times the number of filter stages as one total, which
any one stage could use: a FontFile2 of Flate making 128 MiB of
whitespace, under seven ASCIIHex stages (a 130 KB file), made all of it
before being refused, about 0.1 s a font where `main`'s bound stopped it
at 16 MiB. `edit`'s `matching_thai_outline` reads such a program for each
of a page's fonts with no total, and every `Metrics::from_dict` up to
three times.
Now each stage is held to the limit, as a decode without an allowance
holds it, and the stages together to the limit for each of them, so every
stream the stage scaling was for still reads: a full `/CIDToGIDMap` or a
12 MiB program behind ASCIIHex and Flate. The two bounds take an entry
point of their own: `pdfcraft_filters::decode_tolerant_counted_each`,
which `run` already supports, and `DecodeBudget::decode_stages_within`,
which `Reads::decode` and the editor's program read use. A stage past the
limit is charged what the stages before it decoded and the limit; past
the stages' total, or past what is left, it is charged as
`decode_within` charges. The program, the last stage, is so within the
limit without a check of its own.
Tests: `each_stage_is_held_to_its_own_bound_within_the_total` in
`pdfcraft-filters` (a Flate stage stopped at its bound hands the next
stage nothing), `each_stage_is_held_to_the_limit` in `pdfcraft-cos`, and
in `pdfcraft-fonts` `an_editors_program_read_holds_each_stage_to_its_limit`
and `each_stage_of_a_metrics_stream_is_held_to_its_limit`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
main's #3962 (symbolic TrueType glyph names, 63a6f8ace and nearby) reads a
symbolic TrueType font's codes by the `post` names of the glyphs its cmap
selects, before the Mac OS Roman reading:
- crates/fonts/src/pdf.rs, `unicode_map`: both readings stay, in main's
order, each given the metrics read's allowance. The program read main
added (`symbolic_glyph_texts`) goes through `Reads::decode`, as
`symbolic_mac_roman_texts` does since the last merge: paid for from the
allowance, `past_allowance` set when it can't be, behind several
filters within the stream's own limit.
- crates/fonts/src/pdf/tests.rs: both sides added tests at the same place;
all are kept.
Tests: `adapting_a_programs_cmap_is_paid_for` now expects the program to
be paid for a fourth time, and `the_symbolic_mac_roman_reading_is_paid_for`
becomes `the_symbolic_readings_of_a_program_are_paid_for`, paying for both
readings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmsdeUCdTaD72jkDw2pJKY
- engine: the on_changes test's XfaRun literals set highlight; the script
runner reads its template before borrowing the live form for to_js; has_event
reads the paged live form, as the rest of the runner does, so focus scripts
find a page-master copy by its own SOM path.
- js: property reads compare and copy the shared (Arc<str>) node text, and the
property tests build XHost with its current signature.
- xfa: the Emitter test literal sets groups and used; a field split that is
undone also restores the names handed out; rustfmt on a merged import.
- parity: drop the use/usehref gap from form.xfa-dynamic, as prototypes are now
resolved before the template is parsed.