Class: Ucode::Glyphs::EmbeddedFonts::CodepointMapper
- Inherits:
-
Object
- Object
- Ucode::Glyphs::EmbeddedFonts::CodepointMapper
- Defined in:
- lib/ucode/glyphs/embedded_fonts/codepoint_mapper.rb,
lib/ucode/glyphs/embedded_fonts/codepoint_mapper/strategy.rb,
lib/ucode/glyphs/embedded_fonts/codepoint_mapper/trace_strategy.rb,
lib/ucode/glyphs/embedded_fonts/codepoint_mapper/tounicode_strategy.rb,
lib/ucode/glyphs/embedded_fonts/codepoint_mapper/correlator_strategy.rb
Overview
Resolves codepoint → GID for one Type0 font via a chain of Strategy subclasses.
The chain is partitioned by Strategy#positional?:
* Intrinsic strategies (ToUnicodeStrategy) read the font's
own CMap. Tried in chain order; the first non-empty result
wins.
* Positional strategies (CorrelatorStrategy, TraceStrategy)
attribute glyphs by chart-grid geometry. Expensive — they
shell out to mutool per page — so they only run when an
intrinsic strategy cannot cover the requested block scope.
When positional strategies run, their results merge over the intrinsic result with positional precedence: chart geometry is authoritative for in-block specimens, while a font's CMap can be misleading (Enclosed Ideographic Supplement, where the embedded CJKSymbols font's CMap maps its CIDs to the composing ideographs rather than the squared characters themselves).
Two escape hatches let callers control the gating:
* `block_range:` — when set, an intrinsic result with zero
in-block intersection is treated as "wrong scope" and
dropped, so positional strategies can take over. Auto-detect
for the U1F200 class of failure (Option 1).
* `force_positional_for_font_ids:` — Type0 font object IDs
that always go through positional attribution, regardless
of whether the intrinsic strategy succeeded. Escape hatch
for partial-overlap cases where the CMap covers some
in-block codepoints but positional attribution is still
desired for the rest (Option 2).
Adding a new strategy = one Strategy subclass + (if positional)
a positional? override + one entry in the chain. No edit to
#map (Open/Closed Principle).
Defined Under Namespace
Classes: CorrelatorStrategy, Strategy, ToUnicodeStrategy, TraceStrategy
Class Method Summary collapse
-
.build(source:, correlator_configs:, indexer:, block_range: nil, force_positional_for_font_ids: Set.new, mutool_show: Mutool::Show.new, mutool_draw: Mutool::Draw.new, mutool_trace: Mutool::Trace.new) ⇒ CodepointMapper
Convenience builder — wires up the default 3-strategy chain with default Mutool wrappers.
Instance Method Summary collapse
-
#initialize(strategies:, block_range: nil, force_positional_for_font_ids: Set.new) ⇒ CodepointMapper
constructor
A new instance of CodepointMapper.
-
#map(descriptor) ⇒ Hash{Integer=>Integer}
Codepoint => gid; empty when no strategy produces a mapping.
Constructor Details
#initialize(strategies:, block_range: nil, force_positional_for_font_ids: Set.new) ⇒ CodepointMapper
Returns a new instance of CodepointMapper.
59 60 61 62 63 64 |
# File 'lib/ucode/glyphs/embedded_fonts/codepoint_mapper.rb', line 59 def initialize(strategies:, block_range: nil, force_positional_for_font_ids: Set.new) @strategies = strategies @block_range = block_range @force_positional_for_font_ids = force_positional_for_font_ids end |
Class Method Details
.build(source:, correlator_configs:, indexer:, block_range: nil, force_positional_for_font_ids: Set.new, mutool_show: Mutool::Show.new, mutool_draw: Mutool::Draw.new, mutool_trace: Mutool::Trace.new) ⇒ CodepointMapper
Convenience builder — wires up the default 3-strategy chain
with default Mutool wrappers. Callers that need to inject
stubs for tests should construct strategies directly and pass
them to #initialize.
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/ucode/glyphs/embedded_fonts/codepoint_mapper.rb', line 72 def self.build(source:, correlator_configs:, indexer:, block_range: nil, force_positional_for_font_ids: Set.new, mutool_show: Mutool::Show.new, mutool_draw: Mutool::Draw.new, mutool_trace: Mutool::Trace.new) trace_cache = PageTraceCache.new( pdf: source.pdf_path, page_count: indexer.page_count, mutool: mutool_trace, ) strategies = [ ToUnicodeStrategy.new(source: source, mutool_show: mutool_show), CorrelatorStrategy.new(source: source, correlator_configs: correlator_configs, mutool_draw: mutool_draw), TraceStrategy.new(cache: trace_cache, indexer: indexer), ] new(strategies: strategies, block_range: block_range, force_positional_for_font_ids: force_positional_for_font_ids) end |
Instance Method Details
#map(descriptor) ⇒ Hash{Integer=>Integer}
Returns codepoint => gid; empty when no strategy produces a mapping.
97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/ucode/glyphs/embedded_fonts/codepoint_mapper.rb', line 97 def map(descriptor) return {} unless descriptor.cid_map_kind == :identity positional, intrinsic = partition_strategies intrinsic_result = run_intrinsic(descriptor, intrinsic) return intrinsic_result if positional.empty? return intrinsic_result unless needs_positional?(descriptor, intrinsic_result) positional_result = run_positional(descriptor, positional) merge_with_positional_precedence(intrinsic_result, positional_result) end |