ttfunk 1.6.2.1 → 1.7.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 (56) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +2 -1
  3. data.tar.gz.sig +0 -0
  4. data/CHANGELOG.md +15 -1
  5. data/lib/ttfunk.rb +3 -2
  6. data/lib/ttfunk/bit_field.rb +1 -1
  7. data/lib/ttfunk/collection.rb +8 -2
  8. data/lib/ttfunk/encoded_string.rb +3 -3
  9. data/lib/ttfunk/max.rb +1 -0
  10. data/lib/ttfunk/min.rb +1 -0
  11. data/lib/ttfunk/one_based_array.rb +1 -1
  12. data/lib/ttfunk/otf_encoder.rb +1 -1
  13. data/lib/ttfunk/reader.rb +3 -3
  14. data/lib/ttfunk/sci_form.rb +1 -1
  15. data/lib/ttfunk/subset.rb +3 -3
  16. data/lib/ttfunk/subset/base.rb +24 -21
  17. data/lib/ttfunk/subset/code_page.rb +16 -19
  18. data/lib/ttfunk/subset/unicode.rb +8 -6
  19. data/lib/ttfunk/subset/unicode_8bit.rb +14 -12
  20. data/lib/ttfunk/sum.rb +1 -0
  21. data/lib/ttfunk/table/cff.rb +17 -17
  22. data/lib/ttfunk/table/cff/charset.rb +31 -30
  23. data/lib/ttfunk/table/cff/charsets.rb +3 -3
  24. data/lib/ttfunk/table/cff/charstring.rb +54 -55
  25. data/lib/ttfunk/table/cff/dict.rb +6 -4
  26. data/lib/ttfunk/table/cff/encoding.rb +20 -21
  27. data/lib/ttfunk/table/cff/encodings.rb +1 -1
  28. data/lib/ttfunk/table/cff/fd_selector.rb +14 -11
  29. data/lib/ttfunk/table/cff/font_index.rb +7 -6
  30. data/lib/ttfunk/table/cff/index.rb +6 -5
  31. data/lib/ttfunk/table/cff/one_based_index.rb +7 -3
  32. data/lib/ttfunk/table/cff/path.rb +5 -3
  33. data/lib/ttfunk/table/cff/top_dict.rb +7 -6
  34. data/lib/ttfunk/table/cff/top_index.rb +5 -4
  35. data/lib/ttfunk/table/cmap.rb +8 -6
  36. data/lib/ttfunk/table/cmap/format00.rb +7 -6
  37. data/lib/ttfunk/table/cmap/format04.rb +16 -15
  38. data/lib/ttfunk/table/cmap/format06.rb +6 -5
  39. data/lib/ttfunk/table/cmap/format10.rb +6 -5
  40. data/lib/ttfunk/table/cmap/format12.rb +13 -12
  41. data/lib/ttfunk/table/cmap/subtable.rb +4 -4
  42. data/lib/ttfunk/table/dsig.rb +11 -9
  43. data/lib/ttfunk/table/glyf.rb +3 -3
  44. data/lib/ttfunk/table/glyf/compound.rb +8 -8
  45. data/lib/ttfunk/table/hmtx.rb +6 -5
  46. data/lib/ttfunk/table/kern.rb +4 -4
  47. data/lib/ttfunk/table/kern/format0.rb +1 -1
  48. data/lib/ttfunk/table/loca.rb +7 -6
  49. data/lib/ttfunk/table/name.rb +6 -5
  50. data/lib/ttfunk/table/os2.rb +261 -151
  51. data/lib/ttfunk/table/post.rb +1 -1
  52. data/lib/ttfunk/table/sbix.rb +15 -13
  53. data/lib/ttfunk/table/vorg.rb +1 -1
  54. data/lib/ttfunk/ttf_encoder.rb +4 -4
  55. metadata +29 -99
  56. metadata.gz.sig +0 -0
@@ -4,9 +4,9 @@ module TTFunk
4
4
  class Table
5
5
  class Cff < TTFunk::Table
6
6
  module Charsets
7
- autoload :EXPERT, 'ttfunk/table/cff/charsets/expert'
8
- autoload :EXPERT_SUBSET, 'ttfunk/table/cff/charsets/expert_subset'
9
- autoload :ISO_ADOBE, 'ttfunk/table/cff/charsets/iso_adobe'
7
+ autoload :EXPERT, 'ttfunk/table/cff/charsets/expert'
8
+ autoload :EXPERT_SUBSET, 'ttfunk/table/cff/charsets/expert_subset'
9
+ autoload :ISO_ADOBE, 'ttfunk/table/cff/charsets/iso_adobe'
10
10
  autoload :STANDARD_STRINGS, 'ttfunk/table/cff/charsets/standard_strings'
11
11
  end
12
12
  end
@@ -46,11 +46,9 @@ module TTFunk
46
46
  @font_dict = font_dict
47
47
  @raw = raw
48
48
 
49
- default_width_x = (@font_dict || @top_dict)
50
- .private_dict.default_width_x
49
+ default_width_x = (@font_dict || @top_dict).private_dict.default_width_x
51
50
 
52
- @nominal_width_x = (@font_dict || @top_dict)
53
- .private_dict.nominal_width_x
51
+ @nominal_width_x = (@font_dict || @top_dict).private_dict.nominal_width_x
54
52
 
55
53
  @subrs = (@font_dict || @top_dict).private_dict.subr_index
56
54
  @gsubrs = @top_dict.cff.global_subr_index
@@ -77,10 +75,11 @@ module TTFunk
77
75
  end
78
76
 
79
77
  def glyph
80
- @glyph ||= begin
81
- horizontal_metrics = @top_dict.file.horizontal_metrics.for(glyph_id)
82
- Glyf::PathBased.new(path, horizontal_metrics)
83
- end
78
+ @glyph ||=
79
+ begin
80
+ horizontal_metrics = @top_dict.file.horizontal_metrics.for(glyph_id)
81
+ Glyf::PathBased.new(path, horizontal_metrics)
82
+ end
84
83
  end
85
84
 
86
85
  def render(x: 0, y: 0, font_size: 72)
@@ -109,7 +108,7 @@ module TTFunk
109
108
  if code >= 32 && code <= 246
110
109
  @stack << code - 139
111
110
  elsif (m = CODE_MAP[code])
112
- send(m)
111
+ __send__(m)
113
112
  elsif code >= 247 && code <= 250
114
113
  b0 = code
115
114
  b1 = @data[@index]
@@ -229,73 +228,73 @@ module TTFunk
229
228
  def flex_select
230
229
  flex_code = @data[@index]
231
230
  @index += 1
232
- send(FLEX_CODE_MAP[flex_code])
231
+ __send__(FLEX_CODE_MAP[flex_code])
233
232
  end
234
233
 
235
234
  def flex
236
- c1x = @x + @stack.shift # dx1
237
- c1y = @y + @stack.shift # dy1
238
- c2x = c1x + @stack.shift # dx2
239
- c2y = c1y + @stack.shift # dy2
240
- jpx = c2x + @stack.shift # dx3
241
- jpy = c2y + @stack.shift # dy3
242
- c3x = jpx + @stack.shift # dx4
243
- c3y = jpy + @stack.shift # dy4
244
- c4x = c3x + @stack.shift # dx5
245
- c4y = c3y + @stack.shift # dy5
246
- @x = c4x + @stack.shift # dx6
247
- @y = c4y + @stack.shift # dy6
248
- @stack.shift # flex depth
235
+ c1x = @x + @stack.shift # dx1
236
+ c1y = @y + @stack.shift # dy1
237
+ c2x = c1x + @stack.shift # dx2
238
+ c2y = c1y + @stack.shift # dy2
239
+ jpx = c2x + @stack.shift # dx3
240
+ jpy = c2y + @stack.shift # dy3
241
+ c3x = jpx + @stack.shift # dx4
242
+ c3y = jpy + @stack.shift # dy4
243
+ c4x = c3x + @stack.shift # dx5
244
+ c4y = c3y + @stack.shift # dy5
245
+ @x = c4x + @stack.shift # dx6
246
+ @y = c4y + @stack.shift # dy6
247
+ @stack.shift # flex depth
249
248
 
250
249
  @path.curve_to(c1x, c1y, c2x, c2y, jpx, jpy)
251
250
  @path.curve_to(c3x, c3y, c4x, c4y, @x, @y)
252
251
  end
253
252
 
254
253
  def hflex
255
- c1x = @x + @stack.shift # dx1
256
- c1y = @y # dy1
257
- c2x = c1x + @stack.shift # dx2
258
- c2y = c1y + @stack.shift # dy2
259
- jpx = c2x + @stack.shift # dx3
260
- jpy = c2y # dy3
261
- c3x = jpx + stack.shift # dx4
262
- c3y = c2y # dy4
263
- c4x = c3x + stack.shift # dx5
264
- c4y = @y # dy5
265
- @x = c4x + stack.shift # dx6
254
+ c1x = @x + @stack.shift # dx1
255
+ c1y = @y # dy1
256
+ c2x = c1x + @stack.shift # dx2
257
+ c2y = c1y + @stack.shift # dy2
258
+ jpx = c2x + @stack.shift # dx3
259
+ jpy = c2y # dy3
260
+ c3x = jpx + stack.shift # dx4
261
+ c3y = c2y # dy4
262
+ c4x = c3x + stack.shift # dx5
263
+ c4y = @y # dy5
264
+ @x = c4x + stack.shift # dx6
266
265
 
267
266
  @path.curve_to(c1x, c1y, c2x, c2y, jpx, jpy)
268
267
  @path.curve_to(c3x, c3y, c4x, c4y, @x, @y)
269
268
  end
270
269
 
271
270
  def hflex1
272
- c1x = @x + @stack.shift # dx1
273
- c1y = @y + @stack.shift # dy1
274
- c2x = c1x + @stack.shift # dx2
275
- c2y = c1y + @stack.shift # dy2
276
- jpx = c2x + @stack.shift # dx3
277
- jpy = c2y # dy3
278
- c3x = jpx + @stack.shift # dx4
279
- c3y = c2y # dy4
280
- c4x = c3x + @stack.shift # dx5
281
- c4y = c3y + @stack.shift # dy5
282
- @x = c4x + @stack.shift # dx6
271
+ c1x = @x + @stack.shift # dx1
272
+ c1y = @y + @stack.shift # dy1
273
+ c2x = c1x + @stack.shift # dx2
274
+ c2y = c1y + @stack.shift # dy2
275
+ jpx = c2x + @stack.shift # dx3
276
+ jpy = c2y # dy3
277
+ c3x = jpx + @stack.shift # dx4
278
+ c3y = c2y # dy4
279
+ c4x = c3x + @stack.shift # dx5
280
+ c4y = c3y + @stack.shift # dy5
281
+ @x = c4x + @stack.shift # dx6
283
282
 
284
283
  @path.curve_to(c1x, c1y, c2x, c2y, jpx, jpy)
285
284
  @path.curve_to(c3x, c3y, c4x, c4y, @x, @y)
286
285
  end
287
286
 
288
287
  def flex1
289
- c1x = @x + @stack.shift # dx1
290
- c1y = @y + @stack.shift # dy1
291
- c2x = c1x + @stack.shift # dx2
292
- c2y = c1y + @stack.shift # dy2
293
- jpx = c2x + @stack.shift # dx3
294
- jpy = c2y + @stack.shift # dy3
295
- c3x = jpx + @stack.shift # dx4
296
- c3y = jpy + @stack.shift # dy4
297
- c4x = c3x + @stack.shift # dx5
298
- c4y = c3y + @stack.shift # dy5
288
+ c1x = @x + @stack.shift # dx1
289
+ c1y = @y + @stack.shift # dy1
290
+ c2x = c1x + @stack.shift # dx2
291
+ c2y = c1y + @stack.shift # dy2
292
+ jpx = c2x + @stack.shift # dx3
293
+ jpy = c2y + @stack.shift # dy3
294
+ c3x = jpx + @stack.shift # dx4
295
+ c3y = jpy + @stack.shift # dy4
296
+ c4x = c3x + @stack.shift # dx5
297
+ c4y = c3y + @stack.shift # dy5
299
298
 
300
299
  if (c4x - @x).abs > (c4y - @y).abs
301
300
  @x = c4x + @stack.shift
@@ -7,6 +7,7 @@ module TTFunk
7
7
  class Cff < TTFunk::Table
8
8
  class Dict < TTFunk::SubTable
9
9
  class InvalidOperandError < StandardError; end
10
+
10
11
  class TooManyOperandsError < StandardError; end
11
12
 
12
13
  # for regular single-byte operators
@@ -103,9 +104,9 @@ module TTFunk
103
104
  end
104
105
 
105
106
  def encode_exponent(exp)
106
- return [] if exp == 0
107
+ return [] if exp.zero?
107
108
 
108
- [exp > 0 ? 0xB : 0xC, *encode_significand(exp.abs)]
109
+ [exp.positive? ? 0xB : 0xC, *encode_significand(exp.abs)]
109
110
  end
110
111
 
111
112
  def encode_significand(sig)
@@ -154,11 +155,12 @@ module TTFunk
154
155
  operands << decode_operand(b_zero)
155
156
 
156
157
  if operands.size > MAX_OPERANDS
157
- raise TooManyOperandsError, 'found one too many operands at '\
158
+ raise TooManyOperandsError,
159
+ 'found one too many operands at '\
158
160
  "position #{io.pos} in dict at position #{table_offset}"
159
161
  end
160
162
  else
161
- raise "dict byte value #{b_zero} is reserved"
163
+ raise Error, "dict byte value #{b_zero} is reserved"
162
164
  end
163
165
  end
164
166
  end
@@ -43,7 +43,7 @@ module TTFunk
43
43
  end
44
44
 
45
45
  def [](glyph_id)
46
- return 0 if glyph_id == 0
46
+ return 0 if glyph_id.zero?
47
47
  return code_for(glyph_id) if offset
48
48
 
49
49
  self.class.codes_for_encoding_id(offset_or_id)[glyph_id]
@@ -68,9 +68,10 @@ module TTFunk
68
68
  return '' unless offset
69
69
  return encode_supplemental(new_to_old, old_to_new) if supplemental?
70
70
 
71
- codes = new_to_old.keys.sort.map do |new_gid|
72
- code_for(new_to_old[new_gid])
73
- end
71
+ codes =
72
+ new_to_old.keys.sort.map do |new_gid|
73
+ code_for(new_to_old[new_gid])
74
+ end
74
75
 
75
76
  ranges = TTFunk::BinUtils.rangify(codes)
76
77
 
@@ -100,11 +101,12 @@ module TTFunk
100
101
  private
101
102
 
102
103
  def encode_supplemental(_new_to_old, old_to_new)
103
- new_entries = @entries.each_with_object({}) do |(code, old_gid), ret|
104
- if (new_gid = old_to_new[old_gid])
105
- ret[code] = new_gid
104
+ new_entries =
105
+ @entries.each_with_object({}) do |(code, old_gid), ret|
106
+ if (new_gid = old_to_new[old_gid])
107
+ ret[code] = new_gid
108
+ end
106
109
  end
107
- end
108
110
 
109
111
  result = [format_int(:supplemental), new_entries.size].pack('CC')
110
112
  fmt = element_format(:supplemental)
@@ -117,14 +119,14 @@ module TTFunk
117
119
  end
118
120
 
119
121
  def code_for(glyph_id)
120
- return 0 if glyph_id == 0
122
+ return 0 if glyph_id.zero?
121
123
 
122
124
  # rather than validating the glyph as part of one of the predefined
123
125
  # encodings, just pass it through
124
126
  return glyph_id unless offset
125
127
 
126
128
  case format_sym
127
- when :array_format
129
+ when :array_format, :supplemental
128
130
  @entries[glyph_id]
129
131
 
130
132
  when :range_format
@@ -139,9 +141,6 @@ module TTFunk
139
141
  end
140
142
 
141
143
  0
142
-
143
- when :supplemental
144
- @entries[glyph_id]
145
144
  end
146
145
  end
147
146
 
@@ -176,11 +175,11 @@ module TTFunk
176
175
  end
177
176
 
178
177
  def element_format(fmt = format_sym)
179
- case fmt
180
- when :array_format then 'C'
181
- when :range_format then 'CC'
182
- when :supplemental then 'Cn'
183
- end
178
+ {
179
+ array_format: 'C',
180
+ range_format: 'CC',
181
+ supplemental: 'Cn'
182
+ }[fmt]
184
183
  end
185
184
 
186
185
  # @TODO: handle supplemental encoding (necessary?)
@@ -190,7 +189,7 @@ module TTFunk
190
189
  when :range_format then 2
191
190
  when :supplemental then 3
192
191
  else
193
- raise "'#{fmt}' is an unsupported encoding format"
192
+ raise Error, "'#{fmt}' is an unsupported encoding format"
194
193
  end
195
194
  end
196
195
 
@@ -201,7 +200,7 @@ module TTFunk
201
200
  when 0 then :array_format
202
201
  when 1 then :range_format
203
202
  else
204
- raise "unsupported charset format '#{fmt}'"
203
+ raise Error, "unsupported charset format '#{fmt}'"
205
204
  end
206
205
  end
207
206
 
@@ -211,7 +210,7 @@ module TTFunk
211
210
  when :range_format then 1
212
211
  when :supplemental then 129
213
212
  else
214
- raise "unsupported charset format '#{sym}'"
213
+ raise Error, "unsupported charset format '#{sym}'"
215
214
  end
216
215
  end
217
216
  end
@@ -4,7 +4,7 @@ module TTFunk
4
4
  class Table
5
5
  class Cff < TTFunk::Table
6
6
  module Encodings
7
- autoload :EXPERT, 'ttfunk/table/cff/encodings/expert'
7
+ autoload :EXPERT, 'ttfunk/table/cff/encodings/expert'
8
8
  autoload :STANDARD, 'ttfunk/table/cff/encodings/standard'
9
9
  end
10
10
  end
@@ -29,7 +29,8 @@ module TTFunk
29
29
  return entry
30
30
  end
31
31
 
32
- range, entry = entries.bsearch do |rng, _|
32
+ range, entry =
33
+ entries.bsearch do |rng, _|
33
34
  if rng.cover?(glyph_id)
34
35
  0
35
36
  elsif glyph_id < rng.first
@@ -53,9 +54,10 @@ module TTFunk
53
54
  # mapping is new -> old glyph ids
54
55
  def encode(mapping)
55
56
  # get list of [new_gid, fd_index] pairs
56
- new_indices = mapping.keys.sort.map do |new_gid|
57
- [new_gid, self[mapping[new_gid]]]
58
- end
57
+ new_indices =
58
+ mapping.keys.sort.map do |new_gid|
59
+ [new_gid, self[mapping[new_gid]]]
60
+ end
59
61
 
60
62
  ranges = rangify_gids(new_indices)
61
63
  total_range_size = ranges.size * RANGE_ENTRY_SIZE
@@ -119,11 +121,12 @@ module TTFunk
119
121
 
120
122
  ranges = Array.new(num_ranges) { read(RANGE_ENTRY_SIZE, 'nC') }
121
123
 
122
- @entries = ranges.each_cons(2).map do |first, second|
123
- first_gid, fd_index = first
124
- second_gid, = second
125
- [(first_gid...second_gid), fd_index]
126
- end
124
+ @entries =
125
+ ranges.each_cons(2).map do |first, second|
126
+ first_gid, fd_index = first
127
+ second_gid, = second
128
+ [(first_gid...second_gid), fd_index]
129
+ end
127
130
 
128
131
  # read the sentinel GID, otherwise known as the number of glyphs
129
132
  # in the font
@@ -132,7 +135,7 @@ module TTFunk
132
135
  last_start_gid, last_fd_index = ranges.last
133
136
  @entries << [(last_start_gid...(n_glyphs + 1)), last_fd_index]
134
137
 
135
- @count = entries.inject(0) { |sum, entry| sum + entry.first.size }
138
+ @count = entries.reduce(0) { |sum, entry| sum + entry.first.size }
136
139
  end
137
140
  end
138
141
 
@@ -141,7 +144,7 @@ module TTFunk
141
144
  when ARRAY_FORMAT then :array_format
142
145
  when RANGE_FORMAT then :range_format
143
146
  else
144
- raise "unsupported fd select format '#{@format}'"
147
+ raise Error, "unsupported fd select format '#{@format}'"
145
148
  end
146
149
  end
147
150
  end
@@ -12,12 +12,13 @@ module TTFunk
12
12
  end
13
13
 
14
14
  def [](index)
15
- entry_cache[index] ||= begin
16
- start, finish = absolute_offsets_for(index)
17
- TTFunk::Table::Cff::FontDict.new(
18
- top_dict, file, start, (finish - start) + 1
19
- )
20
- end
15
+ entry_cache[index] ||=
16
+ begin
17
+ start, finish = absolute_offsets_for(index)
18
+ TTFunk::Table::Cff::FontDict.new(
19
+ top_dict, file, start, (finish - start) + 1
20
+ )
21
+ end
21
22
  end
22
23
 
23
24
  def finalize(new_cff_data, mapping)
@@ -30,10 +30,11 @@ module TTFunk
30
30
  def encode
31
31
  result = EncodedString.new
32
32
 
33
- entries = each_with_object([]).with_index do |(entry, ret), index|
34
- new_entry = block_given? ? yield(entry, index) : entry
35
- ret << new_entry if new_entry
36
- end
33
+ entries =
34
+ each_with_object([]).with_index do |(entry, ret), index|
35
+ new_entry = block_given? ? yield(entry, index) : entry
36
+ ret << new_entry if new_entry
37
+ end
37
38
 
38
39
  # "An empty INDEX is represented by a count field with a 0 value and
39
40
  # no additional fields. Thus, the total size of an empty INDEX is 2
@@ -89,7 +90,7 @@ module TTFunk
89
90
  def parse!
90
91
  @count = read(2, 'n').first
91
92
 
92
- if count == 0
93
+ if count.zero?
93
94
  @length = 2
94
95
  @data = []
95
96
  return
@@ -8,8 +8,12 @@ module TTFunk
8
8
  class OneBasedIndex
9
9
  extend Forwardable
10
10
 
11
- def_delegators :base_index, :each, :table_offset,
12
- :count, :length, :encode
11
+ def_delegators :base_index,
12
+ :each,
13
+ :table_offset,
14
+ :count,
15
+ :length,
16
+ :encode
13
17
 
14
18
  attr_reader :base_index
15
19
 
@@ -18,7 +22,7 @@ module TTFunk
18
22
  end
19
23
 
20
24
  def [](idx)
21
- if idx == 0
25
+ if idx.zero?
22
26
  raise IndexError,
23
27
  "index #{idx} was outside the bounds of the index"
24
28
  end