feat(bf-4zgpr): add unmapped_glyph_names config field to CMAP generator
Add unmapped_glyph_names configuration field to DifferencesOverlay struct, which serves as the CMAP generator for Type1 font encoding differences. Changes: - Added unmapped_glyph_names: HashSet<String> field to DifferencesOverlay - Added with_unmapped_glyph_names() constructor for custom configuration - Added is_unmapped_glyph_name() instance method for checking membership - Added unmapped_glyph_names() getter and set_unmapped_glyph_names() setter - Updated parse() to use instance method instead of global function - Defaults to global UNMAPPED_GLYPH_NAMES set when not explicitly configured Acceptance criteria: - CMAP generator struct has unmapped_glyph_names field - Field is HashSet<String> for O(1) lookup efficiency - Field can be set via constructor or setter method - Code compiles and all tests pass (24 encoding tests) Closes bf-4zgpr. See notes/bf-4zgpr.md for verification details.
This commit is contained in:
parent
f23d7a7582
commit
7660cfc84c
2 changed files with 116 additions and 2 deletions
|
|
@ -130,16 +130,43 @@ pub struct DifferencesOverlay {
|
|||
/// Sparse list of (code, glyph_name) overrides.
|
||||
/// Sorted by code for binary search, though linear search is fine for <32 entries.
|
||||
entries: Vec<(u8, Arc<str>)>,
|
||||
/// Glyph names that should be skipped during CMAP entry creation.
|
||||
/// These glyphs have no valid Unicode mapping and should not appear in text extraction.
|
||||
/// Defaults to the global UNMAPPED_GLYPH_NAMES set if not explicitly configured.
|
||||
unmapped_glyph_names: std::collections::HashSet<String>,
|
||||
}
|
||||
|
||||
impl DifferencesOverlay {
|
||||
/// Create an empty overlay.
|
||||
/// Create an empty overlay with default unmapped glyph names.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
entries: Vec::new(),
|
||||
unmapped_glyph_names: Self::default_unmapped_glyph_names(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an empty overlay with custom unmapped glyph names.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `unmapped_glyph_names` - Set of glyph names to skip during CMAP entry creation
|
||||
pub fn with_unmapped_glyph_names(unmapped_glyph_names: std::collections::HashSet<String>) -> Self {
|
||||
Self {
|
||||
entries: Vec::new(),
|
||||
unmapped_glyph_names,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the default set of unmapped glyph names.
|
||||
///
|
||||
/// Returns the global UNMAPPED_GLYPH_NAMES set as a HashSet<String>.
|
||||
fn default_unmapped_glyph_names() -> std::collections::HashSet<String> {
|
||||
crate::font::unmapped::UNMAPPED_GLYPH_NAMES
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Parse a /Differences array into an overlay.
|
||||
///
|
||||
/// The array alternates between integers (starting codes) and names (glyph names).
|
||||
|
|
@ -197,7 +224,7 @@ impl DifferencesOverlay {
|
|||
// 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) {
|
||||
if !overlay.is_unmapped_glyph_name(&name) {
|
||||
overlay.entries.push((cursor as u8, Arc::clone(name)));
|
||||
}
|
||||
}
|
||||
|
|
@ -234,6 +261,39 @@ impl DifferencesOverlay {
|
|||
pub fn len(&self) -> usize {
|
||||
self.entries.len()
|
||||
}
|
||||
|
||||
/// Check if a glyph name is in the unmapped glyph names set.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `name` - The glyph name to check (with or without leading `/`)
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// `true` if the glyph name is in the unmapped set, `false` otherwise.
|
||||
fn is_unmapped_glyph_name(&self, name: &str) -> bool {
|
||||
// Strip leading slash if present
|
||||
let clean_name = if name.starts_with('/') {
|
||||
&name[1..]
|
||||
} else {
|
||||
name
|
||||
};
|
||||
self.unmapped_glyph_names.contains(clean_name)
|
||||
}
|
||||
|
||||
/// Get a reference to the unmapped glyph names set.
|
||||
pub fn unmapped_glyph_names(&self) -> &std::collections::HashSet<String> {
|
||||
&self.unmapped_glyph_names
|
||||
}
|
||||
|
||||
/// Set the unmapped glyph names set.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `unmapped_glyph_names` - New set of glyph names to skip during CMAP entry creation
|
||||
pub fn set_unmapped_glyph_names(&mut self, unmapped_glyph_names: std::collections::HashSet<String>) {
|
||||
self.unmapped_glyph_names = unmapped_glyph_names;
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for DifferencesOverlay {
|
||||
|
|
|
|||
54
notes/bf-4zgpr.md
Normal file
54
notes/bf-4zgpr.md
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
# Verification Note: bf-4zgpr
|
||||
|
||||
## Task
|
||||
Add unmapped_glyph_names config field to CMAP generator
|
||||
|
||||
## Summary
|
||||
Added `unmapped_glyph_names` configuration field to the `DifferencesOverlay` struct, which serves as the CMAP generator for Type1 font encoding differences.
|
||||
|
||||
## Changes Made
|
||||
|
||||
### File: `/home/coding/pdftract/crates/pdftract-core/src/font/encoding.rs`
|
||||
|
||||
1. **Added `unmapped_glyph_names` field to `DifferencesOverlay` struct**:
|
||||
- Type: `std::collections::HashSet<String>`
|
||||
- Stores glyph names that should be skipped during CMAP entry creation
|
||||
- Defaults to global `UNMAPPED_GLYPH_NAMES` set if not explicitly configured
|
||||
|
||||
2. **Added `with_unmapped_glyph_names()` constructor**:
|
||||
- Allows creating an overlay with a custom unmapped glyph names set
|
||||
- Enables the field to be populated from configuration
|
||||
|
||||
3. **Added `is_unmapped_glyph_name()` helper method**:
|
||||
- Instance method that checks if a glyph name is in the unmapped set
|
||||
- Handles leading `/` stripping for consistency
|
||||
|
||||
4. **Added getter and setter methods**:
|
||||
- `unmapped_glyph_names()` - Get reference to the set
|
||||
- `set_unmapped_glyph_names()` - Set a new set
|
||||
|
||||
5. **Updated `parse()` method**:
|
||||
- Changed from global `crate::font::is_unmapped_glyph_name()` to instance method `overlay.is_unmapped_glyph_name()`
|
||||
- Now uses the configurable field instead of hardcoded global set
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- ✅ CMAP generator struct has `unmapped_glyph_names` field
|
||||
- ✅ Field is of appropriate type (`HashSet<String>` for efficient lookup)
|
||||
- ✅ Field can be set from config/passed in constructor via `with_unmapped_glyph_names()`
|
||||
- ✅ Code compiles without errors (verified with `cargo build --release`)
|
||||
- ✅ All tests pass (24 encoding tests, including 2 specific unmapped glyph name tests)
|
||||
|
||||
## Test Results
|
||||
```
|
||||
running 24 tests
|
||||
test font::encoding::tests::test_differences_overlay_skips_notdef ... ok
|
||||
test font::encoding::tests::test_differences_overlay_skips_notdef_with_slash ... ok
|
||||
test font::encoding::tests::test_font_encoding_lookup_order ... ok
|
||||
...
|
||||
test result: ok. 24 passed; 0 failed; 0 ignored; 0 measured
|
||||
```
|
||||
|
||||
## Related Files
|
||||
- `/home/coding/pdftract/crates/pdftract-core/src/font/encoding.rs` - Main implementation
|
||||
- `/home/coding/pdftract/crates/pdftract-core/src/font/unmapped.rs` - Global UNMAPPED_GLYPH_NAMES set (used as default)
|
||||
Loading…
Add table
Reference in a new issue