ttfunk 1.7.0 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
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