1if not modules then modules = { } end modules ['font-cff'] = {
2 version = 1.001,
3 optimize = true,
4 comment = "companion to font-ini.mkiv",
5 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
6 copyright = "PRAGMA ADE / ConTeXt Development Team",
7 license = "see context related readme files"
8}
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30local next, type, tonumber, rawget = next, type, tonumber, rawget
31local byte, char, gmatch, sub = string.byte, string.char, string.gmatch, string.sub
32local concat, insert, remove, unpack = table.concat, table.insert, table.remove, table.unpack
33local floor, abs, round, ceil, min, max = math.floor, math.abs, math.round, math.ceil, math.min, math.max
34local P, C, R, S, C, Cs, Ct = lpeg.P, lpeg.C, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpeg.Ct
35local lpegmatch = lpeg.match
36local formatters = string.formatters
37local bytetable = string.bytetable
38
39
40local readers = fonts.handlers.otf.readers
41local streamreader = readers.streamreader
42
43local readstring = streamreader.readstring
44local readbyte = streamreader.readcardinal1
45local readushort = streamreader.readcardinal2
46local readuint = streamreader.readcardinal3
47local readulong = streamreader.readcardinal4
48local setposition = streamreader.setposition
49local getposition = streamreader.getposition
50local readbytetable = streamreader.readbytetable
51
52directives.register("fonts.streamreader",function()
53
54 streamreader = utilities.streams
55
56 readstring = streamreader.readstring
57 readbyte = streamreader.readcardinal1
58 readushort = streamreader.readcardinal2
59 readuint = streamreader.readcardinal3
60 readulong = streamreader.readcardinal4
61 setposition = streamreader.setposition
62 getposition = streamreader.getposition
63 readbytetable = streamreader.readbytetable
64
65end)
66
67local setmetatableindex = table.setmetatableindex
68
69local trace_charstrings = false trackers.register("fonts.cff.charstrings",function(v) trace_charstrings = v end)
70local report = logs.reporter("otf reader","cff")
71
72local parsedictionaries
73local parsecharstring
74local parsecharstrings
75local resetcharstrings
76local parseprivates
77local startparsing
78local stopparsing
79
80local defaultstrings = { [0] =
81 ".notdef", "space", "exclam", "quotedbl", "numbersign", "dollar", "percent",
82 "ampersand", "quoteright", "parenleft", "parenright", "asterisk", "plus",
83 "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four",
84 "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less",
85 "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H",
86 "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W",
87 "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum",
88 "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
89 "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y",
90 "z", "braceleft", "bar", "braceright", "asciitilde", "exclamdown", "cent",
91 "sterling", "fraction", "yen", "florin", "section", "currency",
92 "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft",
93 "guilsinglright", "fi", "fl", "endash", "dagger", "daggerdbl",
94 "periodcentered", "paragraph", "bullet", "quotesinglbase", "quotedblbase",
95 "quotedblright", "guillemotright", "ellipsis", "perthousand", "questiondown",
96 "grave", "acute", "circumflex", "tilde", "macron", "breve", "dotaccent",
97 "dieresis", "ring", "cedilla", "hungarumlaut", "ogonek", "caron", "emdash",
98 "AE", "ordfeminine", "Lslash", "Oslash", "OE", "ordmasculine", "ae",
99 "dotlessi", "lslash", "oslash", "oe", "germandbls", "onesuperior",
100 "logicalnot", "mu", "trademark", "Eth", "onehalf", "plusminus", "Thorn",
101 "onequarter", "divide", "brokenbar", "degree", "thorn", "threequarters",
102 "twosuperior", "registered", "minus", "eth", "multiply", "threesuperior",
103 "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave", "Aring",
104 "Atilde", "Ccedilla", "Eacute", "Ecircumflex", "Edieresis", "Egrave",
105 "Iacute", "Icircumflex", "Idieresis", "Igrave", "Ntilde", "Oacute",
106 "Ocircumflex", "Odieresis", "Ograve", "Otilde", "Scaron", "Uacute",
107 "Ucircumflex", "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron",
108 "aacute", "acircumflex", "adieresis", "agrave", "aring", "atilde",
109 "ccedilla", "eacute", "ecircumflex", "edieresis", "egrave", "iacute",
110 "icircumflex", "idieresis", "igrave", "ntilde", "oacute", "ocircumflex",
111 "odieresis", "ograve", "otilde", "scaron", "uacute", "ucircumflex",
112 "udieresis", "ugrave", "yacute", "ydieresis", "zcaron", "exclamsmall",
113 "Hungarumlautsmall", "dollaroldstyle", "dollarsuperior", "ampersandsmall",
114 "Acutesmall", "parenleftsuperior", "parenrightsuperior", "twodotenleader",
115 "onedotenleader", "zerooldstyle", "oneoldstyle", "twooldstyle",
116 "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle",
117 "sevenoldstyle", "eightoldstyle", "nineoldstyle", "commasuperior",
118 "threequartersemdash", "periodsuperior", "questionsmall", "asuperior",
119 "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior",
120 "lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior",
121 "tsuperior", "ff", "ffi", "ffl", "parenleftinferior", "parenrightinferior",
122 "Circumflexsmall", "hyphensuperior", "Gravesmall", "Asmall", "Bsmall",
123 "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", "Hsmall", "Ismall",
124 "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall",
125 "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall",
126 "Xsmall", "Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah",
127 "Tildesmall", "exclamdownsmall", "centoldstyle", "Lslashsmall",
128 "Scaronsmall", "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall",
129 "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior",
130 "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall", "oneeighth",
131 "threeeighths", "fiveeighths", "seveneighths", "onethird", "twothirds",
132 "zerosuperior", "foursuperior", "fivesuperior", "sixsuperior",
133 "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior",
134 "oneinferior", "twoinferior", "threeinferior", "fourinferior",
135 "fiveinferior", "sixinferior", "seveninferior", "eightinferior",
136 "nineinferior", "centinferior", "dollarinferior", "periodinferior",
137 "commainferior", "Agravesmall", "Aacutesmall", "Acircumflexsmall",
138 "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall",
139 "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall",
140 "Igravesmall", "Iacutesmall", "Icircumflexsmall", "Idieresissmall",
141 "Ethsmall", "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall",
142 "Otildesmall", "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall",
143 "Uacutesmall", "Ucircumflexsmall", "Udieresissmall", "Yacutesmall",
144 "Thornsmall", "Ydieresissmall", "001.000", "001.001", "001.002", "001.003",
145 "Black", "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold",
146}
147
148local standardnames = { [0] =
149 false, false, false, false, false, false, false, false, false, false, false,
150 false, false, false, false, false, false, false, false, false, false, false,
151 false, false, false, false, false, false, false, false, false, false,
152 "space", "exclam", "quotedbl", "numbersign", "dollar", "percent",
153 "ampersand", "quoteright", "parenleft", "parenright", "asterisk", "plus",
154 "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four",
155 "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less",
156 "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H",
157 "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W",
158 "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum",
159 "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
160 "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y",
161 "z", "braceleft", "bar", "braceright", "asciitilde", false, false, false,
162 false, false, false, false, false, false, false, false, false, false, false,
163 false, false, false, false, false, false, false, false, false, false, false,
164 false, false, false, false, false, false, false, false, false, "exclamdown",
165 "cent", "sterling", "fraction", "yen", "florin", "section", "currency",
166 "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft",
167 "guilsinglright", "fi", "fl", false, "endash", "dagger", "daggerdbl",
168 "periodcentered", false, "paragraph", "bullet", "quotesinglbase",
169 "quotedblbase", "quotedblright", "guillemotright", "ellipsis", "perthousand",
170 false, "questiondown", false, "grave", "acute", "circumflex", "tilde",
171 "macron", "breve", "dotaccent", "dieresis", false, "ring", "cedilla", false,
172 "hungarumlaut", "ogonek", "caron", "emdash", false, false, false, false,
173 false, false, false, false, false, false, false, false, false, false, false,
174 false, "AE", false, "ordfeminine", false, false, false, false, "Lslash",
175 "Oslash", "OE", "ordmasculine", false, false, false, false, false, "ae",
176 false, false, false, "dotlessi", false, false, "lslash", "oslash", "oe",
177 "germandbls", false, false, false, false
178}
179
180local cffreaders = {
181 readbyte,
182 readushort,
183 readuint,
184 readulong,
185}
186
187directives.register("fonts.streamreader",function()
188 cffreaders = {
189 readbyte,
190 readushort,
191 readuint,
192 readulong,
193 }
194end)
195
196
197
198local function readheader(f)
199 local offset = getposition(f)
200 local major = readbyte(f)
201 local header = {
202 offset = offset,
203 major = major,
204 minor = readbyte(f),
205 size = readbyte(f),
206 }
207 if major == 1 then
208 header.dsize = readbyte(f)
209 elseif major == 2 then
210 header.dsize = readushort(f)
211 else
212
213
214 end
215 setposition(f,offset+header.size)
216 return header
217end
218
219
220
221
222local function readlengths(f,longcount)
223 local count = longcount and readulong(f) or readushort(f)
224 if count == 0 then
225 return { }
226 end
227 local osize = readbyte(f)
228 local read = cffreaders[osize]
229 if not read then
230 report("bad offset size: %i",osize)
231 return { }
232 end
233 local lengths = { }
234 local previous = read(f)
235 for i=1,count do
236 local offset = read(f)
237 local length = offset - previous
238 if length < 0 then
239 report("bad offset: %i",length)
240 length = 0
241 end
242 lengths[i] = length
243 previous = offset
244 end
245 return lengths
246end
247
248
249
250
251
252
253local function readfontnames(f)
254 local names = readlengths(f)
255 for i=1,#names do
256 names[i] = readstring(f,names[i])
257 end
258 return names
259end
260
261local function readtopdictionaries(f)
262 local dictionaries = readlengths(f)
263 for i=1,#dictionaries do
264 dictionaries[i] = readstring(f,dictionaries[i])
265 end
266 return dictionaries
267end
268
269
270
271
272local function readstrings(f)
273 local lengths = readlengths(f)
274 local strings = setmetatableindex({ }, defaultstrings)
275 local index = #defaultstrings
276 for i=1,#lengths do
277 index = index + 1
278 strings[index] = readstring(f,lengths[i])
279 end
280 return strings
281end
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298do
299
300
301
302
303 local stack = { }
304 local top = 0
305 local result = { }
306 local strings = { }
307
308 local p_dictionary do
309
310 local p_single =
311 P("\00") / function()
312 result.version = strings[stack[top]] or "unset"
313 top = 0
314 end
315 + P("\01") / function()
316 result.notice = strings[stack[top]] or "unset"
317 top = 0
318 end
319 + P("\02") / function()
320 result.fullname = strings[stack[top]] or "unset"
321 top = 0
322 end
323 + P("\03") / function()
324 result.familyname = strings[stack[top]] or "unset"
325 top = 0
326 end
327 + P("\04") / function()
328 result.weight = strings[stack[top]] or "unset"
329 top = 0
330 end
331 + P("\05") / function()
332 result.fontbbox = { unpack(stack,1,4) }
333 top = 0
334 end
335 + P("\06") / function()
336 result.bluevalues = { unpack(stack,1,top) }
337 top = 0
338 end
339 + P("\07") / function()
340 result.otherblues = { unpack(stack,1,top) }
341 top = 0
342 end
343 + P("\08") / function()
344 result.familyblues = { unpack(stack,1,top) }
345 top = 0
346 end
347 + P("\09") / function()
348 result.familyotherblues = { unpack(stack,1,top) }
349 top = 0
350 end
351 + P("\10") / function()
352 result.stdhw = stack[top]
353 top = 0
354 end
355 + P("\11") / function()
356 result.stdvw = stack[top]
357 top = 0
358 end
359 + P("\13") / function()
360 result.uniqueid = stack[top]
361 top = 0
362 end
363 + P("\14") / function()
364 result.xuid = concat(stack,"",1,top)
365 top = 0
366 end
367 + P("\15") / function()
368 result.charset = stack[top]
369 top = 0
370 end
371 + P("\16") / function()
372 result.encoding = stack[top]
373 top = 0
374 end
375 + P("\17") / function()
376 result.charstrings = stack[top]
377 top = 0
378 end
379 + P("\18") / function()
380 result.private = {
381 size = stack[top-1],
382 offset = stack[top],
383 }
384 top = 0
385 end
386 + P("\19") / function()
387 result.subroutines = stack[top]
388 top = 0
389 end
390 + P("\20") / function()
391 result.defaultwidthx = stack[top]
392 top = 0
393 end
394 + P("\21") / function()
395 result.nominalwidthx = stack[top]
396 top = 0
397 end
398
399
400
401
402 + P("\24") / function()
403 result.vstore = stack[top]
404 top = 0
405 end
406 + P("\25") / function()
407 result.maxstack = stack[top]
408 top = 0
409 end
410
411
412
413
414
415 local p_double = P("\12") * (
416 P("\00") / function()
417 result.copyright = stack[top]
418 top = 0
419 end
420 + P("\01") / function()
421 result.monospaced = stack[top] == 1 and true or false
422 top = 0
423 end
424 + P("\02") / function()
425 result.italicangle = stack[top]
426 top = 0
427 end
428 + P("\03") / function()
429 result.underlineposition = stack[top]
430 top = 0
431 end
432 + P("\04") / function()
433 result.underlinethickness = stack[top]
434 top = 0
435 end
436 + P("\05") / function()
437 result.painttype = stack[top]
438 top = 0
439 end
440 + P("\06") / function()
441 result.charstringtype = stack[top]
442 top = 0
443 end
444 + P("\07") / function()
445 result.fontmatrix = { unpack(stack,1,6) }
446 top = 0
447 end
448 + P("\08") / function()
449 result.strokewidth = stack[top]
450 top = 0
451 end
452 + P("\09") / function()
453 result.bluescale = stack[top]
454 top = 0
455 end
456 + P("\10") / function()
457 result.blueshift = stack[top]
458 top = 0
459 end
460 + P("\11") / function()
461 result.bluefuzz = stack[top]
462 top = 0
463 end
464 + P("\12") / function()
465 result.stemsnaph = { unpack(stack,1,top) }
466 top = 0
467 end
468 + P("\13") / function()
469 result.stemsnapv = { unpack(stack,1,top) }
470 top = 0
471 end
472 + P("\20") / function()
473 result.syntheticbase = stack[top]
474 top = 0
475 end
476 + P("\21") / function()
477 result.postscript = strings[stack[top]] or "unset"
478 top = 0
479 end
480 + P("\22") / function()
481 result.basefontname = strings[stack[top]] or "unset"
482 top = 0
483 end
484 + P("\21") / function()
485 result.basefontblend = stack[top]
486 top = 0
487 end
488 + P("\30") / function()
489 result.cid.registry = strings[stack[top-2]] or "unset"
490 result.cid.ordering = strings[stack[top-1]] or "unset"
491 result.cid.supplement = stack[top]
492 top = 0
493 end
494 + P("\31") / function()
495 result.cid.fontversion = stack[top]
496 top = 0
497 end
498 + P("\32") / function()
499 result.cid.fontrevision= stack[top]
500 top = 0
501 end
502 + P("\33") / function()
503 result.cid.fonttype = stack[top]
504 top = 0
505 end
506 + P("\34") / function()
507 result.cid.count = stack[top]
508 top = 0
509 end
510 + P("\35") / function()
511 result.cid.uidbase = stack[top]
512 top = 0
513 end
514 + P("\36") / function()
515 result.cid.fdarray = stack[top]
516 top = 0
517 end
518 + P("\37") / function()
519 result.cid.fdselect = stack[top]
520 top = 0
521 end
522 + P("\38") / function()
523 result.cid.fontname = strings[stack[top]] or "unset"
524 top = 0
525 end
526 )
527
528
529
530
531
532 local remap_1 = {
533 ["\x00"] = "00", ["\x01"] = "01", ["\x02"] = "02", ["\x03"] = "03", ["\x04"] = "04", ["\x05"] = "05", ["\x06"] = "06", ["\x07"] = "07", ["\x08"] = "08", ["\x09"] = "09", ["\x0A"] = "0.", ["\x0B"] = "0E", ["\x0C"] = "0E-", ["\x0D"] = "0", ["\x0E"] = "0-", ["\x0F"] = "0",
534 ["\x10"] = "10", ["\x11"] = "11", ["\x12"] = "12", ["\x13"] = "13", ["\x14"] = "14", ["\x15"] = "15", ["\x16"] = "16", ["\x17"] = "17", ["\x18"] = "18", ["\x19"] = "19", ["\x1A"] = "1.", ["\x1B"] = "1E", ["\x1C"] = "1E-", ["\x1D"] = "1", ["\x1E"] = "1-", ["\x1F"] = "1",
535 ["\x20"] = "20", ["\x21"] = "21", ["\x22"] = "22", ["\x23"] = "23", ["\x24"] = "24", ["\x25"] = "25", ["\x26"] = "26", ["\x27"] = "27", ["\x28"] = "28", ["\x29"] = "29", ["\x2A"] = "2.", ["\x2B"] = "2E", ["\x2C"] = "2E-", ["\x2D"] = "2", ["\x2E"] = "2-", ["\x2F"] = "2",
536 ["\x30"] = "30", ["\x31"] = "31", ["\x32"] = "32", ["\x33"] = "33", ["\x34"] = "34", ["\x35"] = "35", ["\x36"] = "36", ["\x37"] = "37", ["\x38"] = "38", ["\x39"] = "39", ["\x3A"] = "3.", ["\x3B"] = "3E", ["\x3C"] = "3E-", ["\x3D"] = "3", ["\x3E"] = "3-", ["\x3F"] = "3",
537 ["\x40"] = "40", ["\x41"] = "41", ["\x42"] = "42", ["\x43"] = "43", ["\x44"] = "44", ["\x45"] = "45", ["\x46"] = "46", ["\x47"] = "47", ["\x48"] = "48", ["\x49"] = "49", ["\x4A"] = "4.", ["\x4B"] = "4E", ["\x4C"] = "4E-", ["\x4D"] = "4", ["\x4E"] = "4-", ["\x4F"] = "4",
538 ["\x50"] = "50", ["\x51"] = "51", ["\x52"] = "52", ["\x53"] = "53", ["\x54"] = "54", ["\x55"] = "55", ["\x56"] = "56", ["\x57"] = "57", ["\x58"] = "58", ["\x59"] = "59", ["\x5A"] = "5.", ["\x5B"] = "5E", ["\x5C"] = "5E-", ["\x5D"] = "5", ["\x5E"] = "5-", ["\x5F"] = "5",
539 ["\x60"] = "60", ["\x61"] = "61", ["\x62"] = "62", ["\x63"] = "63", ["\x64"] = "64", ["\x65"] = "65", ["\x66"] = "66", ["\x67"] = "67", ["\x68"] = "68", ["\x69"] = "69", ["\x6A"] = "6.", ["\x6B"] = "6E", ["\x6C"] = "6E-", ["\x6D"] = "6", ["\x6E"] = "6-", ["\x6F"] = "6",
540 ["\x70"] = "70", ["\x71"] = "71", ["\x72"] = "72", ["\x73"] = "73", ["\x74"] = "74", ["\x75"] = "75", ["\x76"] = "76", ["\x77"] = "77", ["\x78"] = "78", ["\x79"] = "79", ["\x7A"] = "7.", ["\x7B"] = "7E", ["\x7C"] = "7E-", ["\x7D"] = "7", ["\x7E"] = "7-", ["\x7F"] = "7",
541 ["\x80"] = "80", ["\x81"] = "81", ["\x82"] = "82", ["\x83"] = "83", ["\x84"] = "84", ["\x85"] = "85", ["\x86"] = "86", ["\x87"] = "87", ["\x88"] = "88", ["\x89"] = "89", ["\x8A"] = "8.", ["\x8B"] = "8E", ["\x8C"] = "8E-", ["\x8D"] = "8", ["\x8E"] = "8-", ["\x8F"] = "8",
542 ["\x90"] = "90", ["\x91"] = "91", ["\x92"] = "92", ["\x93"] = "93", ["\x94"] = "94", ["\x95"] = "95", ["\x96"] = "96", ["\x97"] = "97", ["\x98"] = "98", ["\x99"] = "99", ["\x9A"] = "9.", ["\x9B"] = "9E", ["\x9C"] = "9E-", ["\x9D"] = "9", ["\x9E"] = "9-", ["\x9F"] = "9",
543 ["\xA0"] = ".0", ["\xA1"] = ".1", ["\xA2"] = ".2", ["\xA3"] = ".3", ["\xA4"] = ".4", ["\xA5"] = ".5", ["\xA6"] = ".6", ["\xA7"] = ".7", ["\xA8"] = ".8", ["\xA9"] = ".9", ["\xAA"] = "..", ["\xAB"] = ".E", ["\xAC"] = ".E-", ["\xAD"] = ".", ["\xAE"] = ".-", ["\xAF"] = ".",
544 ["\xB0"] = "E0", ["\xB1"] = "E1", ["\xB2"] = "E2", ["\xB3"] = "E3", ["\xB4"] = "E4", ["\xB5"] = "E5", ["\xB6"] = "E6", ["\xB7"] = "E7", ["\xB8"] = "E8", ["\xB9"] = "E9", ["\xBA"] = "E.", ["\xBB"] = "EE", ["\xBC"] = "EE-", ["\xBD"] = "E", ["\xBE"] = "E-", ["\xBF"] = "E",
545 ["\xC0"] = "E-0", ["\xC1"] = "E-1", ["\xC2"] = "E-2", ["\xC3"] = "E-3", ["\xC4"] = "E-4", ["\xC5"] = "E-5", ["\xC6"] = "E-6", ["\xC7"] = "E-7", ["\xC8"] = "E-8", ["\xC9"] = "E-9", ["\xCA"] = "E-.", ["\xCB"] = "E-E", ["\xCC"] = "E-E-", ["\xCD"] = "E-", ["\xCE"] = "E--", ["\xCF"] = "E-",
546 ["\xD0"] = "-0", ["\xD1"] = "-1", ["\xD2"] = "-2", ["\xD3"] = "-3", ["\xD4"] = "-4", ["\xD5"] = "-5", ["\xD6"] = "-6", ["\xD7"] = "-7", ["\xD8"] = "-8", ["\xD9"] = "-9", ["\xDA"] = "-.", ["\xDB"] = "-E", ["\xDC"] = "-E-", ["\xDD"] = "-", ["\xDE"] = "--", ["\xDF"] = "-",
547 }
548 local remap_2 = {
549 ["\x0F"] = "0", ["\x1F"] = "1", ["\x2F"] = "2", ["\x3F"] = "3", ["\x4F"] = "4",
550 ["\x5F"] = "5", ["\x6F"] = "6", ["\x7F"] = "7", ["\x8F"] = "8", ["\x9F"] = "9",
551 }
552
553 local p_last_1 = S("\x0F\x1F\x2F\x3F\x4F\x5F\x6F\x7F\x8F\x9F\xAF\xBF")
554 local p_last_2 = R("\xF0\xFF")
555
556
557
558
559 local p_nibbles = P("\30") * Cs(((1-(p_last_1+p_last_2))/remap_1)^0 * (p_last_1/remap_2 + p_last_2/"")) / function(n)
560
561 top = top + 1
562 stack[top] = tonumber(n) or 0
563 end
564
565 local p_byte = C(R("\32\246")) / function(b0)
566
567 top = top + 1
568 stack[top] = byte(b0) - 139
569 end
570
571 local p_positive = C(R("\247\250")) * C(1) / function(b0,b1)
572
573 top = top + 1
574 stack[top] = (byte(b0)-247)*256 + byte(b1) + 108
575 end
576
577 local p_negative = C(R("\251\254")) * C(1) / function(b0,b1)
578
579 top = top + 1
580 stack[top] = -(byte(b0)-251)*256 - byte(b1) - 108
581 end
582
583
584
585
586
587
588 local p_short = P("\28") * C(1) * C(1) / function(b1,b2)
589
590 top = top + 1
591 local n = 0x100 * byte(b1) + byte(b2)
592 if n >= 0x8000 then
593 stack[top] = n - 0xFFFF - 1
594 else
595 stack[top] = n
596 end
597 end
598
599 local p_long = P("\29") * C(1) * C(1) * C(1) * C(1) / function(b1,b2,b3,b4)
600
601 top = top + 1
602 local n = 0x1000000 * byte(b1) + 0x10000 * byte(b2) + 0x100 * byte(b3) + byte(b4)
603 if n >= 0x8000000 then
604 stack[top] = n - 0xFFFFFFFF - 1
605 else
606 stack[top] = n
607 end
608 end
609
610 local p_unsupported = P(1) / function(detail)
611 top = 0
612 end
613
614 p_dictionary = (
615 p_byte
616 + p_positive
617 + p_negative
618 + p_short
619 + p_long
620 + p_nibbles
621 + p_single
622 + p_double
623
624 + p_unsupported
625 )^1
626
627 end
628
629 parsedictionaries = function(data,dictionaries,version)
630 stack = { }
631 strings = data.strings
632 if trace_charstrings then
633 report("charstring format %a",version)
634 end
635 for i=1,#dictionaries do
636 top = 0
637 result = version == "cff" and {
638 monospaced = false,
639 italicangle = 0,
640 underlineposition = -100,
641 underlinethickness = 50,
642 painttype = 0,
643 charstringtype = 2,
644 fontmatrix = { 0.001, 0, 0, 0.001, 0, 0 },
645 fontbbox = { 0, 0, 0, 0 },
646 strokewidth = 0,
647 charset = 0,
648 encoding = 0,
649 cid = {
650 fontversion = 0,
651 fontrevision = 0,
652 fonttype = 0,
653 count = 8720,
654 }
655 } or {
656 charstringtype = 2,
657 charset = 0,
658 vstore = 0,
659 cid = {
660
661 },
662 }
663 lpegmatch(p_dictionary,dictionaries[i])
664 dictionaries[i] = result
665 end
666
667 result = { }
668 top = 0
669 stack = { }
670 end
671
672 parseprivates = function(data,dictionaries)
673 stack = { }
674 strings = data.strings
675 for i=1,#dictionaries do
676 local private = dictionaries[i].private
677 if private and private.data then
678 top = 0
679 result = {
680 forcebold = false,
681 languagegroup = 0,
682 expansionfactor = 0.06,
683 initialrandomseed = 0,
684 subroutines = 0,
685 defaultwidthx = 0,
686 nominalwidthx = 0,
687 cid = {
688
689 },
690 }
691 lpegmatch(p_dictionary,private.data)
692 private.data = result
693 end
694 end
695 result = { }
696 top = 0
697 stack = { }
698 end
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716 local x = 0
717 local y = 0
718 local width = false
719 local lsb = 0
720 local result = { }
721 local r = 0
722 local stems = 0
723 local globalbias = 0
724 local localbias = 0
725 local nominalwidth = 0
726 local defaultwidth = 0
727 local charset = false
728 local globals = false
729 local locals = false
730 local depth = 1
731 local xmin = 0
732 local xmax = 0
733 local ymin = 0
734 local ymax = 0
735 local checked = false
736 local keepcurve = false
737 local version = 2
738 local regions = false
739 local nofregions = 0
740 local region = false
741 local factors = false
742 local axis = false
743 local vsindex = 0
744 local justpass = false
745 local seacs = { }
746 local procidx = nil
747 local flexhints = { }
748 local ignorehint = false
749 local nofflexhints = 0
750
751 local encode = { }
752 local chars = { }
753 local typeone = false
754
755 local function showstate(where,i,n)
756 if i then
757 local j = i + n - 1
758 report("%w%-10s : [%s] step",depth*2+2,where,concat(stack," ",i,j <= top and j or top))
759 else
760 report("%w%-10s : [%s] n=%i",depth*2,where,concat(stack," ",1,top),top)
761 end
762 end
763
764 local function showvalue(where,value,showstack)
765 if showstack then
766 report("%w%-10s : %s : [%s] n=%i",depth*2,where,tostring(value),concat(stack," ",1,top),top)
767 else
768 report("%w%-10s : %s",depth*2,where,tostring(value))
769 end
770 end
771
772
773
774
775
776
777 setmetatableindex(chars,function (t,k)
778 local v = char(k)
779 t[k] = v
780 return v
781 end)
782
783 local c_endchar <const> = chars[14]
784
785 local c_closepath <const> = chars[09]
786 local c_endchar <const> = chars[14]
787
788 local c_command <const> = chars[12]
789
790 local pack_result_tagged, pack_result_untagged do
791
792 local c_vlineto <const> = chars[07]
793 local c_hlineto <const> = chars[06]
794 local c_rlineto <const> = chars[05]
795
796 local c_vhcurveto <const> = chars[30]
797 local c_hvcurveto <const> = chars[31]
798 local c_rrcurveto <const> = chars[08]
799
800 local c_vmoveto <const> = chars[04]
801 local c_hmoveto <const> = chars[22]
802 local c_rmoveto <const> = chars[21]
803
804 local function pack_curveto(result,r,x,y,x1,y1,x2,y2,x3,y3)
805 local d1 = x2 - x
806 local d2 = y2 - y
807 local d3 = x3 - x2
808 local d4 = y3 - y2
809 local d5 = x1 - x3
810 local d6 = y1 - y3
811 if d1 == 0 and d6 == 0 then
812 r = r + 1 ; result[r] = encode[d2]
813 r = r + 1 ; result[r] = encode[d3]
814 r = r + 1 ; result[r] = encode[d4]
815 r = r + 1 ; result[r] = encode[d5]
816 r = r + 1 ; result[r] = c_vhcurveto
817 elseif d2 == 0 and d5 == 0 then
818 r = r + 1 ; result[r] = encode[d1]
819 r = r + 1 ; result[r] = encode[d3]
820 r = r + 1 ; result[r] = encode[d4]
821 r = r + 1 ; result[r] = encode[d6]
822 r = r + 1 ; result[r] = c_hvcurveto
823 else
824 r = r + 1 ; result[r] = encode[d1]
825 r = r + 1 ; result[r] = encode[d2]
826 r = r + 1 ; result[r] = encode[d3]
827 r = r + 1 ; result[r] = encode[d4]
828 r = r + 1 ; result[r] = encode[d5]
829 r = r + 1 ; result[r] = encode[d6]
830 r = r + 1 ; result[r] = c_rrcurveto
831 end
832 return r, x1, y1
833 end
834
835 local function pack_moveto(result,r,x,y,x1,y1)
836 x = x1 - x
837 y = y1 - y
838 if x == 0 then
839 r = r + 1 ; result[r] = encode[y]
840 r = r + 1 ; result[r] = c_vmoveto
841 elseif y == 0 then
842 r = r + 1 ; result[r] = encode[x]
843 r = r + 1 ; result[r] = c_hmoveto
844 else
845 r = r + 1 ; result[r] = encode[x]
846 r = r + 1 ; result[r] = encode[y]
847 r = r + 1 ; result[r] = c_rmoveto
848 end
849 return r, x1, y1
850 end
851
852 local function pack_lineto(result,r,x,y,x1,y1)
853 x = x1 - x
854 y = y1 - y
855 if x == 0 then
856 r = r + 1 ; result[r] = encode[y]
857 r = r + 1 ; result[r] = c_vlineto
858 elseif y == 0 then
859 r = r + 1 ; result[r] = encode[x]
860 r = r + 1 ; result[r] = c_hlineto
861 else
862 r = r + 1 ; result[r] = encode[x]
863 r = r + 1 ; result[r] = encode[y]
864 r = r + 1 ; result[r] = c_rlineto
865 end
866 return r, x1, y1
867 end
868
869 pack_result_tagged = function(t,width,xoffset,yoffset)
870
871
872 local result = { encode[width], encode[xoffset or 0], c_hmoveto }
873 local r = 3
874 local n = #t
875 local x = 0
876 local y = yoffset or 0
877
878
879
880 for i=1,n do
881 local ti = t[i]
882 local tg = ti[#ti]
883 if tg == "c" then
884 r, x, y = pack_curveto(result,r,x,y,ti[5],ti[6],ti[1],ti[2],ti[3],ti[4])
885 elseif tg == "l" then
886 r, x, y = pack_lineto(result,r,x,y,ti[1],ti[2])
887 elseif tg == "m" then
888 r, x, y = pack_moveto(result,r,x,y,ti[1],ti[2])
889 elseif tg == "close" then
890 r = r + 1 ; result[r] = c_closepath
891 end
892 end
893 r = r + 1 ; result[r] = c_closepath
894 r = r + 1 ; result[r] = c_endchar
895 return concat(result)
896 end
897
898 pack_result_untagged = function(t,width,xoffset,yoffset)
899 local result = { encode[width], encode[xoffset or 0], c_hmoveto }
900 local r = 3
901 local n = #t
902 local x = 0
903 local y = yoffset or 0
904 for i=1,n do
905 local ti = t[i]
906 local ni = #ti
907 for j=1,ni do
908 local tj = ti[j]
909 local nj = #tj
910 if nj == 6 then
911 r, x, y = pack_curveto(result,r,x,y,tj[1],tj[2],tj[3],tj[4],tj[5],tj[6])
912 elseif j == 1 then
913 r, x, y = pack_moveto(result,r,x,y,tj[1],tj[2])
914 else
915 r, x, y = pack_lineto(result,r,x,y,tj[1],tj[2])
916 end
917 end
918 end
919 r = r + 1 ; result[r] = c_closepath
920 r = r + 1 ; result[r] = c_endchar
921 return concat(result)
922 end
923
924 end
925
926
927
928
929
930
931
932
933 local xycurveto, xylineto, xymoveto
934
935 local function report_hints(verdict)
936 report("%w%-10s : [%s] n=%i, %s",depth*2,"hints",concat(flexhints," ",1,nofflexhints),nofflexhints,verdict)
937 end
938
939 local function flushflexhints()
940 if trace_charstrings then
941 showstate("flush flex hints")
942 end
943 if not ignorehint then
944
945 elseif nofflexhints == 14 then
946 if trace_charstrings then
947 report_hints("flex curves")
948 end
949 local ax = x + flexhints[01] + flexhints[03]
950 local ay = y + flexhints[02] + flexhints[04]
951 local bx = ax + flexhints[05]
952 local by = ay + flexhints[06]
953 local cx = bx + flexhints[07]
954 local cy = by + flexhints[08]
955 local dx = cx + flexhints[09]
956 local dy = cy + flexhints[10]
957 local ex = dx + flexhints[11]
958 local ey = dy + flexhints[12]
959 x = ex + flexhints[13]
960 y = ey + flexhints[14]
961 xycurveto(ax,ay,bx,by,cx,cy)
962 xycurveto(dx,dy,ex,ey,x,y)
963 else
964 if trace_charstrings then
965 report_hints(nofflexhints == 0 and "no values" or "incomplete")
966 end
967 end
968 ignorehint = false
969 nofflexhints = 0
970 end
971
972
973
974 local function collectflexhints()
975 if ignorehint then
976 if trace_charstrings then
977 showstate("already collecting flex hints")
978 end
979 else
980 nofflexhints = 0
981 ignorehint = true
982 if trace_charstrings then
983 showstate("collect flex hints")
984 end
985 end
986 end
987
988 local function resetflexhints(where)
989 if trace_charstrings then
990 showstate("reset flex hints")
991 report_hints(where)
992 end
993 ignorehint = false
994 nofflexhints = 0
995 end
996
997 local closepath, addmoveto, fixmoveto, setwidthfrommove, setwidthfromstem
998
999 do
1000
1001 local close_path = { "close", "path" }
1002 local close_move = { "close", "move" }
1003
1004 closepath = function()
1005 if version == "cff" then
1006 if trace_charstrings then
1007 showstate("closepath")
1008 end
1009
1010 if r > 0 then
1011 local rr = result[r]
1012 local cc = rr == close_move or rr == close_path
1013 local mm = rr[3] == "m"
1014 if cc then
1015
1016 elseif mm then
1017
1018 r = r - 1
1019 else
1020 r = r + 1 ; result[r] = close_path
1021 end
1022 end
1023 end
1024 top = 0
1025 end
1026
1027 addmoveto = function(x,y)
1028 if r > 0 then
1029 local rr = result[r]
1030 local cc = rr == close_move or rr == close_path
1031 local mm = rr[3] == "m"
1032 if cc then
1033
1034 elseif mm then
1035
1036 rr[1] = x
1037 rr[2] = y
1038 return
1039 else
1040 r = r + 1 ; result[r] = close_move
1041 end
1042 end
1043 r = r + 1 ; result[r] = { x, y, "m" }
1044 end
1045
1046 fixmoveto = function()
1047 x = x + flexhints[1]
1048 y = y + flexhints[2]
1049 addmoveto(x,y)
1050 if trace_charstrings then
1051 report_hints("fix moveto")
1052 end
1053 ignorehint = false
1054 nofflexhints = 0
1055 end
1056
1057 setwidthfrommove = function()
1058 if top > 1 then
1059 width = stack[1]
1060 if trace_charstrings then
1061 showvalue("width from move",width)
1062 end
1063 else
1064 width = true
1065 end
1066 end
1067
1068 setwidthfromstem = function()
1069 if width then
1070 remove(stack,1)
1071 else
1072 width = remove(stack,1)
1073 if trace_charstrings then
1074 showvalue("width from stem",width)
1075 end
1076 end
1077 top = top - 1
1078 end
1079
1080 end
1081
1082 xymoveto = function()
1083 if keepcurve then
1084 addmoveto(x,y)
1085 end
1086 if checked then
1087 if x > xmax then xmax = x elseif x < xmin then xmin = x end
1088 if y > ymax then ymax = y elseif y < ymin then ymin = y end
1089 else
1090 xmin = x
1091 ymin = y
1092 xmax = x
1093 ymax = y
1094 checked = true
1095 end
1096 end
1097
1098 local function xmoveto()
1099 if keepcurve then
1100 addmoveto(x,y)
1101 end
1102 if not checked then
1103 xmin = x
1104 ymin = y
1105 xmax = x
1106 ymax = y
1107 checked = true
1108 elseif x > xmax then
1109 xmax = x
1110 elseif x < xmin then
1111 xmin = x
1112 end
1113 end
1114
1115 local function ymoveto()
1116 if keepcurve then
1117 addmoveto(x,y)
1118 end
1119 if not checked then
1120 xmin = x
1121 ymin = y
1122 xmax = x
1123 ymax = y
1124 checked = true
1125 elseif y > ymax then
1126 ymax = y
1127 elseif y < ymin then
1128 ymin = y
1129 end
1130 end
1131
1132 local function moveto()
1133 if trace_charstrings then
1134 showstate("moveto")
1135 end
1136 top = 0
1137 xymoveto()
1138 end
1139
1140 xylineto = function()
1141 if keepcurve then
1142 r = r + 1 ; result[r] = { x, y, "l" }
1143 end
1144 if checked then
1145 if x > xmax then xmax = x elseif x < xmin then xmin = x end
1146 if y > ymax then ymax = y elseif y < ymin then ymin = y end
1147 else
1148 xmin = x
1149 ymin = y
1150 xmax = x
1151 ymax = y
1152 checked = true
1153 end
1154 end
1155
1156 local function xlineto()
1157 if keepcurve then
1158 r = r + 1 ; result[r] = { x, y, "l" }
1159 end
1160 if not checked then
1161 xmin = x
1162 ymin = y
1163 xmax = x
1164 ymax = y
1165 checked = true
1166 elseif x > xmax then
1167 xmax = x
1168 elseif x < xmin then
1169 xmin = x
1170 end
1171 end
1172
1173 local function ylineto()
1174 if keepcurve then
1175 r = r + 1 ; result[r] = { x, y, "l" }
1176 end
1177 if not checked then
1178 xmin = x
1179 ymin = y
1180 xmax = x
1181 ymax = y
1182 checked = true
1183 elseif y > ymax then
1184 ymax = y
1185 elseif y < ymin then
1186 ymin = y
1187 end
1188 end
1189
1190 xycurveto = function(x1,y1,x2,y2,x3,y3,i,n)
1191 if trace_charstrings then
1192 showstate("curveto",i,n)
1193 end
1194 if keepcurve then
1195 r = r + 1 ; result[r] = { x1, y1, x2, y2, x3, y3, "c" }
1196 end
1197 if checked then
1198 if x1 > xmax then xmax = x1 elseif x1 < xmin then xmin = x1 end
1199 if y1 > ymax then ymax = y1 elseif y1 < ymin then ymin = y1 end
1200 else
1201 xmin = x1
1202 ymin = y1
1203 xmax = x1
1204 ymax = y1
1205 checked = true
1206 end
1207 if x2 > xmax then xmax = x2 elseif x2 < xmin then xmin = x2 end
1208 if y2 > ymax then ymax = y2 elseif y2 < ymin then ymin = y2 end
1209 if x3 > xmax then xmax = x3 elseif x3 < xmin then xmin = x3 end
1210 if y3 > ymax then ymax = y3 elseif y3 < ymin then ymin = y3 end
1211 end
1212
1213 local function rmoveto()
1214 if ignorehint then
1215 if trace_charstrings then
1216 showstate("rmoveto (flex)")
1217 end
1218 nofflexhints = nofflexhints + 1 ; flexhints[nofflexhints] = stack[top-1]
1219 nofflexhints = nofflexhints + 1 ; flexhints[nofflexhints] = stack[top]
1220 top = 0
1221 else
1222 if trace_charstrings then
1223 showstate("rmoveto")
1224 end
1225 if not width then
1226 setwidthfrommove()
1227 end
1228 x = x + stack[top-1]
1229 y = y + stack[top]
1230 top = 0
1231 xymoveto()
1232 end
1233 end
1234
1235 local function hmoveto()
1236 if ignorehint then
1237 if trace_charstrings then
1238 showstate("hmoveto (flex)")
1239 end
1240 nofflexhints = nofflexhints + 1 ; flexhints[nofflexhints] = stack[top]
1241 nofflexhints = nofflexhints + 1 ; flexhints[nofflexhints] = 0
1242 top = 0
1243 else
1244 if trace_charstrings then
1245 showstate("hmoveto")
1246 end
1247 if not width then
1248 setwidthfrommove()
1249 end
1250 x = x + stack[top]
1251 top = 0
1252 xmoveto()
1253 end
1254 end
1255
1256 local function vmoveto()
1257 if ignorehint then
1258 if trace_charstrings then
1259 showstate("vmoveto (flex)")
1260 end
1261 nofflexhints = nofflexhints + 1 ; flexhints[nofflexhints] = 0
1262 nofflexhints = nofflexhints + 1 ; flexhints[nofflexhints] = stack[top]
1263 top = 0
1264 else
1265 if trace_charstrings then
1266 showstate("vmoveto")
1267 end
1268 if not width then
1269 setwidthfrommove()
1270 end
1271 y = y + stack[top]
1272 top = 0
1273 ymoveto()
1274 end
1275 end
1276
1277 local function rlineto()
1278 if nofflexhints > 0 then
1279 fixmoveto()
1280 end
1281 if trace_charstrings then
1282 showstate("rlineto")
1283 end
1284 for i=1,top,2 do
1285 x = x + stack[i]
1286 y = y + stack[i+1]
1287 xylineto()
1288 end
1289 top = 0
1290 end
1291
1292 local function hlineto()
1293 if nofflexhints > 0 then
1294 fixmoveto()
1295 end
1296 if trace_charstrings then
1297 showstate("hlineto")
1298 end
1299 if top == 1 then
1300 x = x + stack[1]
1301 xlineto()
1302 else
1303 local swap = true
1304 for i=1,top do
1305 local d = stack[i]
1306 if swap then
1307 x = x + d
1308 xlineto()
1309 swap = false
1310 else
1311 y = y + d
1312 ylineto()
1313 swap = true
1314 end
1315 end
1316 end
1317 top = 0
1318 end
1319
1320 local function vlineto()
1321 if nofflexhints > 0 then
1322 fixmoveto()
1323 end
1324 if trace_charstrings then
1325 showstate("vlineto")
1326 end
1327 if top == 1 then
1328 y = y + stack[1]
1329 ylineto()
1330 else
1331 local swap = false
1332 for i=1,top do
1333 local d = stack[i]
1334 if swap then
1335 x = x + d
1336 xlineto()
1337 swap = false
1338 else
1339 y = y + d
1340 ylineto()
1341 swap = true
1342 end
1343 end
1344 end
1345 top = 0
1346 end
1347
1348 local function rrcurveto()
1349 if nofflexhints > 0 then
1350 fixmoveto()
1351 end
1352 if trace_charstrings then
1353 showstate("rrcurveto")
1354 end
1355 if top == 6 then
1356 local ax = x + stack[1]
1357 local ay = y + stack[2]
1358 local bx = ax + stack[3]
1359 local by = ay + stack[4]
1360 x = bx + stack[5]
1361 y = by + stack[6]
1362 xycurveto(ax,ay,bx,by,x,y,1,6)
1363 else
1364 for i=1,top,6 do
1365 local ax = x + stack[i]
1366 local ay = y + stack[i+1]
1367 local bx = ax + stack[i+2]
1368 local by = ay + stack[i+3]
1369 x = bx + stack[i+4]
1370 y = by + stack[i+5]
1371 xycurveto(ax,ay,bx,by,x,y,i,6)
1372 end
1373 end
1374 top = 0
1375 end
1376
1377 local function hhcurveto()
1378 if nofflexhints > 0 then
1379 fixmoveto()
1380 end
1381 if trace_charstrings then
1382 showstate("hhcurveto")
1383 end
1384 if top == 4 then
1385 local ax = x + stack[1]
1386 local ay = y
1387 local bx = ax + stack[2]
1388 local by = ay + stack[3]
1389 x = bx + stack[4]
1390 y = by
1391 xycurveto(ax,ay,bx,by,x,y,1,4)
1392 elseif top == 5 then
1393 local ax = x + stack[2]
1394 local ay = y + stack[1]
1395 local bx = ax + stack[3]
1396 local by = ay + stack[4]
1397 x = bx + stack[5]
1398 y = by
1399 xycurveto(ax,ay,bx,by,x,y,2,4)
1400 else
1401 local s
1402 if top % 2 ~= 0 then
1403 y = y + stack[1]
1404 s = 2
1405 else
1406 s = 1
1407 end
1408 for i=s,top,4 do
1409 local ax = x + stack[i]
1410 local ay = y
1411 local bx = ax + stack[i+1]
1412 local by = ay + stack[i+2]
1413 x = bx + stack[i+3]
1414 y = by
1415 xycurveto(ax,ay,bx,by,x,y,i,4)
1416 end
1417 end
1418 top = 0
1419 end
1420
1421 local function vvcurveto()
1422 if nofflexhints > 0 then
1423 fixmoveto()
1424 end
1425 if trace_charstrings then
1426 showstate("vvcurveto")
1427 end
1428 if top == 4 then
1429 local ax = x
1430 local ay = y + stack[1]
1431 local bx = ax + stack[2]
1432 local by = ay + stack[3]
1433 x = bx
1434 y = by + stack[4]
1435 xycurveto(ax,ay,bx,by,x,y,1,4)
1436 elseif top == 5 then
1437 local ax = x + stack[1]
1438 local ay = y + stack[2]
1439 local bx = ax + stack[3]
1440 local by = ay + stack[4]
1441 x = bx
1442 y = by + stack[5]
1443 xycurveto(ax,ay,bx,by,x,y,2,4)
1444 else
1445 local s
1446 if top % 2 ~= 0 then
1447 x = x + stack[1]
1448 s = 2
1449 else
1450 s = 1
1451 end
1452 for i=s,top,4 do
1453 local ax = x
1454 local ay = y + stack[i]
1455 local bx = ax + stack[i+1]
1456 local by = ay + stack[i+2]
1457 x = bx
1458 y = by + stack[i+3]
1459 xycurveto(ax,ay,bx,by,x,y,i,4)
1460 end
1461 end
1462 top = 0
1463 end
1464
1465
1466
1467 local function xxcurveto(swap)
1468 local last = top % 4 ~= 0 and stack[top]
1469 if last then
1470 top = top - 1
1471 end
1472 if top == 4 then
1473 local ax, ay, bx, by
1474 if swap then
1475 ax = x + stack[1]
1476 ay = y
1477 bx = ax + stack[2]
1478 by = ay + stack[3]
1479 x = bx
1480 y = by + stack[4]
1481 if last then
1482 x = x + last
1483 end
1484 else
1485 ax = x
1486 ay = y + stack[1]
1487 bx = ax + stack[2]
1488 by = ay + stack[3]
1489 x = bx + stack[4]
1490 y = by
1491 if last then
1492 y = y + last
1493 end
1494 end
1495 xycurveto(ax,ay,bx,by,x,y,1,4)
1496 else
1497 local done = top - 3
1498 for i=1,top,4 do
1499 local ax, ay, bx, by
1500 if swap then
1501 ax = x + stack[i]
1502 ay = y
1503 bx = ax + stack[i+1]
1504 by = ay + stack[i+2]
1505 y = by + stack[i+3]
1506 x = bx
1507 swap = false
1508 else
1509 ax = x
1510 ay = y + stack[i]
1511 bx = ax + stack[i+1]
1512 by = ay + stack[i+2]
1513 x = bx + stack[i+3]
1514 y = by
1515 swap = true
1516 end
1517 if last and i == done then
1518 if swap then
1519 y = y + last
1520 else
1521 x = x + last
1522 end
1523 end
1524 xycurveto(ax,ay,bx,by,x,y,i,4)
1525 end
1526 end
1527 top = 0
1528 end
1529
1530 local function hvcurveto()
1531 if nofflexhints > 0 then
1532 fixmoveto()
1533 end
1534 if trace_charstrings then
1535 showstate("hvcurveto")
1536 end
1537 xxcurveto(true)
1538 end
1539
1540 local function vhcurveto()
1541 if nofflexhints > 0 then
1542 fixmoveto()
1543 end
1544 if trace_charstrings then
1545 showstate("vhcurveto")
1546 end
1547 xxcurveto(false)
1548 end
1549
1550 local function rcurveline()
1551 if nofflexhints > 0 then
1552 fixmoveto()
1553 end
1554 if trace_charstrings then
1555 showstate("rcurveline")
1556 end
1557 for i=1,top-2,6 do
1558 local ax = x + stack[i]
1559 local ay = y + stack[i+1]
1560 local bx = ax + stack[i+2]
1561 local by = ay + stack[i+3]
1562 x = bx + stack[i+4]
1563 y = by + stack[i+5]
1564 xycurveto(ax,ay,bx,by,x,y,i,6)
1565 end
1566 x = x + stack[top-1]
1567 y = y + stack[top]
1568 xylineto()
1569 top = 0
1570 end
1571
1572 local function rlinecurve()
1573 if nofflexhints > 0 then
1574 fixmoveto()
1575 end
1576 if trace_charstrings then
1577 showstate("rlinecurve")
1578 end
1579 if top > 6 then
1580 for i=1,top-6,2 do
1581 x = x + stack[i]
1582 y = y + stack[i+1]
1583 xylineto()
1584 end
1585 end
1586 local ax = x + stack[top-5]
1587 local ay = y + stack[top-4]
1588 local bx = ax + stack[top-3]
1589 local by = ay + stack[top-2]
1590 x = bx + stack[top-1]
1591 y = by + stack[top]
1592 xycurveto(ax,ay,bx,by,x,y)
1593 top = 0
1594 end
1595
1596
1597
1598 local function flex()
1599 if nofflexhints > 0 then
1600 fixmoveto()
1601 end
1602 if trace_charstrings then
1603 showstate("flex")
1604 end
1605 local ax = x + stack[1]
1606 local ay = y + stack[2]
1607 local bx = ax + stack[3]
1608 local by = ay + stack[4]
1609 local cx = bx + stack[5]
1610 local cy = by + stack[6]
1611 local dx = cx + stack[7]
1612 local dy = cy + stack[8]
1613 local ex = dx + stack[9]
1614 local ey = dy + stack[10]
1615 x = ex + stack[11]
1616 y = ey + stack[12]
1617 xycurveto(ax,ay,bx,by,cx,cy)
1618 xycurveto(dx,dy,ex,ey,x,y)
1619 top = 0
1620 end
1621
1622 local function hflex()
1623 if nofflexhints > 0 then
1624 fixmoveto()
1625 end
1626 if trace_charstrings then
1627 showstate("hflex")
1628 end
1629 local ax = x + stack[1]
1630 local ay = y
1631 local bx = ax + stack[2]
1632 local by = ay + stack[3]
1633 local cx = bx + stack[4]
1634 local cy = by
1635 xycurveto(ax,ay,bx,by,cx,cy)
1636 local dx = cx + stack[5]
1637 local dy = by
1638 local ex = dx + stack[6]
1639 local ey = y
1640 x = ex + stack[7]
1641 xycurveto(dx,dy,ex,ey,x,y)
1642 top = 0
1643 end
1644
1645 local function hflex1()
1646 if nofflexhints > 0 then
1647 fixmoveto()
1648 end
1649 if trace_charstrings then
1650 showstate("hflex1")
1651 end
1652 local ax = x + stack[1]
1653 local ay = y + stack[2]
1654 local bx = ax + stack[3]
1655 local by = ay + stack[4]
1656 local cx = bx + stack[5]
1657 local cy = by
1658 xycurveto(ax,ay,bx,by,cx,cy)
1659 local dx = cx + stack[6]
1660 local dy = by
1661 local ex = dx + stack[7]
1662 local ey = dy + stack[8]
1663 x = ex + stack[9]
1664 xycurveto(dx,dy,ex,ey,x,y)
1665 top = 0
1666 end
1667
1668 local function flex1()
1669 if nofflexhints > 0 then
1670 fixmoveto()
1671 end
1672 if trace_charstrings then
1673 showstate("flex1")
1674 end
1675 local ax = x + stack[1]
1676 local ay = y + stack[2]
1677 local bx = ax + stack[3]
1678 local by = ay + stack[4]
1679 local cx = bx + stack[5]
1680 local cy = by + stack[6]
1681 xycurveto(ax,ay,bx,by,cx,cy)
1682 local dx = cx + stack[7]
1683 local dy = cy + stack[8]
1684 local ex = dx + stack[9]
1685 local ey = dy + stack[10]
1686 if abs(ex - x) > abs(ey - y) then
1687 x = ex + stack[11]
1688 else
1689 y = ey + stack[11]
1690 end
1691 xycurveto(dx,dy,ex,ey,x,y)
1692 top = 0
1693 end
1694
1695 local function getstem()
1696 if top == 0 then
1697
1698 elseif top % 2 ~= 0 then
1699 setwidthfromstem()
1700 end
1701 if trace_charstrings then
1702 showstate("stem")
1703 end
1704 stems = stems + (top // 2)
1705 top = 0
1706 end
1707
1708 local function getmask()
1709 if top == 0 then
1710
1711 elseif top % 2 ~= 0 then
1712 setwidthfromstem()
1713 end
1714 if trace_charstrings then
1715 showstate("mask")
1716 end
1717 stems = stems + (top // 2)
1718 top = 0
1719 if stems == 0 then
1720
1721 elseif stems <= 8 then
1722 return 1
1723 else
1724 return (stems + 7) // 8
1725 end
1726 end
1727
1728 local function unsupported(t)
1729 if trace_charstrings then
1730 showstate("unsupported " .. t)
1731 end
1732 top = 0
1733 end
1734
1735 local function unsupportedsub(t)
1736 if trace_charstrings then
1737 showstate("unsupported sub " .. t)
1738 end
1739 top = 0
1740 end
1741
1742
1743
1744 local function getvstem3()
1745 if trace_charstrings then
1746 showstate("vstem3")
1747 end
1748 top = 0
1749 end
1750
1751 local function gethstem3()
1752 if trace_charstrings then
1753 showstate("hstem3")
1754 end
1755 top = 0
1756 end
1757
1758 local function divide()
1759 if version == "cff" then
1760 if trace_charstrings then
1761 showstate("divide")
1762 end
1763 local d = stack[top]
1764 top = top - 1
1765 stack[top] = stack[top] / d
1766 end
1767 end
1768
1769 local function hsbw()
1770 if version == "cff" then
1771 if trace_charstrings then
1772 showstate("hsbw")
1773 end
1774 lsb = stack[top-1] or 0
1775 width = stack[top]
1776 end
1777 top = 0
1778 end
1779
1780 local function sbw()
1781 if version == "cff" then
1782 if trace_charstrings then
1783 showstate("sbw")
1784 end
1785 lsb = stack[top-3]
1786 width = stack[top-1]
1787 end
1788 top = 0
1789 end
1790
1791
1792
1793 local function seac()
1794 if version == "cff" then
1795 if trace_charstrings then
1796 showstate("seac")
1797 end
1798 end
1799 top = 0
1800 end
1801
1802
1803
1804
1805 local hints <const> = 3
1806 local popped = 3
1807
1808
1809
1810
1811
1812
1813 local function callothersubr()
1814 if version == "cff" then
1815 if trace_charstrings then
1816 showstate("callothersubr")
1817 end
1818 if stack[top] == hints then
1819 popped = stack[top-2]
1820 else
1821 popped = 3
1822 end
1823 local t = stack[top-1]
1824 if t then
1825 top = top - (t + 2)
1826 if top < 0 then
1827 top = 0
1828 end
1829 else
1830 top = 0
1831 end
1832 else
1833 top = 0
1834 end
1835 end
1836
1837 local function pop()
1838 if version == "cff" then
1839 if trace_charstrings then
1840 showstate("pop")
1841 end
1842 top = top + 1
1843 stack[top] = popped
1844 else
1845 top = 0
1846 end
1847 end
1848
1849 local function setcurrentpoint()
1850 if version == "cff" then
1851 if trace_charstrings then
1852 showstate("setcurrentpoint (unsupported)")
1853 end
1854
1855 x = x + stack[top-1]
1856 y = y + stack[top]
1857 end
1858 top = 0
1859 end
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869 local reginit = false
1870
1871 local function updateregions(n)
1872 if regions then
1873 local current = regions[n+1] or regions[1]
1874 nofregions = #current
1875 if axis and n ~= reginit then
1876 factors = { }
1877 for i=1,nofregions do
1878 local region = current[i]
1879 local s = 1
1880 for j=1,#axis do
1881 local f = axis[j]
1882 local r = region[j]
1883 local start = r.start
1884 local peak = r.peak
1885 local stop = r.stop
1886 if start > peak or peak > stop then
1887
1888 elseif start < 0 and stop > 0 and peak ~= 0 then
1889
1890 elseif peak == 0 then
1891
1892 elseif f < start or f > stop then
1893
1894 s = 0
1895 break
1896 elseif f < peak then
1897 s = s * (f - start) / (peak - start)
1898 elseif f > peak then
1899 s = s * (stop - f) / (stop - peak)
1900 else
1901
1902 end
1903 end
1904 factors[i] = s
1905 end
1906 end
1907 end
1908 reginit = n
1909 end
1910
1911 local function setvsindex()
1912 local vsindex = stack[top]
1913 if trace_charstrings then
1914 showstate(formatters["vsindex %i"](vsindex))
1915 end
1916 updateregions(vsindex)
1917 top = top - 1
1918 end
1919
1920 local function blend()
1921 local n = stack[top]
1922 top = top - 1
1923 if axis then
1924
1925
1926 if trace_charstrings then
1927 local t = top - nofregions * n
1928 local m = t - n
1929 for i=1,n do
1930 local k = m + i
1931 local d = m + n + (i-1)*nofregions
1932 local old = stack[k]
1933 local new = old
1934 for r=1,nofregions do
1935 new = new + stack[d+r] * factors[r]
1936 end
1937 stack[k] = new
1938 showstate(formatters["blend %i of %i: %s -> %s"](i,n,old,new))
1939 end
1940 top = t
1941 elseif n == 1 then
1942 top = top - nofregions
1943 local v = stack[top]
1944 for r=1,nofregions do
1945 v = v + stack[top+r] * factors[r]
1946 end
1947 stack[top] = v
1948 else
1949 top = top - nofregions * n
1950 local d = top
1951 local k = top - n
1952 for i=1,n do
1953 k = k + 1
1954 local v = stack[k]
1955 for r=1,nofregions do
1956 v = v + stack[d+r] * factors[r]
1957 end
1958 stack[k] = v
1959 d = d + nofregions
1960 end
1961 end
1962 else
1963 top = top - nofregions * n
1964 end
1965 end
1966
1967
1968
1969
1970 local actions = { [0] =
1971 unsupported,
1972 getstem,
1973 unsupported,
1974 getstem,
1975 vmoveto,
1976 rlineto,
1977 hlineto,
1978 vlineto,
1979 rrcurveto,
1980 closepath,
1981 unsupported,
1982 unsupported,
1983 unsupported,
1984 hsbw,
1985 unsupported,
1986 setvsindex,
1987 blend,
1988 unsupported,
1989 getstem,
1990 getmask,
1991 getmask,
1992 rmoveto,
1993 hmoveto,
1994 getstem,
1995 rcurveline,
1996 rlinecurve,
1997 vvcurveto,
1998 hhcurveto,
1999 unsupported,
2000 unsupported,
2001 vhcurveto,
2002 hvcurveto,
2003 }
2004
2005 local reverse = { [0] =
2006 "unsupported",
2007 "getstem",
2008 "unsupported",
2009 "getstem",
2010 "vmoveto",
2011 "rlineto",
2012 "hlineto",
2013 "vlineto",
2014 "rrcurveto",
2015 "unsupported",
2016 "unsupported",
2017 "unsupported",
2018 "unsupported",
2019 "hsbw",
2020 "unsupported",
2021 "setvsindex",
2022 "blend",
2023 "unsupported",
2024 "getstem",
2025 "getmask",
2026 "getmask",
2027 "rmoveto",
2028 "hmoveto",
2029 "getstem",
2030 "rcurveline",
2031 "rlinecurve",
2032 "vvcurveto",
2033 "hhcurveto",
2034 "unsupported",
2035 "unsupported",
2036 "vhcurveto",
2037 "hvcurveto",
2038 }
2039
2040 local subactions = {
2041
2042 [000] = dotsection,
2043 [001] = getvstem3,
2044 [002] = gethstem3,
2045 [003] = false,
2046 [004] = false,
2047 [005] = false,
2048 [006] = seac,
2049 [007] = sbw,
2050 [008] = false,
2051 [009] = false,
2052 [010] = false,
2053 [011] = false,
2054 [012] = divide,
2055 [013] = false,
2056 [014] = false,
2057 [015] = false,
2058 [016] = callothersubr,
2059 [017] = pop,
2060 [018] = false,
2061 [019] = false,
2062 [020] = false,
2063 [021] = false,
2064 [022] = false,
2065 [023] = false,
2066 [024] = false,
2067 [025] = false,
2068 [026] = false,
2069 [027] = false,
2070 [028] = false,
2071 [029] = false,
2072 [030] = false,
2073 [032] = false,
2074 [033] = false,
2075 [033] = setcurrentpoint,
2076 [034] = hflex,
2077 [035] = flex,
2078 [036] = hflex1,
2079 [037] = flex1,
2080 }
2081
2082
2083
2084
2085
2086 setmetatableindex(encode,function(t,i)
2087 for i=-2048,-1130 do
2088
2089 t[i] = char(28,(i >> 8) & 0xFF,i & 0xFF)
2090 end
2091 for i=-1131,-108 do
2092 local v = 0xFB00 - i - 108
2093
2094 t[i] = char((v >> 8) & 0xFF,v & 0xFF)
2095 end
2096 for i=-107,107 do
2097 t[i] = chars[i + 139]
2098 end
2099 for i=108,1131 do
2100 local v = 0xF700 + i - 108
2101
2102 t[i] = char((v >> 8) & 0xFF,v & 0xFF)
2103 end
2104 for i=1132,2048 do
2105
2106 t[i] = char(28,(i >> 8) & 0xFF,i & 0xFF)
2107 end
2108 setmetatableindex(encode,function(t,k)
2109
2110 local r = round(k)
2111 local v = rawget(t,r)
2112 if v then
2113 return v
2114 end
2115 local v1 = floor(k)
2116 local v2 = floor((k - v1) * 0x10000)
2117
2118 return char(255,(v1 >> 8) & 0xFF,v1 & 0xFF,(v2 >> 8) & 0xFF,v2 & 0xFF)
2119 end)
2120 return t[i]
2121 end)
2122
2123 readers.cffencoder = encode
2124
2125 local function p_setvsindex()
2126 local vsindex = stack[top]
2127 updateregions(vsindex)
2128 top = top - 1
2129 end
2130
2131 local function p_blend()
2132
2133 local n = stack[top]
2134 top = top - 1
2135 if not axis then
2136
2137 elseif n == 1 then
2138 top = top - nofregions
2139 local v = stack[top]
2140 for r=1,nofregions do
2141 v = v + stack[top+r] * factors[r]
2142 end
2143 stack[top] = round(v)
2144 else
2145 top = top - nofregions * n
2146 local d = top
2147 local k = top - n
2148 for i=1,n do
2149 k = k + 1
2150 local v = stack[k]
2151 for r=1,nofregions do
2152 v = v + stack[d+r] * factors[r]
2153 end
2154 stack[k] = round(v)
2155 d = d + nofregions
2156 end
2157 end
2158 end
2159
2160 local function p_getstem()
2161 local n = 0
2162 if top % 2 ~= 0 then
2163 n = 1
2164 end
2165 if top > n then
2166 stems = stems + ((top - n) // 2)
2167 end
2168 end
2169
2170 local function p_getmask()
2171 local n = 0
2172 if top % 2 ~= 0 then
2173 n = 1
2174 end
2175 if top > n then
2176 stems = stems + ((top - n) // 2)
2177 end
2178 if stems == 0 then
2179 return 0
2180 elseif stems <= 8 then
2181 return 1
2182 else
2183 return (stems + 7) // 8
2184 end
2185 end
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207 local process
2208
2209 local function call(scope,list,bias)
2210 if top == 0 then
2211 showstate(formatters["unknown %s call %s, bias %i, case %s"](scope,"?",bias-1,1))
2212 top = 0
2213 else
2214 local index = bias + stack[top]
2215 top = top - 1
2216 if trace_charstrings then
2217 showvalue(scope,index,true)
2218 end
2219 depth = depth + 1
2220
2221
2222 if version == "cff" then
2223 if index == 0 then
2224 flushflexhints()
2225 elseif index == 1 then
2226 collectflexhints()
2227
2228
2229
2230
2231 end
2232 end
2233 local tab = list[index]
2234 if tab then
2235 process(tab)
2236 else
2237 showstate(formatters["unknown %s call %s, bias %i, case %s"](scope,index,bias-1,2))
2238 top = 0
2239 end
2240 depth = depth - 1
2241 end
2242 end
2243
2244
2245
2246
2247 do
2248
2249 local op_hstem <const> = 1
2250
2251 local op_vstem <const> = 3
2252
2253
2254
2255
2256 local op_rrcurveto <const> = 8
2257 local op_closepath <const> = 9
2258 local op_callsubr <const> = 10
2259 local op_return <const> = 11
2260 local op_escape <const> = 12
2261 local op_hsbw <const> = 13
2262 local op_endchar <const> = 14
2263 local op_setvsindex <const> = 15
2264 local op_blend <const> = 16
2265
2266 local op_hstemhm <const> = 18
2267 local op_hintmask <const> = 19
2268 local op_cntrmask <const> = 20
2269
2270
2271 local op_vstemhm <const> = 23
2272
2273
2274
2275
2276 local op_integer <const> = 28
2277 local op_callgsubr <const> = 29
2278
2279
2280
2281 process = function(tab)
2282 local i = 1
2283 local n = #tab
2284 while i <= n do
2285 local t = tab[i]
2286 if t >= 32 then
2287 top = top + 1
2288 if t <= 246 then
2289
2290 stack[top] = t - 139
2291 i = i + 1
2292 elseif t <= 250 then
2293
2294
2295
2296 stack[top] = t*256 - 63124 + tab[i+1]
2297 i = i + 2
2298 elseif t <= 254 then
2299
2300
2301
2302 stack[top] = -t*256 + 64148 - tab[i+1]
2303 i = i + 2
2304 elseif typeone then
2305 local n = 0x1000000 * tab[i+1] + 0x10000 * tab[i+2] + 0x100 * tab[i+3] + tab[i+4]
2306 if n >= 0x8000000 then
2307 n = n - 0xFFFFFFFF - 1
2308 end
2309 stack[top] = n
2310 i = i + 5
2311 else
2312 local n1 = 0x100 * tab[i+1] + tab[i+2]
2313 local n2 = 0x100 * tab[i+3] + tab[i+4]
2314 if n1 >= 0x8000 then
2315 n1 = n1 - 0x10000
2316 end
2317 stack[top] = n1 + n2/0xFFFF
2318 i = i + 5
2319 end
2320 elseif t == op_integer then
2321
2322 top = top + 1
2323 local n = 0x100 * tab[i+1] + tab[i+2]
2324 if n >= 0x8000 then
2325
2326 stack[top] = n - 0x10000
2327 else
2328 stack[top] = n
2329 end
2330 i = i + 3
2331 elseif t == op_return then
2332 if trace_charstrings then
2333 showstate("return")
2334 end
2335 return
2336 elseif t == op_callsubr then
2337 call("local",locals,localbias)
2338 i = i + 1
2339 elseif t == op_endchar then
2340 if width then
2341
2342 elseif top > 0 then
2343 width = stack[1]
2344 if r == 0 and justpass then
2345
2346 r = r + 1 ; result[r] = encode[width]
2347 r = r + 1 ; result[r] = c_endchar
2348 end
2349 if trace_charstrings then
2350 showvalue("width",width)
2351 end
2352 else
2353 width = true
2354 end
2355 if trace_charstrings then
2356 showstate("endchar")
2357 end
2358 return
2359 elseif t == op_callgsubr then
2360 call("global",globals,globalbias)
2361 i = i + 1
2362 elseif t == op_escape then
2363 i = i + 1
2364 local t = tab[i]
2365 if justpass then
2366 if t >= 34 and t <= 37 then
2367
2368 for i=1,top do
2369 r = r + 1 ; result[r] = encode[stack[i]]
2370 end
2371 r = r + 1 ; result[r] = c_command
2372 r = r + 1 ; result[r] = chars[t]
2373 top = 0
2374 elseif t == 6 then
2375
2376 seacs[procidx] = {
2377 asb = stack[1],
2378 adx = stack[2],
2379 ady = stack[3],
2380 base = stack[4],
2381 accent = stack[5],
2382 width = width,
2383 lsb = lsb,
2384 }
2385 top = 0
2386 else
2387
2388
2389
2390
2391
2392 local a = subactions[t]
2393 if a then
2394 a(t)
2395 else
2396 top = 0
2397 end
2398 end
2399 else
2400 local a = subactions[t]
2401 if a then
2402 a(t)
2403 else
2404 if trace_charstrings then
2405 showvalue("<subaction>",t)
2406 end
2407 top = 0
2408 end
2409 end
2410 i = i + 1
2411 elseif justpass then
2412
2413 if t == op_setvsindex then
2414 p_setvsindex()
2415 i = i + 1
2416 elseif t == op_blend then
2417 local s = p_blend() or 0
2418 i = i + s + 1
2419
2420 elseif t == op_hstem or t == op_vstem or t == op_hstemhm or operation == op_vstemhm then
2421 p_getstem()
2422 if version == "cff" then
2423
2424 if top > 0 then
2425 for i=1,top do
2426 r = r + 1 ; result[r] = encode[stack[i]]
2427 end
2428 top = 0
2429 end
2430 r = r + 1 ; result[r] = chars[t]
2431 else
2432 top = 0
2433 end
2434 i = i + 1
2435
2436 elseif t == op_hintmask or t == op_cntrmask then
2437 local s = p_getmask() or 0
2438
2439 if true then
2440 if top > 0 then
2441 for i=1,top do
2442 r = r + 1 ; result[r] = encode[stack[i]]
2443 end
2444 top = 0
2445 end
2446 r = r + 1 ; result[r] = chars[t]
2447 for j=1,s do
2448 i = i + 1
2449 r = r + 1 ; result[r] = chars[tab[i]]
2450 end
2451 else
2452 i = i + s
2453 top = 0
2454 end
2455 i = i + 1
2456 elseif t == op_closepath then
2457 if version == "cff" then
2458 r = r + 1 ; result[r] = c_closepath
2459 end
2460 top = 0
2461 i = i + 1
2462 elseif t == op_hsbw then
2463 hsbw()
2464
2465 if true then
2466
2467 r = r + 1 ; result[r] = encode[lsb]
2468 r = r + 1 ; result[r] = chars[22]
2469 else
2470
2471 end
2472 i = i + 1
2473 else
2474 if trace_charstrings then
2475 showstate(reverse[t] or "<action>")
2476 end
2477 if top > 0 then
2478
2479 if t == op_rrcurveto and top > 48 then
2480
2481
2482
2483
2484 local n = 0
2485 for i=1,top do
2486
2487 if n == 48 then
2488 r = r + 1 ; result[r] = chars[t]
2489 n = 1
2490 else
2491 n = n + 1
2492 end
2493 r = r + 1 ; result[r] = encode[stack[i]]
2494 end
2495 else
2496 for i=1,top do
2497 r = r + 1 ; result[r] = encode[stack[i]]
2498 end
2499 end
2500 top = 0
2501 end
2502 r = r + 1 ; result[r] = chars[t]
2503 i = i + 1
2504 end
2505 else
2506 local a = actions[t]
2507 if a then
2508 local s = a(t)
2509 if s then
2510 i = i + s + 1
2511 else
2512 i = i + 1
2513 end
2514 else
2515 if trace_charstrings then
2516 showstate(reverse[t] or "<action>")
2517 end
2518 top = 0
2519 i = i + 1
2520 end
2521 end
2522 end
2523 end
2524
2525 end
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567 readers.potracetocff = potrace and function(glyph,settings)
2568 local xsize = glyph.xsize or 0
2569 local ysize = glyph.ysize or 0
2570 local xoffset = glyph.xoffset or 0
2571 local yoffset = glyph.yoffset or 0
2572 local llx = - xoffset
2573 local lly = yoffset - ysize + 1
2574 local urx = llx + xsize + 1
2575 local ury = lly + ysize
2576
2577 local b, w, h = fonts.handlers.tfm.readers.showpk(glyph,true)
2578 if not b then
2579 return
2580 end
2581 local t = potrace.convert(b,settings,w,h)
2582
2583 llx = round(10*llx)
2584 lly = round(10*lly)
2585 urx = round(10*urx)
2586 ury = round(10*ury)
2587 xoffset = llx
2588 yoffset = -lly
2589
2590 local width = round(10*glyph.width/65536)
2591
2592 for i=1,#t do
2593 local ti = t[i]
2594 for j=1,#ti do
2595 local tj = ti[j]
2596 for k=1,#tj do
2597 tj[k] = round(10*tj[k])
2598 end
2599 end
2600 end
2601 return llx, lly, urx, ury, pack_result_untagged(t,width,xoffset,yoffset)
2602 end or function()
2603 return 0, 0, 0, 0, c_endchar
2604 end
2605
2606
2607
2608
2609
2610 local function getbias(t)
2611 local n = #t
2612 if n < 1240 then return 108
2613 elseif n < 33900 then return 1132
2614 else return 32769
2615 end
2616 end
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627 local force_flatten = false
2628
2629 directives.register("fonts.cff.flatten", function(v) force_flatten = v end )
2630
2631 local function processshape(glyphs,tab,index,hack)
2632
2633 local glyphname = charset and charset[index] or nil
2634
2635 if not tab then
2636 glyphs[index] = {
2637 boundingbox = { 0, 0, 0, 0 },
2638 width = 0,
2639 name = glyphname,
2640 }
2641 return
2642 end
2643
2644 tab = bytetable(tab)
2645
2646 x = 0
2647 y = 0
2648 width = false
2649 lsb = 0
2650 r = 0
2651 top = 0
2652 stems = 0
2653 result = { }
2654 popped = 3
2655 procidx = index
2656
2657 nofflexhints = 0
2658 ignorehint = false
2659
2660 xmin = 0
2661 xmax = 0
2662 ymin = 0
2663 ymax = 0
2664 checked = false
2665 if trace_charstrings then
2666 report("glyph: %i %s",index,glyphname or "")
2667 report("data : % t",tab)
2668 end
2669
2670 if regions then
2671 updateregions(vsindex)
2672 end
2673
2674 local jp = justpass
2675
2676 if justpass and version == "cff0" or typeone then
2677 version = "cff"
2678 justpass = false
2679 end
2680
2681 if force_flatten then
2682 justpass = false
2683 end
2684
2685 process(tab)
2686 if hack then
2687 return x, y
2688 end
2689
2690 local boundingbox = {
2691 round(xmin),
2692 round(ymin),
2693 round(xmax),
2694 round(ymax),
2695 }
2696
2697 if width == true or width == false then
2698 width = defaultwidth
2699 else
2700 width = nominalwidth + width
2701 end
2702
2703 local glyph = glyphs[index]
2704
2705 if jp then
2706 local stream
2707 if justpass then
2708 r = r + 1
2709 result[r] = c_endchar
2710 stream = concat(result)
2711 result = nil
2712 else
2713 stream = pack_result_tagged(result,width,lsb)
2714 justpass = jp
2715 end
2716
2717
2718
2719 if glyph then
2720 glyph.stream = stream
2721 glyph.width = width
2722 else
2723 glyphs[index] = { stream = stream, width = width }
2724 end
2725 elseif glyph then
2726 glyph.segments = keepcurve ~= false and result or nil
2727 glyph.boundingbox = boundingbox
2728 if not glyph.width then
2729
2730
2731 glyph.width = round(width)
2732 end
2733 if not glyph.name then
2734 glyph.name = glyphname
2735 end
2736
2737 elseif keepcurve then
2738 glyphs[index] = {
2739 segments = result,
2740 boundingbox = boundingbox,
2741 width = width,
2742 name = glyphname,
2743
2744 }
2745 result = nil
2746 else
2747 glyphs[index] = {
2748 boundingbox = boundingbox,
2749 width = width,
2750 name = glyphname,
2751 }
2752 end
2753 if trace_charstrings then
2754 report("width : %s",tostring(width))
2755 report("boundingbox: % t",boundingbox)
2756 end
2757
2758 end
2759
2760 startparsing = function(fontdata,data,streams)
2761 reginit = false
2762 axis = false
2763 regions = data.regions
2764 justpass = streams == true
2765 popped = 3
2766 seacs = { }
2767 if regions then
2768
2769
2770
2771 regions = { }
2772 local deltas = data.deltas
2773 for i = 1, #deltas do
2774 regions[i] = deltas[i].regions
2775 end
2776 axis = data.factors or false
2777 end
2778 end
2779
2780 stopparsing = function(fontdata,data)
2781 stack = { }
2782 glyphs = false
2783 result = { }
2784 top = 0
2785 locals = false
2786 globals = false
2787 strings = false
2788 popped = 3
2789 seacs = { }
2790 nofflexhints = 0
2791 ignorehint = false
2792 end
2793
2794 local function setwidths(private)
2795 if not private then
2796 return 0, 0
2797 end
2798 local privatedata = private.data
2799 if not privatedata then
2800 return 0, 0
2801 end
2802 return privatedata.nominalwidthx or 0, privatedata.defaultwidthx or 0
2803 end
2804
2805 parsecharstrings = function(fontdata,data,glphs,doshapes,tversion,streams,nobias,istypeone)
2806
2807 local dictionary = data.dictionaries[1]
2808 local charstrings = dictionary.charstrings
2809
2810 keepcurve = doshapes
2811 version = tversion
2812 typeone = istypeone or false
2813 strings = data.strings
2814 globals = data.routines or { }
2815 locals = dictionary.subroutines or { }
2816 charset = dictionary.charset
2817 vsindex = dictionary.vsindex or 0
2818
2819 local glyphs = glphs or { }
2820
2821 if nobias then
2822 globalbias = 0
2823 localbias = 0
2824 else
2825 globalbias = getbias(globals)
2826 localbias = getbias(locals)
2827 end
2828
2829 nominalwidth, defaultwidth = setwidths(dictionary.private)
2830
2831 if charstrings then
2832 startparsing(fontdata,data,streams)
2833 for index=1,#charstrings do
2834 processshape(glyphs,charstrings[index],index-1)
2835 end
2836 if justpass and next(seacs) then
2837
2838 local charset = data.dictionaries[1].charset
2839 if charset then
2840 local lookup = table.swapped(charset)
2841 for index, v in next, seacs do
2842 local bindex = lookup[standardnames[v.base]]
2843 local aindex = lookup[standardnames[v.accent]]
2844 local bglyph = bindex and glyphs[bindex]
2845 local aglyph = aindex and glyphs[aindex]
2846 if bglyph and aglyph then
2847
2848 local jp = justpass
2849 justpass = false
2850 local x, y = processshape(glyphs,charstrings[bindex+1],bindex,true)
2851 justpass = jp
2852
2853 local base = bglyph.stream
2854 local accent = aglyph.stream
2855 local moveto = encode[-x-v.asb+v.adx] .. chars[22]
2856 .. encode[-y +v.ady] .. chars[04]
2857
2858 base = sub(base,1,#base-1)
2859
2860 glyphs[index].stream = base .. moveto .. accent
2861 end
2862 end
2863 end
2864 end
2865 stopparsing(fontdata,data)
2866 else
2867 report("no charstrings")
2868 end
2869 return glyphs
2870 end
2871
2872 parsecharstring = function(fontdata,data,dictionary,tab,glphs,index,doshapes,tversion,streams)
2873
2874 keepcurve = doshapes
2875 version = tversion
2876 strings = data.strings
2877 globals = data.routines or { }
2878 locals = dictionary.subroutines or { }
2879 typeone = false
2880 charset = false
2881 vsindex = dictionary.vsindex or 0
2882
2883 local glyphs = glphs or { }
2884
2885 justpass = streams == true
2886 seacs = { }
2887
2888 if nobias then
2889 globalbias = 0
2890 localbias = 0
2891 else
2892 globalbias = getbias(globals)
2893 localbias = getbias(locals)
2894 end
2895
2896 nominalwidth, defaultwidth = setwidths(dictionary.private)
2897
2898 processshape(glyphs,tab,index-1)
2899
2900 return glyphs[index]
2901 end
2902
2903end
2904
2905do
2906
2907 local function readglobals(f,data,version)
2908 local routines = readlengths(f,version == "cff2")
2909 for i=1,#routines do
2910 routines[i] = readbytetable(f,routines[i])
2911 end
2912 data.routines = routines
2913 end
2914
2915 local function readencodings(f,data)
2916 data.encodings = { }
2917 end
2918
2919 local function readcharsets(f,data,dictionary)
2920 local header = data.header
2921 local strings = data.strings
2922 local nofglyphs = data.nofglyphs
2923 local charsetoffset = dictionary.charset
2924 if charsetoffset and charsetoffset ~= 0 then
2925 setposition(f,header.offset+charsetoffset)
2926 local format = readbyte(f)
2927 local charset = { [0] = ".notdef" }
2928 dictionary.charset = charset
2929 if format == 0 then
2930 for i=1,nofglyphs do
2931 charset[i] = strings[readushort(f)]
2932 end
2933 elseif format == 1 or format == 2 then
2934 local readcount = format == 1 and readbyte or readushort
2935 local i = 1
2936 while i <= nofglyphs do
2937 local sid = readushort(f)
2938 local n = readcount(f)
2939 for s=sid,sid+n do
2940 charset[i] = strings[s]
2941 i = i + 1
2942 if i > nofglyphs then
2943 break
2944 end
2945 end
2946 end
2947 else
2948 report("cff parser: unsupported charset format %a",format)
2949 end
2950 else
2951 dictionary.nocharset = true
2952 dictionary.charset = nil
2953 end
2954 end
2955
2956 local function readprivates(f,data)
2957 local header = data.header
2958 local dictionaries = data.dictionaries
2959 local private = dictionaries[1].private
2960 if private then
2961 setposition(f,header.offset+private.offset)
2962 private.data = readstring(f,private.size)
2963 end
2964 end
2965
2966 local function readlocals(f,data,dictionary,cff2)
2967 local header = data.header
2968 local private = dictionary.private
2969 if private then
2970 local subroutineoffset = private.data.subroutines
2971 if subroutineoffset ~= 0 then
2972 setposition(f,header.offset+private.offset+subroutineoffset)
2973 local subroutines = readlengths(f,version == "cff2")
2974 for i=1,#subroutines do
2975 subroutines[i] = readbytetable(f,subroutines[i])
2976 end
2977 dictionary.subroutines = subroutines
2978 private.data.subroutines = nil
2979 else
2980 dictionary.subroutines = { }
2981 end
2982 else
2983 dictionary.subroutines = { }
2984 end
2985 end
2986
2987
2988
2989
2990 local function readcharstrings(f,data,version)
2991 local header = data.header
2992 local dictionaries = data.dictionaries
2993 local dictionary = dictionaries[1]
2994 local stringtype = dictionary.charstringtype
2995 local offset = dictionary.charstrings
2996 if type(offset) ~= "number" then
2997
2998 elseif stringtype == 2 then
2999 setposition(f,header.offset+offset)
3000
3001 local charstrings = readlengths(f,version=="cff2")
3002 local nofglyphs = #charstrings
3003 for i=1,nofglyphs do
3004 charstrings[i] = readstring(f,charstrings[i])
3005 end
3006 data.nofglyphs = nofglyphs
3007 dictionary.charstrings = charstrings
3008 else
3009 report("unsupported charstr type %i",stringtype)
3010 data.nofglyphs = 0
3011 dictionary.charstrings = { }
3012 end
3013 end
3014
3015
3016
3017 local function readcidprivates(f,data)
3018 local header = data.header
3019 local dictionaries = data.dictionaries[1].cid.dictionaries
3020 for i=1,#dictionaries do
3021 local dictionary = dictionaries[i]
3022 local private = dictionary.private
3023 if private then
3024 setposition(f,header.offset+private.offset)
3025 private.data = readstring(f,private.size)
3026 end
3027 end
3028 parseprivates(data,dictionaries)
3029 end
3030
3031 readers.parsecharstrings = parsecharstrings
3032
3033 local function readnoselect(f,fontdata,data,glyphs,doshapes,version,streams)
3034 local dictionaries = data.dictionaries
3035 local dictionary = dictionaries[1]
3036 local cid = not dictionary.private and dictionary.cid
3037 readglobals(f,data,version)
3038 readcharstrings(f,data,version)
3039 if version == "cff2" then
3040 dictionary.charset = nil
3041 else
3042 readencodings(f,data)
3043 readcharsets(f,data,dictionary)
3044 end
3045 if cid then
3046 local fdarray = cid.fdarray
3047 if fdarray then
3048 setposition(f,data.header.offset + fdarray)
3049 local dictionaries = readlengths(f,version=="cff2")
3050 local nofdictionaries = #dictionaries
3051 if nofdictionaries > 0 then
3052 for i=1,nofdictionaries do
3053 dictionaries[i] = readstring(f,dictionaries[i])
3054 end
3055 parsedictionaries(data,dictionaries)
3056 dictionary.private = dictionaries[1].private
3057 if nofdictionaries > 1 then
3058 report("ignoring dictionaries > 1 in cid font")
3059 end
3060 end
3061 end
3062 end
3063 readprivates(f,data)
3064 parseprivates(data,data.dictionaries)
3065 readlocals(f,data,dictionary,version)
3066 startparsing(fontdata,data,streams)
3067 parsecharstrings(fontdata,data,glyphs,doshapes,version,streams,false)
3068 stopparsing(fontdata,data)
3069 end
3070
3071 local function readfdselect(f,fontdata,data,glyphs,doshapes,version,streams)
3072 local header = data.header
3073 local dictionaries = data.dictionaries
3074 local dictionary = dictionaries[1]
3075 local cid = dictionary.cid
3076 local cidselect = cid and cid.fdselect
3077 readglobals(f,data,version)
3078 readcharstrings(f,data,version)
3079 if version ~= "cff2" then
3080 readencodings(f,data)
3081 end
3082 local charstrings = dictionary.charstrings
3083 local fdindex = { }
3084 local nofglyphs = data.nofglyphs
3085 local maxindex = -1
3086 setposition(f,header.offset+cidselect)
3087 local format = readbyte(f)
3088 if format == 1 then
3089 for i=0,nofglyphs do
3090 local index = readbyte(f)
3091 fdindex[i] = index
3092 if index > maxindex then
3093 maxindex = index
3094 end
3095 end
3096 elseif format == 3 then
3097 local nofranges = readushort(f)
3098 local first = readushort(f)
3099 local index = readbyte(f)
3100 while true do
3101 local last = readushort(f)
3102 if index > maxindex then
3103 maxindex = index
3104 end
3105 for i=first,last do
3106 fdindex[i] = index
3107 end
3108 if last >= nofglyphs then
3109 break
3110 else
3111 first = last + 1
3112 index = readbyte(f)
3113 end
3114 end
3115 else
3116 report("unsupported fd index format %i",format)
3117 end
3118
3119 if maxindex >= 0 then
3120 local cidarray = cid.fdarray
3121 if cidarray then
3122 setposition(f,header.offset+cidarray)
3123 local dictionaries = readlengths(f,version == "cff2")
3124 if #dictionaries > 0 then
3125 for i=1,#dictionaries do
3126 dictionaries[i] = readstring(f,dictionaries[i])
3127 end
3128 parsedictionaries(data,dictionaries)
3129 cid.dictionaries = dictionaries
3130 readcidprivates(f,data)
3131 for i=1,#dictionaries do
3132 readlocals(f,data,dictionaries[i],version)
3133 end
3134 startparsing(fontdata,data,streams)
3135 for i=1,#charstrings do
3136 local dictionary = dictionaries[fdindex[i]+1]
3137 if dictionary then
3138 parsecharstring(fontdata,data,dictionary,charstrings[i],glyphs,i,doshapes,version,streams)
3139 else
3140
3141 end
3142
3143 end
3144 stopparsing(fontdata,data)
3145 else
3146 report("no cid dictionaries")
3147 end
3148 else
3149 report("no cid array")
3150 end
3151 end
3152 end
3153
3154 local gotodatatable = readers.helpers.gotodatatable
3155
3156 local function cleanup(data,dictionaries)
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166 end
3167
3168 function readers.cff(f,fontdata,specification)
3169 local tableoffset = gotodatatable(f,fontdata,"cff",specification.details or specification.glyphs)
3170 if tableoffset then
3171 local header = readheader(f)
3172 if header.major ~= 1 then
3173 report("only version %s is supported for table %a",1,"cff")
3174 return
3175 end
3176 local glyphs = fontdata.glyphs
3177 local names = readfontnames(f)
3178 local dictionaries = readtopdictionaries(f)
3179 local strings = readstrings(f)
3180 local data = {
3181 header = header,
3182 names = names,
3183 dictionaries = dictionaries,
3184 strings = strings,
3185 nofglyphs = fontdata.nofglyphs,
3186 }
3187
3188 parsedictionaries(data,dictionaries,"cff")
3189
3190 local dic = dictionaries[1]
3191 local cid = dic.cid
3192
3193 local cffinfo = {
3194 familyname = dic.familyname,
3195 fullname = dic.fullname,
3196 boundingbox = dic.boundingbox,
3197 weight = dic.weight,
3198 italicangle = dic.italicangle,
3199 underlineposition = dic.underlineposition,
3200 underlinethickness = dic.underlinethickness,
3201 defaultwidth = dic.defaultwidthx,
3202 nominalwidth = dic.nominalwidthx,
3203 monospaced = dic.monospaced,
3204 }
3205 fontdata.cidinfo = cid and {
3206 registry = cid.registry,
3207 ordering = cid.ordering,
3208 supplement = cid.supplement,
3209 }
3210 fontdata.cffinfo = cffinfo
3211
3212 local all = specification.shapes or specification.streams or false
3213 if specification.glyphs or all then
3214 if cid and cid.fdselect then
3215 readfdselect(f,fontdata,data,glyphs,all,"cff",specification.streams)
3216 else
3217 readnoselect(f,fontdata,data,glyphs,all,"cff",specification.streams)
3218 end
3219 end
3220 local private = dic.private
3221 if private then
3222 local data = private.data
3223 if type(data) == "table" then
3224 cffinfo.defaultwidth = data.defaultwidthx or cffinfo.defaultwidth
3225 cffinfo.nominalwidth = data.nominalwidthx or cffinfo.nominalwidth
3226 cffinfo.bluevalues = data.bluevalues
3227 cffinfo.otherblues = data.otherblues
3228 cffinfo.familyblues = data.familyblues
3229 cffinfo.familyotherblues = data.familyotherblues
3230 cffinfo.bluescale = data.bluescale
3231 cffinfo.blueshift = data.blueshift
3232 cffinfo.bluefuzz = data.bluefuzz
3233 cffinfo.stdhw = data.stdhw
3234 cffinfo.stdvw = data.stdvw
3235 cffinfo.stemsnaph = data.stemsnaph
3236 cffinfo.stemsnapv = data.stemsnapv
3237 end
3238 end
3239 cleanup(data,dictionaries)
3240 end
3241 end
3242
3243 function readers.cff2(f,fontdata,specification)
3244 local tableoffset = gotodatatable(f,fontdata,"cff2",specification.glyphs)
3245 if tableoffset then
3246 local header = readheader(f)
3247 if header.major ~= 2 then
3248 report("only version %s is supported for table %a",2,"cff2")
3249 return
3250 end
3251 local glyphs = fontdata.glyphs
3252 local dictionaries = { readstring(f,header.dsize) }
3253 local data = {
3254 header = header,
3255 dictionaries = dictionaries,
3256 nofglyphs = fontdata.nofglyphs,
3257 }
3258
3259 parsedictionaries(data,dictionaries,"cff2")
3260
3261 local offset = dictionaries[1].vstore
3262 if offset > 0 then
3263 local storeoffset = dictionaries[1].vstore + data.header.offset + 2
3264 local regions, deltas = readers.helpers.readvariationdata(f,storeoffset,factors)
3265
3266 data.regions = regions
3267 data.deltas = deltas
3268 else
3269 data.regions = { }
3270 data.deltas = { }
3271 end
3272 data.factors = specification.factors
3273
3274 local cid = data.dictionaries[1].cid
3275 local all = specification.shapes or specification.streams or false
3276 if cid and cid.fdselect then
3277 readfdselect(f,fontdata,data,glyphs,all,"cff2",specification.streams)
3278 else
3279 readnoselect(f,fontdata,data,glyphs,all,"cff2",specification.streams)
3280 end
3281 cleanup(data,dictionaries)
3282 end
3283 end
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323end
3324 |