* fix(tounicode): skip subset GID remap for CIDFontType0 (CFF) descendants
The sequential-GID repair in try_remap_subset_cmap assumes CIDs are glyph
indices that a subsetter can renumber. That holds for CIDFontType2
(TrueType) but not for CIDFontType0 (CFF), where CIDs are resolved through
the CFF charset, so a valid ToUnicode CMap stays valid after subsetting.
For CFF fonts the corrupting path was unavoidable: CIDToGIDMap is
CIDFontType2-only (PDF 32000-1:2008, 9.7.4.2), so the branch that repairs
the CMap correctly can never be taken, and any CFF font whose /W array
starts at a low CID fell through into remap_to_sequential. Japanese
Adobe-Japan1 documents extracted as long runs of a single unrelated kanji.
Guard both repair paths on a CIDFontType2 descendant, placed before the
CIDToGIDMap branch so a CIDToGIDMap wrongly attached to a CFF font by a
malformed producer is ignored too.
On a National Diet Library proceedings PDF: 1233 U+FFFD in 69099 chars
before, 0 in 68331 after; character 3-gram recall against a hand-written
ground truth 0.354 -> 0.605. The PDF from #118 (CIDFontType2) extracts
byte-identically before and after.
Two existing tests build descendant dicts without a /Subtype and set
CIDToGIDMap, which is CIDFontType2-only, so the fixtures now say what they
already meant. Without that, test_try_remap_skipped_when_w_covers_cmap
would keep passing while no longer exercising the W-coverage logic.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(tounicode): resolve indirect /Subtype, skip only explicit non-CIDFontType2
Addresses review feedback on the guard added in the previous commit.
- /Subtype may be an indirect reference, and as_name() does not dereference
it. A genuine CIDFontType2 font storing /Subtype indirectly would have been
read as "not CIDFontType2", returning early and losing the repair it needs —
reintroducing the corruption this PR fixes, for those fonts. Resolve the
reference through the document before comparing.
- Bail out only when /Subtype is explicitly a non-CIDFontType2 name. A missing
or unresolvable /Subtype now keeps the pre-existing behaviour instead of
silently disabling the repair. As a result the two existing tests no longer
need fixture changes, and this commit reverts those; the diff against main
is now additive only.
- The CFF regression test now attaches a real CIDToGIDMap stream rather than
/Identity, which get_cid_to_gid_map treats as "no map". With the stream, the
test also fails if the guard is moved back below the CIDToGIDMap branch —
verified by moving it and watching it fail.
- Added test_try_remap_resolves_indirect_subtype.
cargo fmt --check, cargo clippy -- -D warnings and cargo test (862 tests) pass.
The Diet PDF still extracts with 0 U+FFFD and the #118 PDF is still unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>