ttfunk 1.5.1 → 1.6.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 (90) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CHANGELOG.md +60 -0
  5. data/README.md +2 -1
  6. data/lib/ttfunk.rb +45 -0
  7. data/lib/ttfunk/aggregate.rb +15 -0
  8. data/lib/ttfunk/bin_utils.rb +47 -0
  9. data/lib/ttfunk/bit_field.rb +31 -0
  10. data/lib/ttfunk/collection.rb +3 -1
  11. data/lib/ttfunk/directory.rb +6 -0
  12. data/lib/ttfunk/encoded_string.rb +97 -0
  13. data/lib/ttfunk/max.rb +25 -0
  14. data/lib/ttfunk/min.rb +25 -0
  15. data/lib/ttfunk/one_based_array.rb +36 -0
  16. data/lib/ttfunk/otf_encoder.rb +61 -0
  17. data/lib/ttfunk/placeholder.rb +13 -0
  18. data/lib/ttfunk/reader.rb +34 -32
  19. data/lib/ttfunk/resource_file.rb +7 -5
  20. data/lib/ttfunk/sci_form.rb +29 -0
  21. data/lib/ttfunk/sub_table.rb +38 -0
  22. data/lib/ttfunk/subset.rb +2 -0
  23. data/lib/ttfunk/subset/base.rb +61 -120
  24. data/lib/ttfunk/subset/code_page.rb +89 -0
  25. data/lib/ttfunk/subset/mac_roman.rb +5 -42
  26. data/lib/ttfunk/subset/unicode.rb +12 -6
  27. data/lib/ttfunk/subset/unicode_8bit.rb +14 -12
  28. data/lib/ttfunk/subset/windows_1252.rb +5 -47
  29. data/lib/ttfunk/subset_collection.rb +4 -0
  30. data/lib/ttfunk/sum.rb +20 -0
  31. data/lib/ttfunk/table.rb +4 -0
  32. data/lib/ttfunk/table/cff.rb +69 -0
  33. data/lib/ttfunk/table/cff/charset.rb +212 -0
  34. data/lib/ttfunk/table/cff/charsets.rb +14 -0
  35. data/lib/ttfunk/table/cff/charsets/expert.rb +189 -0
  36. data/lib/ttfunk/table/cff/charsets/expert_subset.rb +119 -0
  37. data/lib/ttfunk/table/cff/charsets/iso_adobe.rb +241 -0
  38. data/lib/ttfunk/table/cff/charsets/standard_strings.rb +404 -0
  39. data/lib/ttfunk/table/cff/charstring.rb +487 -0
  40. data/lib/ttfunk/table/cff/charstrings_index.rb +39 -0
  41. data/lib/ttfunk/table/cff/dict.rb +266 -0
  42. data/lib/ttfunk/table/cff/encoding.rb +220 -0
  43. data/lib/ttfunk/table/cff/encodings.rb +12 -0
  44. data/lib/ttfunk/table/cff/encodings/expert.rb +206 -0
  45. data/lib/ttfunk/table/cff/encodings/standard.rb +181 -0
  46. data/lib/ttfunk/table/cff/fd_selector.rb +150 -0
  47. data/lib/ttfunk/table/cff/font_dict.rb +79 -0
  48. data/lib/ttfunk/table/cff/font_index.rb +29 -0
  49. data/lib/ttfunk/table/cff/header.rb +33 -0
  50. data/lib/ttfunk/table/cff/index.rb +125 -0
  51. data/lib/ttfunk/table/cff/one_based_index.rb +31 -0
  52. data/lib/ttfunk/table/cff/path.rb +66 -0
  53. data/lib/ttfunk/table/cff/private_dict.rb +84 -0
  54. data/lib/ttfunk/table/cff/subr_index.rb +19 -0
  55. data/lib/ttfunk/table/cff/top_dict.rb +230 -0
  56. data/lib/ttfunk/table/cff/top_index.rb +16 -0
  57. data/lib/ttfunk/table/cmap.rb +4 -4
  58. data/lib/ttfunk/table/cmap/format00.rb +1 -2
  59. data/lib/ttfunk/table/cmap/format04.rb +11 -3
  60. data/lib/ttfunk/table/cmap/format06.rb +2 -0
  61. data/lib/ttfunk/table/cmap/format10.rb +2 -0
  62. data/lib/ttfunk/table/cmap/format12.rb +2 -0
  63. data/lib/ttfunk/table/cmap/subtable.rb +12 -8
  64. data/lib/ttfunk/table/dsig.rb +50 -0
  65. data/lib/ttfunk/table/glyf.rb +11 -9
  66. data/lib/ttfunk/table/glyf/compound.rb +14 -7
  67. data/lib/ttfunk/table/glyf/path_based.rb +47 -0
  68. data/lib/ttfunk/table/glyf/simple.rb +21 -15
  69. data/lib/ttfunk/table/head.rb +43 -5
  70. data/lib/ttfunk/table/hhea.rb +47 -4
  71. data/lib/ttfunk/table/hmtx.rb +11 -4
  72. data/lib/ttfunk/table/kern.rb +3 -0
  73. data/lib/ttfunk/table/kern/format0.rb +3 -0
  74. data/lib/ttfunk/table/loca.rb +2 -0
  75. data/lib/ttfunk/table/maxp.rb +144 -10
  76. data/lib/ttfunk/table/name.rb +75 -37
  77. data/lib/ttfunk/table/os2.rb +327 -4
  78. data/lib/ttfunk/table/post.rb +8 -1
  79. data/lib/ttfunk/table/post/format10.rb +2 -0
  80. data/lib/ttfunk/table/post/format20.rb +5 -1
  81. data/lib/ttfunk/table/post/format30.rb +2 -0
  82. data/lib/ttfunk/table/post/format40.rb +2 -0
  83. data/lib/ttfunk/table/sbix.rb +2 -0
  84. data/lib/ttfunk/table/simple.rb +2 -0
  85. data/lib/ttfunk/table/vorg.rb +54 -0
  86. data/lib/ttfunk/ttf_encoder.rb +220 -0
  87. metadata +88 -20
  88. metadata.gz.sig +0 -0
  89. data/lib/ttfunk/encoding/mac_roman.rb +0 -100
  90. data/lib/ttfunk/encoding/windows_1252.rb +0 -76
@@ -0,0 +1,404 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TTFunk
4
+ class Table
5
+ class Cff < TTFunk::Table
6
+ module Charsets
7
+ STANDARD_STRINGS = OneBasedArray.new(
8
+ [
9
+ 'space',
10
+ 'exclam',
11
+ 'quotedbl',
12
+ 'numbersign',
13
+ 'dollar',
14
+ 'percent',
15
+ 'ampersand',
16
+ 'quoteright',
17
+ 'parenleft',
18
+ 'parenright',
19
+ 'asterisk',
20
+ 'plus',
21
+ 'comma',
22
+ 'hyphen',
23
+ 'period',
24
+ 'slash',
25
+ 'zero',
26
+ 'one',
27
+ 'two',
28
+ 'three',
29
+ 'four',
30
+ 'five',
31
+ 'six',
32
+ 'seven',
33
+ 'eight',
34
+ 'nine',
35
+ 'colon',
36
+ 'semicolon',
37
+ 'less',
38
+ 'equal',
39
+ 'greater',
40
+ 'question',
41
+ 'at',
42
+ 'A',
43
+ 'B',
44
+ 'C',
45
+ 'D',
46
+ 'E',
47
+ 'F',
48
+ 'G',
49
+ 'H',
50
+ 'I',
51
+ 'J',
52
+ 'K',
53
+ 'L',
54
+ 'M',
55
+ 'N',
56
+ 'O',
57
+ 'P',
58
+ 'Q',
59
+ 'R',
60
+ 'S',
61
+ 'T',
62
+ 'U',
63
+ 'V',
64
+ 'W',
65
+ 'X',
66
+ 'Y',
67
+ 'Z',
68
+ 'bracketleft',
69
+ 'backslash',
70
+ 'bracketright',
71
+ 'asciicircum',
72
+ 'underscore',
73
+ 'quoteleft',
74
+ 'a',
75
+ 'b',
76
+ 'c',
77
+ 'd',
78
+ 'e',
79
+ 'f',
80
+ 'g',
81
+ 'h',
82
+ 'i',
83
+ 'j',
84
+ 'k',
85
+ 'l',
86
+ 'm',
87
+ 'n',
88
+ 'o',
89
+ 'p',
90
+ 'q',
91
+ 'r',
92
+ 's',
93
+ 't',
94
+ 'u',
95
+ 'v',
96
+ 'w',
97
+ 'x',
98
+ 'y',
99
+ 'z',
100
+ 'braceleft',
101
+ 'bar',
102
+ 'braceright',
103
+ 'asciitilde',
104
+ 'exclamdown',
105
+ 'cent',
106
+ 'sterling',
107
+ 'fraction',
108
+ 'yen',
109
+ 'florin',
110
+ 'section',
111
+ 'currency',
112
+ 'quotesingle',
113
+ 'quotedblleft',
114
+ 'guillemotleft',
115
+ 'guilsinglleft',
116
+ 'guilsinglright',
117
+ 'fi',
118
+ 'fl',
119
+ 'endash',
120
+ 'dagger',
121
+ 'daggerdbl',
122
+ 'periodcentered',
123
+ 'paragraph',
124
+ 'bullet',
125
+ 'quotesinglbase',
126
+ 'quotedblbase',
127
+ 'quotedblright',
128
+ 'guillemotright',
129
+ 'ellipsis',
130
+ 'perthousand',
131
+ 'questiondown',
132
+ 'grave',
133
+ 'acute',
134
+ 'circumflex',
135
+ 'tilde',
136
+ 'macron',
137
+ 'breve',
138
+ 'dotaccent',
139
+ 'dieresis',
140
+ 'ring',
141
+ 'cedilla',
142
+ 'hungarumlaut',
143
+ 'ogonek',
144
+ 'caron',
145
+ 'emdash',
146
+ 'AE',
147
+ 'ordfeminine',
148
+ 'Lslash',
149
+ 'Oslash',
150
+ 'OE',
151
+ 'ordmasculine',
152
+ 'ae',
153
+ 'dotlessi',
154
+ 'lslash',
155
+ 'oslash',
156
+ 'oe',
157
+ 'germandbls',
158
+ 'onesuperior',
159
+ 'logicalnot',
160
+ 'mu',
161
+ 'trademark',
162
+ 'Eth',
163
+ 'onehalf',
164
+ 'plusminus',
165
+ 'Thorn',
166
+ 'onequarter',
167
+ 'divide',
168
+ 'brokenbar',
169
+ 'degree',
170
+ 'thorn',
171
+ 'threequarters',
172
+ 'twosuperior',
173
+ 'registered',
174
+ 'minus',
175
+ 'eth',
176
+ 'multiply',
177
+ 'threesuperior',
178
+ 'copyright',
179
+ 'Aacute',
180
+ 'Acircumflex',
181
+ 'Adieresis',
182
+ 'Agrave',
183
+ 'Aring',
184
+ 'Atilde',
185
+ 'Ccedilla',
186
+ 'Eacute',
187
+ 'Ecircumflex',
188
+ 'Edieresis',
189
+ 'Egrave',
190
+ 'Iacute',
191
+ 'Icircumflex',
192
+ 'Idieresis',
193
+ 'Igrave',
194
+ 'Ntilde',
195
+ 'Oacute',
196
+ 'Ocircumflex',
197
+ 'Odieresis',
198
+ 'Ograve',
199
+ 'Otilde',
200
+ 'Scaron',
201
+ 'Uacute',
202
+ 'Ucircumflex',
203
+ 'Udieresis',
204
+ 'Ugrave',
205
+ 'Yacute',
206
+ 'Ydieresis',
207
+ 'Zcaron',
208
+ 'aacute',
209
+ 'acircumflex',
210
+ 'adieresis',
211
+ 'agrave',
212
+ 'aring',
213
+ 'atilde',
214
+ 'ccedilla',
215
+ 'eacute',
216
+ 'ecircumflex',
217
+ 'edieresis',
218
+ 'egrave',
219
+ 'iacute',
220
+ 'icircumflex',
221
+ 'idieresis',
222
+ 'igrave',
223
+ 'ntilde',
224
+ 'oacute',
225
+ 'ocircumflex',
226
+ 'odieresis',
227
+ 'ograve',
228
+ 'otilde',
229
+ 'scaron',
230
+ 'uacute',
231
+ 'ucircumflex',
232
+ 'udieresis',
233
+ 'ugrave',
234
+ 'yacute',
235
+ 'ydieresis',
236
+ 'zcaron',
237
+ 'exclamsmall',
238
+ 'Hungarumlautsmall',
239
+ 'dollaroldstyle',
240
+ 'dollarsuperior',
241
+ 'ampersandsmall',
242
+ 'Acutesmall',
243
+ 'parenleftsuperior',
244
+ 'parenrightsuperior',
245
+ '266 ff',
246
+ 'onedotenleader',
247
+ 'zerooldstyle',
248
+ 'oneoldstyle',
249
+ 'twooldstyle',
250
+ 'threeoldstyle',
251
+ 'fouroldstyle',
252
+ 'fiveoldstyle',
253
+ 'sixoldstyle',
254
+ 'sevenoldstyle',
255
+ 'eightoldstyle',
256
+ 'nineoldstyle',
257
+ 'commasuperior',
258
+ 'threequartersemdash',
259
+ 'periodsuperior',
260
+ 'questionsmall',
261
+ 'asuperior',
262
+ 'bsuperior',
263
+ 'centsuperior',
264
+ 'dsuperior',
265
+ 'esuperior',
266
+ 'isuperior',
267
+ 'lsuperior',
268
+ 'msuperior',
269
+ 'nsuperior',
270
+ 'osuperior',
271
+ 'rsuperior',
272
+ 'ssuperior',
273
+ 'tsuperior',
274
+ 'ff',
275
+ 'ffi',
276
+ 'ffl',
277
+ 'parenleftinferior',
278
+ 'parenrightinferior',
279
+ 'Circumflexsmall',
280
+ 'hyphensuperior',
281
+ 'Gravesmall',
282
+ 'Asmall',
283
+ 'Bsmall',
284
+ 'Csmall',
285
+ 'Dsmall',
286
+ 'Esmall',
287
+ 'Fsmall',
288
+ 'Gsmall',
289
+ 'Hsmall',
290
+ 'Ismall',
291
+ 'Jsmall',
292
+ 'Ksmall',
293
+ 'Lsmall',
294
+ 'Msmall',
295
+ 'Nsmall',
296
+ 'Osmall',
297
+ 'Psmall',
298
+ 'Qsmall',
299
+ 'Rsmall',
300
+ 'Ssmall',
301
+ 'Tsmall',
302
+ 'Usmall',
303
+ 'Vsmall',
304
+ 'Wsmall',
305
+ 'Xsmall',
306
+ 'Ysmall',
307
+ 'Zsmall',
308
+ 'colonmonetary',
309
+ 'onefitted',
310
+ 'rupiah',
311
+ 'Tildesmall',
312
+ 'exclamdownsmall',
313
+ 'centoldstyle',
314
+ 'Lslashsmall',
315
+ 'Scaronsmall',
316
+ 'Zcaronsmall',
317
+ 'Dieresissmall',
318
+ 'Brevesmall',
319
+ 'Caronsmall',
320
+ 'Dotaccentsmall',
321
+ 'Macronsmall',
322
+ 'figuredash',
323
+ 'hypheninferior',
324
+ 'Ogoneksmall',
325
+ 'Ringsmall',
326
+ 'Cedillasmall',
327
+ 'questiondownsmall',
328
+ 'oneeighth',
329
+ 'threeeighths',
330
+ 'fiveeighths',
331
+ 'seveneighths',
332
+ 'onethird',
333
+ 'twothirds',
334
+ 'zerosuperior',
335
+ 'foursuperior',
336
+ 'fivesuperior',
337
+ 'sixsuperior',
338
+ 'sevensuperior',
339
+ 'eightsuperior',
340
+ 'ninesuperior',
341
+ 'zeroinferior',
342
+ 'oneinferior',
343
+ 'twoinferior',
344
+ 'threeinferior',
345
+ 'fourinferior',
346
+ 'fiveinferior',
347
+ 'sixinferior',
348
+ 'seveninferior',
349
+ 'eightinferior',
350
+ 'nineinferior',
351
+ 'centinferior',
352
+ 'dollarinferior',
353
+ 'periodinferior',
354
+ 'commainferior',
355
+ 'Agravesmall',
356
+ 'Aacutesmall',
357
+ 'Acircumflexsmall',
358
+ 'Atildesmall',
359
+ 'Adieresissmall',
360
+ 'Aringsmall',
361
+ 'AEsmall',
362
+ 'Ccedillasmall',
363
+ 'Egravesmall',
364
+ 'Eacutesmall',
365
+ 'Ecircumflexsmall',
366
+ 'Edieresissmall',
367
+ 'Igravesmall',
368
+ 'Iacutesmall',
369
+ 'Icircumflexsmall',
370
+ 'Idieresissmall',
371
+ 'Ethsmall',
372
+ 'Ntildesmall',
373
+ 'Ogravesmall',
374
+ 'Oacutesmall',
375
+ 'Ocircumflexsmall',
376
+ 'Otildesmall',
377
+ 'Odieresissmall',
378
+ 'OEsmall',
379
+ 'Oslashsmall',
380
+ 'Ugravesmall',
381
+ 'Uacutesmall',
382
+ 'Ucircumflexsmall',
383
+ 'Udieresissmall',
384
+ 'Yacutesmall',
385
+ 'Thornsmall',
386
+ 'Ydieresissmall',
387
+ '001.000',
388
+ '001.001',
389
+ '001.002',
390
+ '001.003',
391
+ 'Black',
392
+ 'Bold',
393
+ 'Book',
394
+ 'Light',
395
+ 'Medium',
396
+ 'Regular',
397
+ 'Roman',
398
+ 'Semibold'
399
+ ]
400
+ ).freeze
401
+ end
402
+ end
403
+ end
404
+ end
@@ -0,0 +1,487 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TTFunk
4
+ class Table
5
+ class Cff < TTFunk::Table
6
+ class Charstring
7
+ CODE_MAP = {
8
+ 1 => :hstem,
9
+ 3 => :vstem,
10
+ 4 => :vmoveto,
11
+ 5 => :rlineto,
12
+ 6 => :hlineto,
13
+ 7 => :vlineto,
14
+ 8 => :rrcurveto,
15
+ 10 => :callsubr,
16
+ 12 => :flex_select,
17
+ 14 => :endchar,
18
+ 18 => :hstemhm,
19
+ 19 => :hintmask,
20
+ 20 => :cntrmask,
21
+ 21 => :rmoveto,
22
+ 22 => :hmoveto,
23
+ 23 => :vstemhm,
24
+ 24 => :rcurveline,
25
+ 25 => :rlinecurve,
26
+ 26 => :vvcurveto,
27
+ 27 => :hhcurveto,
28
+ 28 => :shortint,
29
+ 29 => :callgsubr,
30
+ 30 => :vhcurveto,
31
+ 31 => :hvcurveto
32
+ }.freeze
33
+
34
+ FLEX_CODE_MAP = {
35
+ 35 => :flex,
36
+ 34 => :hflex,
37
+ 36 => :hflex1,
38
+ 37 => :flex1
39
+ }.freeze
40
+
41
+ attr_reader :glyph_id, :raw
42
+
43
+ def initialize(glyph_id, top_dict, font_dict, raw)
44
+ @glyph_id = glyph_id
45
+ @top_dict = top_dict
46
+ @font_dict = font_dict
47
+ @raw = raw
48
+
49
+ default_width_x = (@font_dict || @top_dict)
50
+ .private_dict.default_width_x
51
+
52
+ @nominal_width_x = (@font_dict || @top_dict)
53
+ .private_dict.nominal_width_x
54
+
55
+ @subrs = (@font_dict || @top_dict).private_dict.subr_index
56
+ @gsubrs = @top_dict.cff.global_subr_index
57
+ @subrs_bias = @subrs.bias if @subrs
58
+ @gsubrs_bias = @gsubrs.bias if @gsubrs
59
+
60
+ @stack = []
61
+ @data = raw.bytes
62
+ @index = 0
63
+ @n_stems = 0
64
+ @have_width = false
65
+ @open = false
66
+ @width = default_width_x
67
+ @x = 0
68
+ @y = 0
69
+ end
70
+
71
+ def path
72
+ @path || begin
73
+ @path = Path.new
74
+ parse!
75
+ @path
76
+ end
77
+ end
78
+
79
+ 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
84
+ end
85
+
86
+ def render(x: 0, y: 0, font_size: 72)
87
+ path.render(
88
+ x: x,
89
+ y: y,
90
+ font_size: font_size,
91
+ units_per_em: @top_dict.file.header.units_per_em
92
+ )
93
+ end
94
+
95
+ def encode
96
+ raw
97
+ end
98
+
99
+ private
100
+
101
+ def parse!
102
+ until @index >= @data.size
103
+ code = @data[@index]
104
+ @index += 1
105
+
106
+ # return from callgsubr - do nothing since we inline subrs
107
+ next if code == 11
108
+
109
+ if code >= 32 && code <= 246
110
+ @stack << code - 139
111
+ elsif (m = CODE_MAP[code])
112
+ send(m)
113
+ elsif code >= 247 && code <= 250
114
+ b0 = code
115
+ b1 = @data[@index]
116
+ @index += 1
117
+ @stack << (b0 - 247) * 256 + b1 + 108
118
+ elsif code >= 251 && code <= 254
119
+ b0 = code
120
+ b1 = @data[@index]
121
+ @index += 1
122
+ @stack << -(b0 - 251) * 256 - b1 - 108
123
+ else
124
+ b1, b2, b3, b4 = read_bytes(4)
125
+ @stack << ((b1 << 24) | (b2 << 16) | (b3 << 8) | b4) / 65_536
126
+ end
127
+ end
128
+ end
129
+
130
+ def read_bytes(length)
131
+ bytes = @data[@index, length]
132
+ @index += length
133
+ bytes
134
+ end
135
+
136
+ def hstem
137
+ stem
138
+ end
139
+
140
+ def vstem
141
+ stem
142
+ end
143
+
144
+ # rubocop:disable Style/EvenOdd
145
+ def stem
146
+ # The number of stem operators on the stack is always even.
147
+ # If the value is uneven, that means a width is specified.
148
+ has_width_arg = @stack.size % 2 == 1
149
+
150
+ if has_width_arg && !@have_width
151
+ @width = @stack.shift + @nominal_width_x
152
+ end
153
+
154
+ @n_stems += @stack.length >> 1
155
+ @stack.clear
156
+ @have_width = true
157
+ end
158
+ # rubocop:enable Style/EvenOdd
159
+
160
+ def vmoveto
161
+ if @stack.size > 1 && !@have_width
162
+ @width = @stack.shift + @nominal_width_x
163
+ @have_width = true
164
+ end
165
+
166
+ @y += @stack.pop
167
+ add_contour(@x, @y)
168
+ end
169
+
170
+ def add_contour(x, y)
171
+ if @open
172
+ @path.close_path
173
+ end
174
+
175
+ @path.move_to(x, y)
176
+ @open = true
177
+ end
178
+
179
+ def rlineto
180
+ until @stack.empty?
181
+ @x += @stack.shift
182
+ @y += @stack.shift
183
+ @path.line_to(@x, @y)
184
+ end
185
+ end
186
+
187
+ def hlineto
188
+ until @stack.empty?
189
+ @x += @stack.shift
190
+ @path.line_to(@x, @y)
191
+
192
+ break if @stack.empty?
193
+
194
+ @y += @stack.shift
195
+ @path.line_to(@x, @y)
196
+ end
197
+ end
198
+
199
+ def vlineto
200
+ until @stack.empty?
201
+ @y += @stack.shift
202
+ @path.line_to(@x, @y)
203
+
204
+ break if @stack.empty?
205
+
206
+ @x += @stack.shift
207
+ @path.line_to(@x, @y)
208
+ end
209
+ end
210
+
211
+ def rrcurveto
212
+ until @stack.empty?
213
+ c1x = @x + @stack.shift
214
+ c1y = @y + @stack.shift
215
+ c2x = c1x + @stack.shift
216
+ c2y = c1y + @stack.shift
217
+ @x = c2x + @stack.shift
218
+ @y = c2y + @stack.shift
219
+ @path.curve_to(c1x, c1y, c2x, c2y, @x, @y)
220
+ end
221
+ end
222
+
223
+ def callsubr
224
+ code_index = @stack.pop + @subrs_bias
225
+ subr_code = @subrs[code_index].bytes
226
+ @data[@index, 0] = subr_code
227
+ end
228
+
229
+ def flex_select
230
+ flex_code = @data[@index]
231
+ @index += 1
232
+ send(FLEX_CODE_MAP[flex_code])
233
+ end
234
+
235
+ 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
249
+
250
+ @path.curve_to(c1x, c1y, c2x, c2y, jpx, jpy)
251
+ @path.curve_to(c3x, c3y, c4x, c4y, @x, @y)
252
+ end
253
+
254
+ 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
266
+
267
+ @path.curve_to(c1x, c1y, c2x, c2y, jpx, jpy)
268
+ @path.curve_to(c3x, c3y, c4x, c4y, @x, @y)
269
+ end
270
+
271
+ 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
283
+
284
+ @path.curve_to(c1x, c1y, c2x, c2y, jpx, jpy)
285
+ @path.curve_to(c3x, c3y, c4x, c4y, @x, @y)
286
+ end
287
+
288
+ 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
299
+
300
+ if (c4x - @x).abs > (c4y - @y).abs
301
+ @x = c4x + @stack.shift
302
+ else
303
+ @y = c4y + @stack.shift
304
+ end
305
+
306
+ @path.curve_to(c1x, c1y, c2x, c2y, jpx, jpy)
307
+ @path.curve_to(c3x, c3y, c4x, c4y, @x, @y)
308
+ end
309
+
310
+ def endchar
311
+ if !@stack.empty? && !@have_width
312
+ @width = @stack.shift + @nominal_width_x
313
+ @have_width = true
314
+ end
315
+
316
+ if @open
317
+ @path.close_path
318
+ @open = false
319
+ end
320
+ end
321
+
322
+ def hstemhm
323
+ stem
324
+ end
325
+
326
+ def hintmask
327
+ cntrmask
328
+ end
329
+
330
+ def cntrmask
331
+ stem
332
+
333
+ # skip past hinting data, no need to worry about it since we're not
334
+ # very concerned about rendering glyphs
335
+ read_bytes((@n_stems + 7) >> 3)
336
+ end
337
+
338
+ def rmoveto
339
+ if @stack.size > 2 && !@have_width
340
+ @width = @stack.shift + @nominal_width_x
341
+ @have_width = true
342
+ end
343
+
344
+ @y += @stack.pop
345
+ @x += @stack.pop
346
+ add_contour(@x, @y)
347
+ end
348
+
349
+ def hmoveto
350
+ if @stack.size > 1 && !@have_width
351
+ @width = @stack.shift + @nominal_width_x
352
+ @have_width = true
353
+ end
354
+
355
+ @x += @stack.pop
356
+ add_contour(@x, @y)
357
+ end
358
+
359
+ def vstemhm
360
+ stem
361
+ end
362
+
363
+ def rcurveline
364
+ while @stack.size > 2
365
+ c1x = @x + @stack.shift
366
+ c1y = @y + @stack.shift
367
+ c2x = c1x + @stack.shift
368
+ c2y = c1y + @stack.shift
369
+ @x = c2x + @stack.shift
370
+ @y = c2y + @stack.shift
371
+ @path.curve_to(c1x, c1y, c2x, c2y, @x, @y)
372
+ end
373
+
374
+ @x += @stack.shift
375
+ @y += @stack.shift
376
+ @path.line_to(@x, @y)
377
+ end
378
+
379
+ def rlinecurve
380
+ while @stack.size > 6
381
+ @x += @stack.shift
382
+ @y += @stack.shift
383
+ @path.line_to(@x, @y)
384
+ end
385
+
386
+ c1x = @x + @stack.shift
387
+ c1y = @y + @stack.shift
388
+ c2x = c1x + @stack.shift
389
+ c2y = c1y + @stack.shift
390
+ @x = c2x + @stack.shift
391
+ @y = c2y + @stack.shift
392
+
393
+ @path.curve_to(c1x, c1y, c2x, c2y, @x, @y)
394
+ end
395
+
396
+ # rubocop:disable Style/EvenOdd
397
+ def vvcurveto
398
+ if @stack.size % 2 == 1
399
+ @x += @stack.shift
400
+ end
401
+
402
+ until @stack.empty?
403
+ c1x = @x
404
+ c1y = @y + @stack.shift
405
+ c2x = c1x + @stack.shift
406
+ c2y = c1y + @stack.shift
407
+ @x = c2x
408
+ @y = c2y + @stack.shift
409
+ @path.curve_to(c1x, c1y, c2x, c2y, @x, @y)
410
+ end
411
+ end
412
+
413
+ def hhcurveto
414
+ if @stack.size % 2 == 1
415
+ @y += @stack.shift
416
+ end
417
+
418
+ until @stack.empty?
419
+ c1x = @x + @stack.shift
420
+ c1y = @y
421
+ c2x = c1x + @stack.shift
422
+ c2y = c1y + @stack.shift
423
+ @x = c2x + @stack.shift
424
+ @y = c2y
425
+ @path.curve_to(c1x, c1y, c2x, c2y, @x, @y)
426
+ end
427
+ end
428
+ # rubocop:enable Style/EvenOdd
429
+
430
+ def shortint
431
+ b1, b2 = read_bytes(2)
432
+ @stack << (((b1 << 24) | (b2 << 16)) >> 16)
433
+ end
434
+
435
+ def callgsubr
436
+ code_index = @stack.pop + @gsubrs_bias
437
+ subr_code = @gsubrs[code_index].bytes
438
+ @data[@index, 0] = subr_code
439
+ end
440
+
441
+ def vhcurveto
442
+ until @stack.empty?
443
+ c1x = @x
444
+ c1y = @y + @stack.shift
445
+ c2x = c1x + @stack.shift
446
+ c2y = c1y + @stack.shift
447
+ @x = c2x + @stack.shift
448
+ @y = c2y + (@stack.size == 1 ? @stack.shift : 0)
449
+ @path.curve_to(c1x, c1y, c2x, c2y, @x, @y)
450
+
451
+ break if @stack.empty?
452
+
453
+ c1x = @x + @stack.shift
454
+ c1y = @y
455
+ c2x = c1x + @stack.shift
456
+ c2y = c1y + @stack.shift
457
+ @y = c2y + @stack.shift
458
+ @x = c2x + (@stack.size == 1 ? @stack.shift : 0)
459
+ @path.curve_to(c1x, c1y, c2x, c2y, @x, @y)
460
+ end
461
+ end
462
+
463
+ def hvcurveto
464
+ until @stack.empty?
465
+ c1x = @x + @stack.shift
466
+ c1y = @y
467
+ c2x = c1x + @stack.shift
468
+ c2y = c1y + @stack.shift
469
+ @y = c2y + @stack.shift
470
+ @x = c2x + (@stack.size == 1 ? @stack.shift : 0)
471
+ @path.curve_to(c1x, c1y, c2x, c2y, @x, @y)
472
+
473
+ break if @stack.empty?
474
+
475
+ c1x = @x
476
+ c1y = @y + @stack.shift
477
+ c2x = c1x + @stack.shift
478
+ c2y = c1y + @stack.shift
479
+ @x = c2x + @stack.shift
480
+ @y = c2y + (@stack.size == 1 ? @stack.shift : 0)
481
+ @path.curve_to(c1x, c1y, c2x, c2y, @x, @y)
482
+ end
483
+ end
484
+ end
485
+ end
486
+ end
487
+ end