ttfunk 1.7.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +74 -0
  4. data/README.md +17 -15
  5. data/lib/ttfunk/aggregate.rb +5 -0
  6. data/lib/ttfunk/bin_utils.rb +27 -8
  7. data/lib/ttfunk/bit_field.rb +25 -2
  8. data/lib/ttfunk/collection.rb +27 -3
  9. data/lib/ttfunk/directory.rb +7 -1
  10. data/lib/ttfunk/encoded_string.rb +58 -4
  11. data/lib/ttfunk/max.rb +14 -0
  12. data/lib/ttfunk/min.rb +14 -0
  13. data/lib/ttfunk/one_based_array.rb +20 -0
  14. data/lib/ttfunk/otf_encoder.rb +5 -14
  15. data/lib/ttfunk/placeholder.rb +15 -1
  16. data/lib/ttfunk/reader.rb +6 -4
  17. data/lib/ttfunk/resource_file.rb +29 -5
  18. data/lib/ttfunk/sci_form.rb +20 -3
  19. data/lib/ttfunk/sub_table.rb +29 -4
  20. data/lib/ttfunk/subset/base.rb +48 -0
  21. data/lib/ttfunk/subset/code_page.rb +49 -2
  22. data/lib/ttfunk/subset/mac_roman.rb +2 -0
  23. data/lib/ttfunk/subset/unicode.rb +32 -0
  24. data/lib/ttfunk/subset/unicode_8bit.rb +32 -0
  25. data/lib/ttfunk/subset/windows_1252.rb +2 -0
  26. data/lib/ttfunk/subset.rb +8 -0
  27. data/lib/ttfunk/subset_collection.rb +39 -14
  28. data/lib/ttfunk/sum.rb +13 -0
  29. data/lib/ttfunk/table/cff/charset.rb +96 -18
  30. data/lib/ttfunk/table/cff/charsets/expert.rb +3 -2
  31. data/lib/ttfunk/table/cff/charsets/expert_subset.rb +3 -2
  32. data/lib/ttfunk/table/cff/charsets/iso_adobe.rb +3 -2
  33. data/lib/ttfunk/table/cff/charsets/standard_strings.rb +3 -2
  34. data/lib/ttfunk/table/cff/charsets.rb +1 -0
  35. data/lib/ttfunk/table/cff/charstring.rb +33 -12
  36. data/lib/ttfunk/table/cff/charstrings_index.rb +17 -11
  37. data/lib/ttfunk/table/cff/dict.rb +53 -23
  38. data/lib/ttfunk/table/cff/encoding.rb +82 -24
  39. data/lib/ttfunk/table/cff/encodings/expert.rb +3 -2
  40. data/lib/ttfunk/table/cff/encodings/standard.rb +3 -2
  41. data/lib/ttfunk/table/cff/encodings.rb +1 -0
  42. data/lib/ttfunk/table/cff/fd_selector.rb +61 -21
  43. data/lib/ttfunk/table/cff/font_dict.rb +30 -18
  44. data/lib/ttfunk/table/cff/font_index.rb +22 -10
  45. data/lib/ttfunk/table/cff/header.rb +16 -3
  46. data/lib/ttfunk/table/cff/index.rb +97 -65
  47. data/lib/ttfunk/table/cff/one_based_index.rb +11 -1
  48. data/lib/ttfunk/table/cff/path.rb +43 -4
  49. data/lib/ttfunk/table/cff/private_dict.rb +31 -11
  50. data/lib/ttfunk/table/cff/subr_index.rb +7 -2
  51. data/lib/ttfunk/table/cff/top_dict.rb +82 -59
  52. data/lib/ttfunk/table/cff/top_index.rb +10 -6
  53. data/lib/ttfunk/table/cff.rb +41 -21
  54. data/lib/ttfunk/table/cmap/format00.rb +27 -6
  55. data/lib/ttfunk/table/cmap/format04.rb +34 -14
  56. data/lib/ttfunk/table/cmap/format06.rb +28 -1
  57. data/lib/ttfunk/table/cmap/format10.rb +29 -2
  58. data/lib/ttfunk/table/cmap/format12.rb +29 -2
  59. data/lib/ttfunk/table/cmap/subtable.rb +50 -6
  60. data/lib/ttfunk/table/cmap.rb +21 -0
  61. data/lib/ttfunk/table/dsig.rb +47 -6
  62. data/lib/ttfunk/table/glyf/compound.rb +73 -6
  63. data/lib/ttfunk/table/glyf/path_based.rb +40 -3
  64. data/lib/ttfunk/table/glyf/simple.rb +50 -5
  65. data/lib/ttfunk/table/glyf.rb +15 -7
  66. data/lib/ttfunk/table/head.rb +84 -6
  67. data/lib/ttfunk/table/hhea.rb +71 -10
  68. data/lib/ttfunk/table/hmtx.rb +32 -5
  69. data/lib/ttfunk/table/kern/format0.rb +25 -7
  70. data/lib/ttfunk/table/kern.rb +16 -4
  71. data/lib/ttfunk/table/loca.rb +21 -8
  72. data/lib/ttfunk/table/maxp.rb +195 -10
  73. data/lib/ttfunk/table/name.rb +126 -9
  74. data/lib/ttfunk/table/os2.rb +150 -26
  75. data/lib/ttfunk/table/post/format10.rb +7 -0
  76. data/lib/ttfunk/table/post/format20.rb +9 -0
  77. data/lib/ttfunk/table/post/format30.rb +6 -0
  78. data/lib/ttfunk/table/post/format40.rb +5 -0
  79. data/lib/ttfunk/table/post.rb +63 -7
  80. data/lib/ttfunk/table/sbix.rb +50 -14
  81. data/lib/ttfunk/table/simple.rb +5 -0
  82. data/lib/ttfunk/table/vorg.rb +31 -3
  83. data/lib/ttfunk/table.rb +20 -1
  84. data/lib/ttfunk/ttf_encoder.rb +39 -41
  85. data/lib/ttfunk.rb +154 -1
  86. data.tar.gz.sig +0 -0
  87. metadata +50 -28
  88. metadata.gz.sig +0 -0
@@ -3,26 +3,48 @@
3
3
  require_relative 'subset'
4
4
 
5
5
  module TTFunk
6
+ # Subset collection.
7
+ #
8
+ # For many use cases a font subset can be efficiently encoded using MacRoman
9
+ # encoding. However, for full font coverage and characters that are not in
10
+ # MacRoman encoding an additional Unicode subset is used. There can be as many
11
+ # as needed Unicode subsets to fully cover glyphs provided by the original
12
+ # font. Ther resulting set of subsets all use 8-bit encoding helping to
13
+ # efficiently encode text in Prawn.
6
14
  class SubsetCollection
15
+ # @param original [TTFunk::File]
7
16
  def initialize(original)
8
17
  @original = original
9
18
  @subsets = [Subset.for(@original, :mac_roman)]
10
19
  end
11
20
 
21
+ # Get subset by index.
22
+ #
23
+ # @param subset [Integer]
24
+ # @return [TTFunk::Subset::Unicode, TTFunk::Subset::Unicode8Bit,
25
+ # TTFunk::Subset::MacRoman, TTFunk::Subset::Windows1252]
12
26
  def [](subset)
13
27
  @subsets[subset]
14
28
  end
15
29
 
16
- # +characters+ should be an array of UTF-16 characters
30
+ # Add chracters to appropiate subsets.
31
+ #
32
+ # @param characters [Array<Integer>] should be an array of UTF-16 code
33
+ # points
34
+ # @return [void]
17
35
  def use(characters)
18
36
  characters.each do |char|
19
37
  covered = false
20
- @subsets.each_with_index do |subset, _i|
21
- next unless subset.covers?(char)
22
-
23
- subset.use(char)
24
- covered = true
25
- break
38
+ i = 0
39
+ length = @subsets.length
40
+ while i < length
41
+ subset = @subsets[i]
42
+ if subset.covers?(char)
43
+ subset.use(char)
44
+ covered = true
45
+ break
46
+ end
47
+ i += 1
26
48
  end
27
49
 
28
50
  unless covered
@@ -32,13 +54,16 @@ module TTFunk
32
54
  end
33
55
  end
34
56
 
35
- # +characters+ should be an array of UTF-16 characters. Returns
36
- # an array of subset chunks, where each chunk is another array of
37
- # two elements. The first element is the subset number, and the
38
- # second element is the string of characters to render with that
39
- # font subset. The strings will be encoded for their subset font,
40
- # and so may not look (in the raw) like what was passed in, but
41
- # they will render correctly with the indicated subset font.
57
+ # Encode characters into subset-character pairs.
58
+ #
59
+ # @param characters [Array<Integer>] should be an array of UTF-16 code
60
+ # points
61
+ # @return [Array<Array(Integer, String)>] subset chunks, where each chunk
62
+ # is another array of two elements. The first element is the subset
63
+ # number, and the second element is the string of characters to render
64
+ # with that font subset. The strings will be encoded for their subset
65
+ # font, and so may not look (in the raw) like what was passed in, but they
66
+ # will render correctly with the corresponding subset font.
42
67
  def encode(characters)
43
68
  return [] if characters.empty?
44
69
 
data/lib/ttfunk/sum.rb CHANGED
@@ -1,18 +1,31 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TTFunk
4
+ # Sum aggreaget. Is sums all pushed values.
4
5
  class Sum < Aggregate
6
+ # Value
7
+ #
8
+ # @return [#+]
5
9
  attr_reader :value
6
10
 
11
+ # @param init_value [#+] initial value
7
12
  def initialize(init_value = 0)
8
13
  super()
9
14
  @value = init_value
10
15
  end
11
16
 
17
+ # Push a value. It will be added to the current value.
18
+ #
19
+ # @param operand [any]
20
+ # @return [void]
12
21
  def <<(operand)
13
22
  @value += coerce(operand)
14
23
  end
15
24
 
25
+ # Get the stored value or default.
26
+ #
27
+ # @param _default [any] Unused. Here for API compatibility.
28
+ # @return [any]
16
29
  def value_or(_default)
17
30
  # value should always be non-nil
18
31
  value
@@ -3,25 +3,47 @@
3
3
  module TTFunk
4
4
  class Table
5
5
  class Cff < TTFunk::Table
6
+ # CFF Charset
6
7
  class Charset < TTFunk::SubTable
7
8
  include Enumerable
8
9
 
10
+ # First glyph string. This is an implicit glyph present in all charsets.
9
11
  FIRST_GLYPH_STRING = '.notdef'
12
+
13
+ # Format 0.
10
14
  ARRAY_FORMAT = 0
15
+
16
+ # Format 1.
11
17
  RANGE_FORMAT_8 = 1
18
+
19
+ # Format 2.
12
20
  RANGE_FORMAT_16 = 2
13
21
 
22
+ # Predefined ISOAdobe charset ID.
14
23
  ISO_ADOBE_CHARSET_ID = 0
24
+
25
+ # Predefined Expert charset ID.
15
26
  EXPERT_CHARSET_ID = 1
27
+
28
+ # Predefined Expert Subset charset ID.
16
29
  EXPERT_SUBSET_CHARSET_ID = 2
17
30
 
31
+ # Default charset ID.
18
32
  DEFAULT_CHARSET_ID = ISO_ADOBE_CHARSET_ID
19
33
 
20
34
  class << self
35
+ # Standard strings defined in the spec that do not need to be defined
36
+ # in the CFF.
37
+ #
38
+ # @return [TTFunk::OneBasedArray<String>]
21
39
  def standard_strings
22
40
  Charsets::STANDARD_STRINGS
23
41
  end
24
42
 
43
+ # Strings for charset ID.
44
+ #
45
+ # @param charset_id [Integer]
46
+ # @return [TTFunk::OneBasedArray<String>]
25
47
  def strings_for_charset_id(charset_id)
26
48
  case charset_id
27
49
  when ISO_ADOBE_CHARSET_ID
@@ -34,9 +56,39 @@ module TTFunk
34
56
  end
35
57
  end
36
58
 
37
- attr_reader :entries, :length
38
- attr_reader :top_dict, :format, :count, :offset_or_id
39
-
59
+ # Encoded entries.
60
+ # @return [TTFunk::OneBasedArray<Integer>, Array<Range<Integer>>]
61
+ attr_reader :entries
62
+
63
+ # Length of encoded charset subtable.
64
+ # @return [Integer]
65
+ attr_reader :length
66
+
67
+ # Top dict.
68
+ # @return [TTFunk::Table::Cff::TopDict]
69
+ attr_reader :top_dict
70
+
71
+ # Encodign format.
72
+ # @return [Integer]
73
+ attr_reader :format
74
+
75
+ # Number of encoded items.
76
+ # @return [Integer]
77
+ attr_reader :items_count
78
+
79
+ # Offset or charset ID.
80
+ # @return [Integer]
81
+ attr_reader :offset_or_id
82
+
83
+ # @overload initialize(top_dict, file, offset = nil, length = nil)
84
+ # @param top_dict [TTFunk::Table:Cff::TopDict]
85
+ # @param file [TTFunk::File]
86
+ # @param offset [Integer]
87
+ # @param length [Integer]
88
+ # @overload initialize(top_dict, file, charset_id)
89
+ # @param top_dict [TTFunk::Table:Cff::TopDict]
90
+ # @param file [TTFunk::File]
91
+ # @param charset_id [Integer] 0, 1, or 2
40
92
  def initialize(top_dict, file, offset_or_id = nil, length = nil)
41
93
  @top_dict = top_dict
42
94
  @offset_or_id = offset_or_id || DEFAULT_CHARSET_ID
@@ -44,23 +96,37 @@ module TTFunk
44
96
  if offset
45
97
  super(file, offset, length)
46
98
  else
47
- @count = self.class.strings_for_charset_id(offset_or_id).size
99
+ @items_count = self.class.strings_for_charset_id(offset_or_id).size
48
100
  end
49
101
  end
50
102
 
103
+ # Iterate over character names.
104
+ #
105
+ # @overload each()
106
+ # @yieldparam name [String]
107
+ # @return [void]
108
+ # @overload each()
109
+ # @return [Enumerator]
51
110
  def each
52
111
  return to_enum(__method__) unless block_given?
53
112
 
54
113
  # +1 adjusts for the implicit .notdef glyph
55
- (count + 1).times { |i| yield self[i] }
114
+ (items_count + 1).times { |i| yield(self[i]) }
56
115
  end
57
116
 
117
+ # Get character name for glyph index.
118
+ #
119
+ # @param glyph_id [Integer]
120
+ # @return [String, nil]
58
121
  def [](glyph_id)
59
122
  return FIRST_GLYPH_STRING if glyph_id.zero?
60
123
 
61
124
  find_string(sid_for(glyph_id))
62
125
  end
63
126
 
127
+ # Charset offset in the file.
128
+ #
129
+ # @return [Integer, nil]
64
130
  def offset
65
131
  # Numbers from 0..2 mean charset IDs instead of offsets. IDs are
66
132
  # basically pre-defined sets of characters.
@@ -73,13 +139,25 @@ module TTFunk
73
139
  end
74
140
  end
75
141
 
76
- # mapping is new -> old glyph ids
77
- def encode(mapping)
142
+ # Encode charset.
143
+ #
144
+ # @param charmap [Hash{Integer => Hash}] keys are the charac codes,
145
+ # values are hashes:
146
+ # * `:old` (<tt>Integer</tt>) - glyph ID in the original font.
147
+ # * `:new` (<tt>Integer</tt>) - glyph ID in the subset font.
148
+ # @return [String]
149
+ def encode(charmap)
78
150
  # no offset means no charset was specified (i.e. we're supposed to
79
151
  # use a predefined charset) so there's nothing to encode
80
152
  return '' unless offset
81
153
 
82
- sids = mapping.keys.sort.map { |new_gid| sid_for(mapping[new_gid]) }
154
+ sids =
155
+ charmap
156
+ .values
157
+ .reject { |mapping| mapping[:new].zero? }
158
+ .sort_by { |mapping| mapping[:new] }
159
+ .map { |mapping| sid_for(mapping[:old]) }
160
+
83
161
  ranges = TTFunk::BinUtils.rangify(sids)
84
162
  range_max = ranges.map(&:last).max
85
163
 
@@ -138,7 +216,7 @@ module TTFunk
138
216
 
139
217
  idx = sid - 390
140
218
 
141
- if idx < file.cff.string_index.count
219
+ if idx < file.cff.string_index.items_count
142
220
  file.cff.string_index[idx]
143
221
  end
144
222
  else
@@ -153,23 +231,23 @@ module TTFunk
153
231
 
154
232
  case format_sym
155
233
  when :array_format
156
- @count = top_dict.charstrings_index.count - 1
157
- @length = count * element_width
234
+ @items_count = top_dict.charstrings_index.items_count - 1
235
+ @length = @items_count * element_width
158
236
  @entries = OneBasedArray.new(read(length, 'n*'))
159
237
 
160
238
  when :range_format8, :range_format16
161
239
  # The number of ranges is not explicitly specified in the font.
162
240
  # Instead, software utilizing this data simply processes ranges
163
241
  # until all glyphs in the font are covered.
164
- @count = 0
242
+ @items_count = 0
165
243
  @entries = []
166
244
  @length = 0
167
245
 
168
- until count >= top_dict.charstrings_index.count - 1
246
+ until @items_count >= top_dict.charstrings_index.items_count - 1
169
247
  @length += 1 + element_width
170
248
  sid, num_left = read(element_width, element_format)
171
- entries << (sid..(sid + num_left))
172
- @count += num_left + 1
249
+ @entries << (sid..(sid + num_left))
250
+ @items_count += num_left + 1
173
251
  end
174
252
  end
175
253
  end
@@ -178,7 +256,7 @@ module TTFunk
178
256
  {
179
257
  array_format: 2, # SID
180
258
  range_format8: 3, # SID + Card8
181
- range_format16: 4 # SID + Card16
259
+ range_format16: 4, # SID + Card16
182
260
  }[fmt]
183
261
  end
184
262
 
@@ -186,7 +264,7 @@ module TTFunk
186
264
  {
187
265
  array_format: 'n',
188
266
  range_format8: 'nC',
189
- range_format16: 'nn'
267
+ range_format16: 'nn',
190
268
  }[fmt]
191
269
  end
192
270
 
@@ -204,7 +282,7 @@ module TTFunk
204
282
  {
205
283
  array_format: ARRAY_FORMAT,
206
284
  range_format8: RANGE_FORMAT_8,
207
- range_format16: RANGE_FORMAT_16
285
+ range_format16: RANGE_FORMAT_16,
208
286
  }[sym]
209
287
  end
210
288
  end
@@ -4,6 +4,7 @@ module TTFunk
4
4
  class Table
5
5
  class Cff < TTFunk::Table
6
6
  module Charsets
7
+ # Predefinde CFF Expert charset
7
8
  EXPERT = OneBasedArray.new(
8
9
  [
9
10
  'space',
@@ -180,8 +181,8 @@ module TTFunk
180
181
  'Ucircumflexsmall',
181
182
  'Udieresissmall',
182
183
  'Yacutesmall',
183
- 'Thornsmall'
184
- ]
184
+ 'Thornsmall',
185
+ ],
185
186
  ).freeze
186
187
  end
187
188
  end
@@ -4,6 +4,7 @@ module TTFunk
4
4
  class Table
5
5
  class Cff < TTFunk::Table
6
6
  module Charsets
7
+ # Predefined CFF Expert Subset charset
7
8
  EXPERT_SUBSET = OneBasedArray.new(
8
9
  [
9
10
  'space',
@@ -110,8 +111,8 @@ module TTFunk
110
111
  'nineinferior',
111
112
  'centinferior',
112
113
  'dollarinferior',
113
- 'periodinferior'
114
- ]
114
+ 'periodinferior',
115
+ ],
115
116
  ).freeze
116
117
  end
117
118
  end
@@ -4,6 +4,7 @@ module TTFunk
4
4
  class Table
5
5
  class Cff < TTFunk::Table
6
6
  module Charsets
7
+ # Predefined CFF ISOAdobe charset
7
8
  ISO_ADOBE = OneBasedArray.new(
8
9
  [
9
10
  'space',
@@ -232,8 +233,8 @@ module TTFunk
232
233
  'ugrave',
233
234
  'yacute',
234
235
  'ydieresis',
235
- 'zcaron'
236
- ]
236
+ 'zcaron',
237
+ ],
237
238
  ).freeze
238
239
  end
239
240
  end
@@ -4,6 +4,7 @@ module TTFunk
4
4
  class Table
5
5
  class Cff < TTFunk::Table
6
6
  module Charsets
7
+ # Standard CFF strings
7
8
  STANDARD_STRINGS = OneBasedArray.new(
8
9
  [
9
10
  'space',
@@ -395,8 +396,8 @@ module TTFunk
395
396
  'Medium',
396
397
  'Regular',
397
398
  'Roman',
398
- 'Semibold'
399
- ]
399
+ 'Semibold',
400
+ ],
400
401
  ).freeze
401
402
  end
402
403
  end
@@ -3,6 +3,7 @@
3
3
  module TTFunk
4
4
  class Table
5
5
  class Cff < TTFunk::Table
6
+ # Predefined CFF data
6
7
  module Charsets
7
8
  autoload :EXPERT, 'ttfunk/table/cff/charsets/expert'
8
9
  autoload :EXPERT_SUBSET, 'ttfunk/table/cff/charsets/expert_subset'
@@ -3,7 +3,9 @@
3
3
  module TTFunk
4
4
  class Table
5
5
  class Cff < TTFunk::Table
6
+ # CFF Charstring.
6
7
  class Charstring
8
+ # Type 2 charstring operators
7
9
  CODE_MAP = {
8
10
  1 => :hstem,
9
11
  3 => :vstem,
@@ -28,18 +30,29 @@ module TTFunk
28
30
  28 => :shortint,
29
31
  29 => :callgsubr,
30
32
  30 => :vhcurveto,
31
- 31 => :hvcurveto
33
+ 31 => :hvcurveto,
32
34
  }.freeze
33
35
 
36
+ # Type 2 Flex operators.
34
37
  FLEX_CODE_MAP = {
35
38
  35 => :flex,
36
39
  34 => :hflex,
37
40
  36 => :hflex1,
38
- 37 => :flex1
41
+ 37 => :flex1,
39
42
  }.freeze
40
43
 
41
- attr_reader :glyph_id, :raw
44
+ # Glyph ID.
45
+ # @return [Integer]
46
+ attr_reader :glyph_id
42
47
 
48
+ # Encoded charstring.
49
+ # @return [String]
50
+ attr_reader :raw
51
+
52
+ # @param glyph_id [Integer]
53
+ # @param top_dict [TTFunk::Table:Cff::TopDict]
54
+ # @param font_dict [TTFunk::Table:Cff::FontDict]
55
+ # @param raw [String]
43
56
  def initialize(glyph_id, top_dict, font_dict, raw)
44
57
  @glyph_id = glyph_id
45
58
  @top_dict = top_dict
@@ -66,6 +79,9 @@ module TTFunk
66
79
  @y = 0
67
80
  end
68
81
 
82
+ # Get path representation of this charstring.
83
+ #
84
+ # @return [TTFunk::Table::Cff::Path]
69
85
  def path
70
86
  @path || begin
71
87
  @path = Path.new
@@ -74,6 +90,9 @@ module TTFunk
74
90
  end
75
91
  end
76
92
 
93
+ # Get a TrueType-compatible glyph representation of this charstring.
94
+ #
95
+ # @return [TTFunk::Table::Glyf::PathBased]
77
96
  def glyph
78
97
  @glyph ||=
79
98
  begin
@@ -82,19 +101,21 @@ module TTFunk
82
101
  end
83
102
  end
84
103
 
104
+ # Get path representation of this charstring at the specified font size.
105
+ #
106
+ # @param x [Integer, Float] new horizontal position.
107
+ # @param y [Integer, Float] new vertical position.
108
+ # @param font_size [Integer, Float] font size.
109
+ # @return [TTFunk::Table::Cff::Path]
85
110
  def render(x: 0, y: 0, font_size: 72)
86
111
  path.render(
87
112
  x: x,
88
113
  y: y,
89
114
  font_size: font_size,
90
- units_per_em: @top_dict.file.header.units_per_em
115
+ units_per_em: @top_dict.file.header.units_per_em,
91
116
  )
92
117
  end
93
118
 
94
- def encode
95
- raw
96
- end
97
-
98
119
  private
99
120
 
100
121
  def parse!
@@ -106,22 +127,22 @@ module TTFunk
106
127
  next if code == 11
107
128
 
108
129
  if code >= 32 && code <= 246
109
- @stack << code - 139
130
+ @stack << (code - 139)
110
131
  elsif (m = CODE_MAP[code])
111
132
  __send__(m)
112
133
  elsif code >= 247 && code <= 250
113
134
  b0 = code
114
135
  b1 = @data[@index]
115
136
  @index += 1
116
- @stack << (b0 - 247) * 256 + b1 + 108
137
+ @stack << (((b0 - 247) * 256) + b1 + 108)
117
138
  elsif code >= 251 && code <= 254
118
139
  b0 = code
119
140
  b1 = @data[@index]
120
141
  @index += 1
121
- @stack << -(b0 - 251) * 256 - b1 - 108
142
+ @stack << ((-(b0 - 251) * 256) - b1 - 108)
122
143
  else
123
144
  b1, b2, b3, b4 = read_bytes(4)
124
- @stack << ((b1 << 24) | (b2 << 16) | (b3 << 8) | b4) / 65_536
145
+ @stack << (((b1 << 24) | (b2 << 16) | (b3 << 8) | b4) / 65_536)
125
146
  end
126
147
  end
127
148
  end
@@ -3,28 +3,34 @@
3
3
  module TTFunk
4
4
  class Table
5
5
  class Cff < TTFunk::Table
6
+ # CFF Charstrings Index.
6
7
  class CharstringsIndex < TTFunk::Table::Cff::Index
8
+ # Top dict.
9
+ # @return [TTFunk::Table::Cff::TopDict]
7
10
  attr_reader :top_dict
8
11
 
12
+ # @overload initialize(top_dict, file, offset, length = nil)
13
+ # @param top_dict [TTFunk::Table:Cff::TopDict]
14
+ # @param file [TTFunk::File]
15
+ # @param offset [Integer]
16
+ # @param length [Integer]
9
17
  def initialize(top_dict, *remaining_args)
10
18
  super(*remaining_args)
11
19
  @top_dict = top_dict
12
20
  end
13
21
 
14
- def [](index)
15
- entry_cache[index] ||= TTFunk::Table::Cff::Charstring.new(
16
- index, top_dict, font_dict_for(index), super
17
- )
18
- end
22
+ private
19
23
 
20
- # gets passed a mapping of new => old glyph ids
21
- def encode(mapping)
22
- super() do |_entry, index|
23
- self[mapping[index]].encode if mapping.include?(index)
24
- end
24
+ def decode_item(index, _offset, _length)
25
+ TTFunk::Table::Cff::Charstring.new(index, top_dict, font_dict_for(index), super)
25
26
  end
26
27
 
27
- private
28
+ def encode_items(charmap)
29
+ charmap
30
+ .reject { |code, mapping| mapping[:new].zero? && !code.zero? }
31
+ .sort_by { |_code, mapping| mapping[:new] }
32
+ .map { |(_code, mapping)| items[mapping[:old]] }
33
+ end
28
34
 
29
35
  def font_dict_for(index)
30
36
  # only CID-keyed fonts contain an FD selector and font dicts