Module: TTFunk::Table::Cmap::Format04

Defined in:
lib/ttfunk/table/cmap/format04.rb

Overview

Format 4: Segment mapping to delta values.

This module conditionally extends Subtable.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#code_mapHash{Integer => Integer} (readonly)

Code map.

Returns:

  • (Hash{Integer => Integer})
Source Code
lib/ttfunk/table/cmap/format04.rb, line 16
16
def code_map
17
  @code_map
18
end

#languageInteger (readonly)

Language.

Returns:

  • (Integer)
Source Code
lib/ttfunk/table/cmap/format04.rb, line 12
12
def language
13
  @language
14
end

Class Method Details

.encode(charmap) ⇒ Hash

Encode the encoding record to format 4.

Parameters:

  • charmap (Hash{Integer => Integer})

    a hash mapping character codes to glyph IDs from the original font.

Returns:

  • (Hash)
    • :charmap (Hash{Integer => Hash}) keys are the characrers in charset, values are hashes:
      • :old (Integer) - glyph ID in the original font.
      • :new (Integer) - glyph ID in the subset font. that maps the characters in charmap to a
    • :subtable (String) - serialized encoding record.
    • :max_glyph_id (Integer) - maximum glyph ID in the new font.
Source Code
lib/ttfunk/table/cmap/format04.rb, line 30
30
def self.encode(charmap)
31
  end_codes = []
32
  start_codes = []
33
  next_id = 0
34
  last = difference = nil
35
36
  glyph_map = { 0 => 0 }
37
  new_map =
38
    charmap.keys.sort.each_with_object({}) do |code, map|
39
      old = charmap[code]
40
      glyph_map[old] ||= next_id += 1
41
      map[code] = { old: old, new: glyph_map[old] }
42
43
      delta = glyph_map[old] - code
44
      if last.nil? || delta != difference
45
        end_codes << last if last
46
        start_codes << code
47
        difference = delta
48
      end
49
      last = code
50
51
      map
52
    end
53
54
  end_codes << last if last
55
  end_codes << 0xFFFF
56
  start_codes << 0xFFFF
57
  segcount = start_codes.length
58
59
  # build the conversion tables
60
  deltas = []
61
  range_offsets = []
62
  glyph_indices = []
63
  offset = 0
64
65
  start_codes.zip(end_codes).each_with_index do |(a, b), segment|
66
    if a == 0xFFFF
67
      # We want the final 0xFFFF code to map to glyph 0.
68
      # The glyph index is calculated as glyph = charcode + delta,
69
      # which means that delta must be -0xFFFF to map character code
70
      # 0xFFFF to glyph 0.
71
      deltas << -0xFFFF
72
      range_offsets << 0
73
      break
74
    end
75
76
    start_glyph_id = new_map[a][:new]
77
78
    if a - start_glyph_id >= 0x8000
79
      deltas << 0
80
      range_offsets << (2 * (glyph_indices.length + segcount - segment))
81
      a.upto(b) { |code| glyph_indices << new_map[code][:new] }
82
    else
83
      deltas << (-a + start_glyph_id)
84
      range_offsets << 0
85
    end
86
87
    offset += 2
88
  end
89
90
  # format, length, language
91
  subtable = [
92
    4, 16 + (8 * segcount) + (2 * glyph_indices.length), 0,
93
  ].pack('nnn')
94
95
  search_range = 2 * (2**Integer(Math.log(segcount) / Math.log(2)))
96
  entry_selector = Integer(Math.log(search_range / 2) / Math.log(2))
97
  range_shift = (2 * segcount) - search_range
98
  subtable << [
99
    segcount * 2, search_range, entry_selector, range_shift,
100
  ].pack('nnnn')
101
102
  subtable << end_codes.pack('n*') << "\0\0" << start_codes.pack('n*')
103
  subtable << deltas.pack('n*') << range_offsets.pack('n*')
104
  subtable << glyph_indices.pack('n*')
105
106
  { charmap: new_map, subtable: subtable, max_glyph_id: next_id + 1 }
107
end

Instance Method Details

#[](code) ⇒ Integer

Get glyph ID for character code.

Parameters:

  • code (Integer)

    character code.

Returns:

  • (Integer)

    glyph ID.

Source Code
lib/ttfunk/table/cmap/format04.rb, line 113
113
def [](code)
114
  @code_map[code] || 0
115
end

#supported?true

Is this encoding record format supported?

Returns:

  • (true)
Source Code
lib/ttfunk/table/cmap/format04.rb, line 120
120
def supported?
121
  true
122
end