Class: Ucode::Glyphs::EmbeddedFonts::Catalog

Inherits:
Object
  • Object
show all
Defined in:
lib/ucode/glyphs/embedded_fonts/catalog.rb

Overview

Composes PdfIndexer + CodepointMapper to build a global {codepoint => FontEntry} index from a Code Charts PDF.

Responsibilities split cleanly:

* {PdfIndexer} — subprocess + dict parsing → Array<RawFontDescriptor>
* {CodepointMapper} — 3-path codepoint→GID strategy → {cp => gid}
* {Catalog} (this class) — composes both into FontEntry objects
and exposes the public lookup interface

When multiple fonts cover the same codepoint, the first font discovered wins. Discovery order follows mutool info's page-major listing, so earlier blocks' fonts win — the expected behavior.

Instance Method Summary collapse

Constructor Details

#initialize(source, block_range: nil, force_positional_for_font_ids: Set.new, correlator_configs: {}) ⇒ Catalog

Returns a new instance of Catalog.

Parameters:

  • source (PdfSource)
  • block_range (Range<Integer>, nil) (defaults to: nil)

    codepoint scope the caller is extracting. When present, drops an intrinsic strategy's result if it has zero in-block intersection, letting positional strategies take over (the U1F200 class of failure where the font's CMap encoded composing ideographs rather than the specimens). nil = legacy mode (intrinsic result always trusted).

  • force_positional_for_font_ids (Set<Integer>) (defaults to: Set.new)

    Type0 font object IDs that always trigger positional attribution regardless of intrinsic success. Escape hatch for partial-overlap cases.

  • correlator_configs (Hash{Integer=>ContentStreamCorrelator::Config}) (defaults to: {})

    maps a Type0 font's PDF object ID to the pillar-2 config to use when the font has no /ToUnicode CMap. Empty by default.



35
36
37
38
39
40
41
42
43
# File 'lib/ucode/glyphs/embedded_fonts/catalog.rb', line 35

def initialize(source, block_range: nil,
               force_positional_for_font_ids: Set.new,
               correlator_configs: {})
  @source = source
  @block_range = block_range
  @force_positional_for_font_ids = force_positional_for_font_ids
  @correlator_configs = correlator_configs
  @index = nil
end

Instance Method Details

#codepointsArray<Integer>

Returns every codepoint this PDF covers.

Returns:

  • (Array<Integer>)

    every codepoint this PDF covers



89
90
91
# File 'lib/ucode/glyphs/embedded_fonts/catalog.rb', line 89

def codepoints
  index.keys
end

#font_countInteger

Returns number of Type0 fonts with non-empty maps.

Returns:

  • (Integer)

    number of Type0 fonts with non-empty maps



99
100
101
# File 'lib/ucode/glyphs/embedded_fonts/catalog.rb', line 99

def font_count
  font_entries.size
end

#font_entriesArray<FontEntry>

Returns every font entry (one per Type0 font).

Returns:

  • (Array<FontEntry>)

    every font entry (one per Type0 font)



104
105
106
# File 'lib/ucode/glyphs/embedded_fonts/catalog.rb', line 104

def font_entries
  @font_entries ||= build_font_entries
end

#indexHash{Integer=>FontEntry}

Returns frozen codepoint → entry map.

Returns:

  • (Hash{Integer=>FontEntry})

    frozen codepoint → entry map



46
47
48
# File 'lib/ucode/glyphs/embedded_fonts/catalog.rb', line 46

def index
  @index ||= build_index.freeze
end

#location_for(codepoint) ⇒ Hash{Symbol=>Integer, Float}?

Locate where in the PDF a codepoint's specimen was rendered. Returns {page:, x:, y:} (PDF user space, origin bottom-left) by joining #lookup with the trace cache's (font, gid) search. Nil when:

* the codepoint isn't in this PDF, OR
* the embedded font has no traced specimen (ToUnicode-only
path with no positional correlation data), OR
* the trace cache wasn't populated (lazy + never asked
for any positional strategy).

Memoized per-Catalog; the second call for the same codepoint is O(1).

Parameters:

  • codepoint (Integer)

Returns:

  • (Hash{Symbol=>Integer, Float}, nil)


71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/ucode/glyphs/embedded_fonts/catalog.rb', line 71

def location_for(codepoint)
  @locations ||= {}
  return @locations[codepoint] if @locations.key?(codepoint)

  entry = lookup(codepoint)
  result = if entry.nil?
             nil
           else
             trace_cache.find_glyph(
               base_font: entry.base_font,
               gid: entry.gid_for(codepoint),
             )
           end
  @locations[codepoint] = result
  result
end

#lookup(codepoint) ⇒ FontEntry?

Parameters:

  • codepoint (Integer)

Returns:



52
53
54
# File 'lib/ucode/glyphs/embedded_fonts/catalog.rb', line 52

def lookup(codepoint)
  index[codepoint]
end

#sizeInteger

Returns number of codepoints covered.

Returns:

  • (Integer)

    number of codepoints covered



94
95
96
# File 'lib/ucode/glyphs/embedded_fonts/catalog.rb', line 94

def size
  index.size
end