From f757d8b689d3ad2c8b6c4c7a669c43a583132962 Mon Sep 17 00:00:00 2001 From: jedarden Date: Mon, 6 Jul 2026 13:33:23 -0400 Subject: [PATCH] docs(bf-2nn5x): verify unmapped_glyph_names config wiring to CMAP entry creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Verify that the unmapped_glyph_names configuration is properly wired through to the CMAP entry creation point in Type1 font encoding differences parsing. The configuration was already added in bf-4zgpr (commit 7660cfc8). This bead confirms the wiring is complete: - DifferencesOverlay stores unmapped_glyph_names as instance state - Default initialization loads from global UNMAPPED_GLYPH_NAMES set - Skip check at encoding.rs:227 filters unmapped glyphs before entry creation - Custom configuration available via with_unmapped_glyph_names() constructor Acceptance criteria: - ✅ CMAP entry creation accepts unmapped_glyph_names (via self field) - ✅ Configuration passes from defaults to entry creation - ✅ Code compiles without errors See notes/bf-2nn5x.md for detailed verification. --- notes/bf-2nn5x.md | 133 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 notes/bf-2nn5x.md diff --git a/notes/bf-2nn5x.md b/notes/bf-2nn5x.md new file mode 100644 index 0000000..a231bc0 --- /dev/null +++ b/notes/bf-2nn5x.md @@ -0,0 +1,133 @@ +# Verification: unmapped_glyph_names Config Wired to CMAP Entry Creation + +## Task +Wire unmapped_glyph_names config to CMAP entry creation point. + +## Status: PASS + +The unmapped_glyph_names configuration was already wired to the CMAP entry creation point in a previous commit (7660cfc8: "feat(bf-4zgpr): add unmapped_glyph_names config field to CMAP generator"). This bead verifies the wiring is complete and functional. + +## Implementation + +### CMAP Entry Creation Point +**Location:** `crates/pdftract-core/src/font/encoding.rs:220-230` + +The CMAP entry creation for Type1 font encoding differences occurs in `DifferencesOverlay::parse()`. This is where individual (code, glyph_name) pairs are added to the overlay. + +### Configuration Storage +**Location:** `crates/pdftract-core/src/font/encoding.rs:129-146` + +The `DifferencesOverlay` struct stores the `unmapped_glyph_names` configuration: + +```rust +pub struct DifferencesOverlay { + entries: Vec<(u8, Arc)>, + unmapped_glyph_names: std::collections::HashSet, +} +``` + +### Configuration Initialization +**Location:** `crates/pdftract-core/src/font/encoding.rs:140-168` + +The configuration is initialized with defaults from the global `UNMAPPED_GLYPH_NAMES` set: + +```rust +pub fn new() -> Self { + Self { + entries: Vec::new(), + unmapped_glyph_names: Self::default_unmapped_glyph_names(), + } +} + +fn default_unmapped_glyph_names() -> std::collections::HashSet { + crate::font::unmapped::UNMAPPED_GLYPH_NAMES + .iter() + .map(|s| s.to_string()) + .collect() +} +``` + +### Skip Check at Entry Creation +**Location:** `crates/pdftract-core/src/font/encoding.rs:223-230` + +The skip check prevents unmapped glyph names from being added as CMAP entries: + +```rust +if cursor <= 255 { + // Skip unmapped glyph names (e.g., .notdef) to prevent them from + // appearing in text extraction output. These glyphs have no valid + // Unicode mapping and should emit GLYPH_UNMAPPED diagnostics instead. + if !overlay.is_unmapped_glyph_name(&name) { + overlay.entries.push((cursor as u8, Arc::clone(name))); + } +} +``` + +### Accessor Methods +**Locations:** `crates/pdftract-core/src/font/encoding.rs:148-158, 265-296` + +The configuration provides methods for customization and access: + +```rust +// Custom constructor +pub fn with_unmapped_glyph_names(unmapped_glyph_names: std::collections::HashSet) -> Self + +// Membership check +fn is_unmapped_glyph_name(&self, name: &str) -> bool + +// Getter +pub fn unmapped_glyph_names(&self) -> &std::collections::HashSet + +// Setter +pub fn set_unmapped_glyph_names(&mut self, unmapped_glyph_names: std::collections::HashSet) +``` + +## Call Chain + +Configuration flows from global constants to entry creation: + +1. **Global Definition:** `UNMAPPED_GLYPH_NAMES` in `unmapped.rs` (auto-generated from AGL) +2. **Default Initialization:** `DifferencesOverlay::new()` loads global set +3. **Parse Entry:** `DifferencesOverlay::parse()` creates overlay with defaults +4. **Skip Check:** `is_unmapped_glyph_name(&name)` checks membership before adding +5. **Entry Creation:** `overlay.entries.push()` executes only for mapped glyphs + +## Custom Configuration Path + +For custom configurations, users can: +1. Create a `HashSet` with desired glyph names +2. Use `DifferencesOverlay::with_unmapped_glyph_names(custom_set)` +3. Or use `set_unmapped_glyph_names()` on an existing overlay + +## Acceptance Criteria Status + +- ✅ CMAP entry creation point accepts unmapped_glyph_names (via `self` field) +- ✅ Configuration is correctly passed from defaults through to entry creation +- ✅ Code compiles without errors (`cargo check --package pdftract-core` passed) + +## Why This Design + +The `unmapped_glyph_names` configuration is stored as instance state in `DifferencesOverlay` rather than passed as a parameter to `add_mapping()` because: + +1. **Type1 Encoding Context:** The CMAP entry creation for Type1 fonts works with glyph names (e.g., ".notdef"), not byte codes +2. **Semantic Fit:** The configuration belongs to the overlay that creates entries, not each individual entry +3. **Flexibility:** Instance state allows custom configuration via constructor/setter without changing method signatures + +## Note on ToUnicode CMap + +The ToUnicode CMap parser (`cmap.rs`) does not use this configuration because: +- ToUnicode CMaps map byte sequences → Unicode characters directly +- There are no glyph names involved in ToUnicode mappings +- The skip logic is specific to Type1 font encoding differences + +## Related Files + +- `crates/pdftract-core/src/font/encoding.rs` - CMAP entry creation and config +- `crates/pdftract-core/src/font/unmapped.rs` - Global UNMAPPED_GLYPH_NAMES set +- `crates/pdftract-core/src/font/cmap.rs` - ToUnicode CMap parser (different code path) + +## Related Beads + +- bf-4zgpr: Added unmapped_glyph_names config field to DifferencesOverlay +- bf-6cvmz: Documented unmapped_glyph_names configuration structure +- bf-o4nrq: Documented CMAP entry creation point