ttfunk 1.5.1 → 1.6.0

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