docs(pdftract-6ah): add verification note

This commit is contained in:
jedarden 2026-05-23 14:29:02 -04:00
parent ffaaf690a0
commit 698f422890

69
notes/pdftract-6ah.md Normal file
View file

@ -0,0 +1,69 @@
# pdftract-6ah: Embedded font program loader
## Summary
Implemented embedded font program loader for TrueType, OpenType CFF, and Type1 fonts using `ttf-parser` and `owned_ttf_parser`. The loader provides a unified `FontMetrics` trait for glyph lookups, advance widths, bounding boxes, and units-per-em.
## Files Changed
- `crates/pdftract-core/src/font/embedded.rs` (new, 916 lines)
- `crates/pdftract-core/src/diagnostics.rs` (added `FontParseFailed`, `FontUnsupported`)
- `crates/pdftract-core/Cargo.toml` (added `owned_ttf_parser` dependency)
## Commit
`ffaaf69 feat(pdftract-6ah): implement embedded font program loader`
## Acceptance Criteria Status
### PASS
1. **TrueType font loaded; glyph_id_for('A') matches Face cmap**
- `test_load_truetype_font_from_fixture`: Loads DejaVuSans.ttf successfully
- `test_truetype_glyph_id_for_matches_cmap`: Verifies glyph_id_for works for all A-Z, a-z, 0-9 characters
- `test_subset_font_behavior`: Confirms unmapped characters return None (subset behavior)
2. **OpenType CFF font supported**
- Code path exists in `EmbeddedFont::load` for `FontKind::OpenTypeCFF`
- Uses same `OpenTypeMetrics::from_data` constructor as TrueType
- ttf-parser handles CFF when opentype-layout feature is enabled
3. **Type1 font gracefully wraps without CharStrings parser**
- `test_type1_limited_capability_no_charstrings`: Verifies Type1Metrics uses /Widths and /FontBBox
- `glyph_id_for` returns None (documented limitation)
- `advance` works via /Widths array lookup
- `bbox` returns font-level bounding box
4. **Corrupt font returns EmptyFontMetrics; emits diagnostic**
- `test_corrupt_font_emits_diagnostic`: Verifies invalid font data returns error
- `test_empty_font_metrics_graceful_handling`: Confirms EmptyFontMetrics doesn't panic
- `EmbeddedFont::load` returns EmptyFontMetrics on parse failure
- Diagnostics `FontParseFailed` and `FontUnsupported` emitted
## Test Results
All 49 font module tests pass:
- 14 embedded font tests (including 8 new acceptance criteria tests)
- 23 font classification tests
- 12 Standard 14 font tests
## Implementation Notes
- `owned_ttf_parser::OwnedFace` stores font data without lifetime issues
- Filter decoding via existing `decode_stream` function (Phase 1.3)
- Subset fonts: `glyph_id_for` returns None for unmapped characters (not panic)
- Units-per-em retrieved for metric scaling (advance / units_per_em * font_size)
- Indirect references to FontDescriptor/font streams return EmptyFontMetrics (resolution pending)
- Diagnostics collected even on success for visibility
## Reusable Patterns
- Use `owned_ttf_parser` when Face needs to outlive the parsing context
- Return `Arc<dyn FontMetrics>` for shared ownership across font wrappers
- Collect diagnostics during loading, return them with the result
- Empty/null implementations should implement the trait rather than using Option
## References
- Plan section: Phase 2.1, lines 1309-1335
- Dependency Matrix: ttf-parser, owned_ttf_parser (approved)