pdftract/notes/bf-1puzp.md
jedarden bcab32d890 docs(bf-1puzp): verify CMAP skip logic for unmapped glyphs
All acceptance criteria verified:
- Glyph names checked against unmapped_glyph_names config
- Unmapped glyphs skipped during CMAP generation
- Code compiles without errors
- Tests demonstrate skip behavior

The implementation was already complete in encoding.rs:200.
See notes/bf-1puzp.md for detailed verification.
2026-07-06 10:03:10 -04:00

4.3 KiB

CMAP Skip Logic for Unmapped Glyphs - Verification

Bead ID: bf-1puzp Date: 2026-07-06 Status: VERIFIED - Already Implemented

Overview

The CMAP skip logic for unmapped glyphs was already implemented in the codebase. This note verifies the implementation meets all acceptance criteria.

Implementation Location

File: crates/pdftract-core/src/font/encoding.rs Function: DifferencesOverlay::parse() Lines: 194-203

Code

// MARKER: CMAP entry creation point - Type1 font encoding differences.
// See notes/bf-e4uvb-child-1.md for documentation.
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 !crate::font::is_unmapped_glyph_name(&name) {
        overlay.entries.push((cursor as u8, Arc::clone(name)));
    }
}

Acceptance Criteria Verification

1. Generator checks glyph name against unmapped_glyph_names config before CMAP entry creation

The code calls crate::font::is_unmapped_glyph_name(&name) at line 200, which checks the glyph name against the UNMAPPED_GLYPH_NAMES set defined in crates/pdftract-core/src/font/unmapped.rs.

2. Unmapped glyphs are skipped during CMAP generation

Glyphs that return true from is_unmapped_glyph_name() are skipped - the overlay.entries.push() call is only executed when the check returns false (note the ! negation).

3. Code compiles without errors

Verified with:

cargo build -p pdftract-core

Compilation successful with no errors.

4. Simple test demonstrating skip behavior

Two existing tests demonstrate the skip behavior:

Test 1: test_differences_overlay_skips_notdef (encoding.rs:676-693)

let arr = PdfObject::Array(Box::new(vec![
    PdfObject::Integer(39),
    PdfObject::Name(Arc::from(".notdef")),
    PdfObject::Integer(96),
    PdfObject::Name(Arc::from("grave")),
]));

let overlay = DifferencesOverlay::parse(&arr, &mut diagnostics);

// .notdef should be skipped, only grave should be present
assert_eq!(overlay.get(39), None); // .notdef was skipped
assert_eq!(overlay.get(96), Some(Arc::from("grave")));
assert_eq!(overlay.len(), 1);

Test 2: test_differences_overlay_skips_notdef_with_slash (encoding.rs:696-713)

let arr = PdfObject::Array(Box::new(vec![
    PdfObject::Integer(10),
    PdfObject::Name(Arc::from("/.notdef")),
    PdfObject::Integer(11),
    PdfObject::Name(Arc::from("A")),
]));

let overlay = DifferencesOverlay::parse(&arr, &mut diagnostics);

// /.notdef should be skipped, only A should be present
assert_eq!(overlay.get(10), None); // /.notdef was skipped
assert_eq!(overlay.get(11), Some(Arc::from("A")));

Both tests pass, confirming the skip behavior works correctly.

Test Execution

$ cargo test -p pdftract-core --lib -- encoding::tests::test_differences_overlay_skips_notdef
running 2 tests
test font::encoding::tests::test_differences_overlay_skips_notdef ... ok
test font::encoding::tests::test_differences_overlay_skips_notdef_with_slash ... ok

test result: ok. 2 passed; 0 failed; 0 ignored

Implementation Details

Unmapped Glyph Configuration

File: crates/pdftract-core/src/font/unmapped.rs

The UNMAPPED_GLYPH_NAMES set currently contains:

  • .notdef - The special fallback glyph defined by PDF/font specifications

Additional unmapped glyph names can be added to this set as needed.

Check Function

The is_unmapped_glyph_name() function:

  1. Strips leading / if present (handles both .notdef and /.notdef)
  2. Checks if the clean name is in UNMAPPED_GLYPH_NAMES
  3. Returns true if unmapped, false otherwise

Summary

All acceptance criteria are met:

  • Glyph names checked against unmapped_glyph_names config
  • Unmapped glyphs skipped during CMAP generation
  • Code compiles without errors
  • Tests demonstrate skip behavior

The implementation is complete and working correctly.

  • notes/bf-e4uvb-child-1.md - CMAP and ToUnicode entry creation points documentation
  • crates/pdftract-core/src/font/unmapped.rs - Unmapped glyph configuration
  • crates/pdftract-core/src/font/encoding.rs - CMAP entry creation with skip logic