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
38local idiv = number.idiv
39local rshift, band, extract = bit32.rshift, bit32.band, bit32.extract
40
41local readers = fonts.handlers.otf.readers
42local streamreader = readers.streamreader
43
44local readstring = streamreader.readstring
45local readbyte = streamreader.readcardinal1
46local readushort = streamreader.readcardinal2
47local readuint = streamreader.readcardinal3
48local readulong = streamreader.readcardinal4
49local setposition = streamreader.setposition
50local getposition = streamreader.getposition
51local readbytetable = streamreader.readbytetable
52
53directives.register("fonts.streamreader",function()
54
55 streamreader = utilities.streams
56
57 readstring = streamreader.readstring
58 readbyte = streamreader.readcardinal1
59 readushort = streamreader.readcardinal2
60 readuint = streamreader.readcardinal3
61 readulong = streamreader.readcardinal4
62 setposition = streamreader.setposition
63 getposition = streamreader.getposition
64 readbytetable = streamreader.readbytetable
65
66end)
67
68local setmetatableindex = table.setmetatableindex
69
70local trace_charstrings = false trackers.register("fonts.cff.charstrings",function(v) trace_charstrings = v end)
71local report = logs.reporter("otf reader","cff")
72
73local parsedictionaries
74local parsecharstring
75local parsecharstrings
76local resetcharstrings
77local parseprivates
78local startparsing
79local stopparsing
80
81local defaultstrings = { [0] =
82 ".notdef", "space", "exclam", "quotedbl", "numbersign", "dollar", "percent",
83 "ampersand", "quoteright", "parenleft", "parenright", "asterisk", "plus",
84 "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four",
85 "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less",
86 "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H",
87 "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W",
88 "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum",
89 "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
90 "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y",
91 "z", "braceleft", "bar", "braceright", "asciitilde", "exclamdown", "cent",
92 "sterling", "fraction", "yen", "florin", "section", "currency",
93 "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft",
94 "guilsinglright", "fi", "fl", "endash", "dagger", "daggerdbl",
95 "periodcentered", "paragraph", "bullet", "quotesinglbase", "quotedblbase",
96 "quotedblright", "guillemotright", "ellipsis", "perthousand", "questiondown",
97 "grave", "acute", "circumflex", "tilde", "macron", "breve", "dotaccent",
98 "dieresis", "ring", "cedilla", "hungarumlaut", "ogonek", "caron", "emdash",
99 "AE", "ordfeminine", "Lslash", "Oslash", "OE", "ordmasculine", "ae",
100 "dotlessi", "lslash", "oslash", "oe", "germandbls", "onesuperior",
101 "logicalnot", "mu", "trademark", "Eth", "onehalf", "plusminus", "Thorn",
102 "onequarter", "divide", "brokenbar", "degree", "thorn", "threequarters",
103 "twosuperior", "registered", "minus", "eth", "multiply", "threesuperior",
104 "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave", "Aring",
105 "Atilde", "Ccedilla", "Eacute", "Ecircumflex", "Edieresis", "Egrave",
106 "Iacute", "Icircumflex", "Idieresis", "Igrave", "Ntilde", "Oacute",
107 "Ocircumflex", "Odieresis", "Ograve", "Otilde", "Scaron", "Uacute",
108 "Ucircumflex", "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron",
109 "aacute", "acircumflex", "adieresis", "agrave", "aring", "atilde",
110 "ccedilla", "eacute", "ecircumflex", "edieresis", "egrave", "iacute",
111 "icircumflex", "idieresis", "igrave", "ntilde", "oacute", "ocircumflex",
112 "odieresis", "ograve", "otilde", "scaron", "uacute", "ucircumflex",
113 "udieresis", "ugrave", "yacute", "ydieresis", "zcaron", "exclamsmall",
114 "Hungarumlautsmall", "dollaroldstyle", "dollarsuperior", "ampersandsmall",
115 "Acutesmall", "parenleftsuperior", "parenrightsuperior", "twodotenleader",
116 "onedotenleader", "zerooldstyle", "oneoldstyle", "twooldstyle",
117 "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle",
118 "sevenoldstyle", "eightoldstyle", "nineoldstyle", "commasuperior",
119 "threequartersemdash", "periodsuperior", "questionsmall", "asuperior",
120 "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior",
121 "lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior",
122 "tsuperior", "ff", "ffi", "ffl", "parenleftinferior", "parenrightinferior",
123 "Circumflexsmall", "hyphensuperior", "Gravesmall", "Asmall", "Bsmall",
124 "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", "Hsmall", "Ismall",
125 "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall",
126 "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall",
127 "Xsmall", "Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah",
128 "Tildesmall", "exclamdownsmall", "centoldstyle", "Lslashsmall",
129 "Scaronsmall", "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall",
130 "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior",
131 "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall", "oneeighth",
132 "threeeighths", "fiveeighths", "seveneighths", "onethird", "twothirds",
133 "zerosuperior", "foursuperior", "fivesuperior", "sixsuperior",
134 "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior",
135 "oneinferior", "twoinferior", "threeinferior", "fourinferior",
136 "fiveinferior", "sixinferior", "seveninferior", "eightinferior",
137 "nineinferior", "centinferior", "dollarinferior", "periodinferior",
138 "commainferior", "Agravesmall", "Aacutesmall", "Acircumflexsmall",
139 "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall",
140 "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall",
141 "Igravesmall", "Iacutesmall", "Icircumflexsmall", "Idieresissmall",
142 "Ethsmall", "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall",
143 "Otildesmall", "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall",
144 "Uacutesmall", "Ucircumflexsmall", "Udieresissmall", "Yacutesmall",
145 "Thornsmall", "Ydieresissmall", "001.000", "001.001", "001.002", "001.003",
146 "Black", "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold",
147}
148
149local standardnames = { [0] =
150 false, false, false, false, false, false, false, false, false, false, false,
151 false, false, false, false, false, false, false, false, false, false, false,
152 false, false, false, false, false, false, false, false, false, false,
153 "space", "exclam", "quotedbl", "numbersign", "dollar", "percent",
154 "ampersand", "quoteright", "parenleft", "parenright", "asterisk", "plus",
155 "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four",
156 "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less",
157 "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H",
158 "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W",
159 "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum",
160 "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
161 "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y",
162 "z", "braceleft", "bar", "braceright", "asciitilde", 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, false, false,
165 false, false, false, false, false, false, false, false, false, "exclamdown",
166 "cent", "sterling", "fraction", "yen", "florin", "section", "currency",
167 "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft",
168 "guilsinglright", "fi", "fl", false, "endash", "dagger", "daggerdbl",
169 "periodcentered", false, "paragraph", "bullet", "quotesinglbase",
170 "quotedblbase", "quotedblright", "guillemotright", "ellipsis", "perthousand",
171 false, "questiondown", false, "grave", "acute", "circumflex", "tilde",
172 "macron", "breve", "dotaccent", "dieresis", false, "ring", "cedilla", false,
173 "hungarumlaut", "ogonek", "caron", "emdash", false, false, false, false,
174 false, false, false, false, false, false, false, false, false, false, false,
175 false, "AE", false, "ordfeminine", false, false, false, false, "Lslash",
176 "Oslash", "OE", "ordmasculine", false, false, false, false, false, "ae",
177 false, false, false, "dotlessi", false, false, "lslash", "oslash", "oe",
178 "germandbls", false, false, false, false
179}
180
181local cffreaders = {
182 readbyte,
183 readushort,
184 readuint,
185 readulong,
186}
187
188directives.register("fonts.streamreader",function()
189 cffreaders = {
190 readbyte,
191 readushort,
192 readuint,
193 readulong,
194 }
195end)
196
197
198
199local function readheader(f)
200 local offset = getposition(f)
201 local major = readbyte(f)
202 local header = {
203 offset = offset,
204 major = major,
205 minor = readbyte(f),
206 size = readbyte(f),
207 }
208 if major == 1 then
209 header.dsize = readbyte(f)
210 elseif major == 2 then
211 header.dsize = readushort(f)
212 else
213
214
215 end
216 setposition(f,offset+header.size)
217 return header
218end
219
220
221
222
223local function readlengths(f,longcount)
224 local count = longcount and readulong(f) or readushort(f)
225 if count == 0 then
226 return { }
227 end
228 local osize = readbyte(f)
229 local read = cffreaders[osize]
230 if not read then
231 report("bad offset size: %i",osize)
232 return { }
233 end
234 local lengths = { }
235 local previous = read(f)
236 for i=1,count do
237 local offset = read(f)
238 local length = offset - previous
239 if length < 0 then
240 report("bad offset: %i",length)
241 length = 0
242 end
243 lengths[i] = length
244 previous = offset
245 end
246 return lengths
247end
248
249
250
251
252
253
254local function readfontnames(f)
255 local names = readlengths(f)
256 for i=1,#names do
257 names[i] = readstring(f,names[i])
258 end
259 return names
260end
261
262local function readtopdictionaries(f)
263 local dictionaries = readlengths(f)
264 for i=1,#dictionaries do
265 dictionaries[i] = readstring(f,dictionaries[i])
266 end
267 return dictionaries
268end
269
270
271
272
273local function readstrings(f)
274 local lengths = readlengths(f)
275 local strings = setmetatableindex({ }, defaultstrings)
276 local index = #defaultstrings
277 for i=1,#lengths do
278 index = index + 1
279 strings[index] = readstring(f,lengths[i])
280 end
281 return strings
282end
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299do
300
301
302
303
304 local stack = { }
305 local top = 0
306 local result = { }
307 local strings = { }
308
309 local p_single =
310 P("\00") / function()
311 result.version = strings[stack[top]] or "unset"
312 top = 0
313 end
314 + P("\01") / function()
315 result.notice = strings[stack[top]] or "unset"
316 top = 0
317 end
318 + P("\02") / function()
319 result.fullname = strings[stack[top]] or "unset"
320 top = 0
321 end
322 + P("\03") / function()
323 result.familyname = strings[stack[top]] or "unset"
324 top = 0
325 end
326 + P("\04") / function()
327 result.weight = strings[stack[top]] or "unset"
328 top = 0
329 end
330 + P("\05") / function()
331 result.fontbbox = { unpack(stack,1,4) }
332 top = 0
333 end
334 + P("\06") / function()
335 result.bluevalues = { unpack(stack,1,top) }
336 top = 0
337 end
338 + P("\07") / function()
339 result.otherblues = { unpack(stack,1,top) }
340 top = 0
341 end
342 + P("\08") / function()
343 result.familyblues = { unpack(stack,1,top) }
344 top = 0
345 end
346 + P("\09") / function()
347 result.familyotherblues = { unpack(stack,1,top) }
348 top = 0
349 end
350 + P("\10") / function()
351 result.strhw = stack[top]
352 top = 0
353 end
354 + P("\11") / function()
355 result.strvw = stack[top]
356 top = 0
357 end
358 + P("\13") / function()
359 result.uniqueid = stack[top]
360 top = 0
361 end
362 + P("\14") / function()
363 result.xuid = concat(stack,"",1,top)
364 top = 0
365 end
366 + P("\15") / function()
367 result.charset = stack[top]
368 top = 0
369 end
370 + P("\16") / function()
371 result.encoding = stack[top]
372 top = 0
373 end
374 + P("\17") / function()
375 result.charstrings = stack[top]
376 top = 0
377 end
378 + P("\18") / function()
379 result.private = {
380 size = stack[top-1],
381 offset = stack[top],
382 }
383 top = 0
384 end
385 + P("\19") / function()
386 result.subroutines = stack[top]
387 top = 0
388 end
389 + P("\20") / function()
390 result.defaultwidthx = stack[top]
391 top = 0
392 end
393 + P("\21") / function()
394 result.nominalwidthx = stack[top]
395 top = 0
396 end
397
398
399
400
401 + P("\24") / function()
402 result.vstore = stack[top]
403 top = 0
404 end
405 + P("\25") / function()
406 result.maxstack = stack[top]
407 top = 0
408 end
409
410
411
412
413
414 local p_double = P("\12") * (
415 P("\00") / function()
416 result.copyright = stack[top]
417 top = 0
418 end
419 + P("\01") / function()
420 result.monospaced = stack[top] == 1 and true or false
421 top = 0
422 end
423 + P("\02") / function()
424 result.italicangle = stack[top]
425 top = 0
426 end
427 + P("\03") / function()
428 result.underlineposition = stack[top]
429 top = 0
430 end
431 + P("\04") / function()
432 result.underlinethickness = stack[top]
433 top = 0
434 end
435 + P("\05") / function()
436 result.painttype = stack[top]
437 top = 0
438 end
439 + P("\06") / function()
440 result.charstringtype = stack[top]
441 top = 0
442 end
443 + P("\07") / function()
444 result.fontmatrix = { unpack(stack,1,6) }
445 top = 0
446 end
447 + P("\08") / function()
448 result.strokewidth = stack[top]
449 top = 0
450 end
451 + P("\09") / function()
452 result.bluescale = stack[top]
453 top = 0
454 end
455 + P("\10") / function()
456 result.bluesnap = stack[top]
457 top = 0
458 end
459 + P("\11") / function()
460 result.bluefuzz = stack[top]
461 top = 0
462 end
463 + P("\12") / function()
464 result.stemsnaph = { unpack(stack,1,top) }
465 top = 0
466 end
467 + P("\13") / function()
468 result.stemsnapv = { unpack(stack,1,top) }
469 top = 0
470 end
471 + P("\20") / function()
472 result.syntheticbase = stack[top]
473 top = 0
474 end
475 + P("\21") / function()
476 result.postscript = strings[stack[top]] or "unset"
477 top = 0
478 end
479 + P("\22") / function()
480 result.basefontname = strings[stack[top]] or "unset"
481 top = 0
482 end
483 + P("\21") / function()
484 result.basefontblend = stack[top]
485 top = 0
486 end
487 + P("\30") / function()
488 result.cid.registry = strings[stack[top-2]] or "unset"
489 result.cid.ordering = strings[stack[top-1]] or "unset"
490 result.cid.supplement = stack[top]
491 top = 0
492 end
493 + P("\31") / function()
494 result.cid.fontversion = stack[top]
495 top = 0
496 end
497 + P("\32") / function()
498 result.cid.fontrevision= stack[top]
499 top = 0
500 end
501 + P("\33") / function()
502 result.cid.fonttype = stack[top]
503 top = 0
504 end
505 + P("\34") / function()
506 result.cid.count = stack[top]
507 top = 0
508 end
509 + P("\35") / function()
510 result.cid.uidbase = stack[top]
511 top = 0
512 end
513 + P("\36") / function()
514 result.cid.fdarray = stack[top]
515 top = 0
516 end
517 + P("\37") / function()
518 result.cid.fdselect = stack[top]
519 top = 0
520 end
521 + P("\38") / function()
522 result.cid.fontname = strings[stack[top]] or "unset"
523 top = 0
524 end
525 )
526
527
528
529
530
531 local remap = {
532 ["\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",
533 ["\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",
534 ["\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",
535 ["\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",
536 ["\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",
537 ["\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",
538 ["\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",
539 ["\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",
540 ["\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",
541 ["\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",
542 ["\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"] = ".",
543 ["\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",
544 ["\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-",
545 ["\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"] = "-",
546 }
547
548 local p_last = S("\x0F\x1F\x2F\x3F\x4F\x5F\x6F\x7F\x8F\x9F\xAF\xBF")
549 + R("\xF0\xFF")
550
551 local p_nibbles = P("\30") * Cs(((1-p_last)/remap)^0 * (P(1)/remap)) / function(n)
552
553 top = top + 1
554 stack[top] = tonumber(n) or 0
555 end
556
557 local p_byte = C(R("\32\246")) / function(b0)
558
559 top = top + 1
560 stack[top] = byte(b0) - 139
561 end
562
563 local p_positive = C(R("\247\250")) * C(1) / function(b0,b1)
564
565 top = top + 1
566 stack[top] = (byte(b0)-247)*256 + byte(b1) + 108
567 end
568
569 local p_negative = C(R("\251\254")) * C(1) / function(b0,b1)
570
571 top = top + 1
572 stack[top] = -(byte(b0)-251)*256 - byte(b1) - 108
573 end
574
575
576
577
578
579
580 local p_short = P("\28") * C(1) * C(1) / function(b1,b2)
581
582 top = top + 1
583 local n = 0x100 * byte(b1) + byte(b2)
584 if n >= 0x8000 then
585 stack[top] = n - 0xFFFF - 1
586 else
587 stack[top] = n
588 end
589 end
590
591 local p_long = P("\29") * C(1) * C(1) * C(1) * C(1) / function(b1,b2,b3,b4)
592
593 top = top + 1
594 local n = 0x1000000 * byte(b1) + 0x10000 * byte(b2) + 0x100 * byte(b3) + byte(b4)
595 if n >= 0x8000000 then
596 stack[top] = n - 0xFFFFFFFF - 1
597 else
598 stack[top] = n
599 end
600 end
601
602 local p_unsupported = P(1) / function(detail)
603 top = 0
604 end
605
606 local p_dictionary = (
607 p_byte
608 + p_positive
609 + p_negative
610 + p_short
611 + p_long
612 + p_nibbles
613 + p_single
614 + p_double
615
616 + p_unsupported
617 )^1
618
619 parsedictionaries = function(data,dictionaries,version)
620 stack = { }
621 strings = data.strings
622 if trace_charstrings then
623 report("charstring format %a",version)
624 end
625 for i=1,#dictionaries do
626 top = 0
627 result = version == "cff" and {
628 monospaced = false,
629 italicangle = 0,
630 underlineposition = -100,
631 underlinethickness = 50,
632 painttype = 0,
633 charstringtype = 2,
634 fontmatrix = { 0.001, 0, 0, 0.001, 0, 0 },
635 fontbbox = { 0, 0, 0, 0 },
636 strokewidth = 0,
637 charset = 0,
638 encoding = 0,
639 cid = {
640 fontversion = 0,
641 fontrevision = 0,
642 fonttype = 0,
643 count = 8720,
644 }
645 } or {
646 charstringtype = 2,
647 charset = 0,
648 vstore = 0,
649 cid = {
650
651 },
652 }
653 lpegmatch(p_dictionary,dictionaries[i])
654 dictionaries[i] = result
655 end
656
657 result = { }
658 top = 0
659 stack = { }
660 end
661
662 parseprivates = function(data,dictionaries)
663 stack = { }
664 strings = data.strings
665 for i=1,#dictionaries do
666 local private = dictionaries[i].private
667 if private and private.data then
668 top = 0
669 result = {
670 forcebold = false,
671 languagegroup = 0,
672 expansionfactor = 0.06,
673 initialrandomseed = 0,
674 subroutines = 0,
675 defaultwidthx = 0,
676 nominalwidthx = 0,
677 cid = {
678
679 },
680 }
681 lpegmatch(p_dictionary,private.data)
682 private.data = result
683 end
684 end
685 result = { }
686 top = 0
687 stack = { }
688 end
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706 local x = 0
707 local y = 0
708 local width = false
709 local lsb = 0
710local result = { }
711 local r = 0
712 local stems = 0
713 local globalbias = 0
714 local localbias = 0
715 local nominalwidth = 0
716 local defaultwidth = 0
717 local charset = false
718 local globals = false
719 local locals = false
720 local depth = 1
721 local xmin = 0
722 local xmax = 0
723 local ymin = 0
724 local ymax = 0
725 local checked = false
726 local keepcurve = false
727 local version = 2
728 local regions = false
729 local nofregions = 0
730 local region = false
731 local factors = false
732 local axis = false
733 local vsindex = 0
734 local justpass = false
735 local seacs = { }
736 local procidx = nil
737
738 local function showstate(where)
739 report("%w%-10s : [%s] n=%i",depth*2,where,concat(stack," ",1,top),top)
740 end
741
742 local function showvalue(where,value,showstack)
743 if showstack then
744 report("%w%-10s : %s : [%s] n=%i",depth*2,where,tostring(value),concat(stack," ",1,top),top)
745 else
746 report("%w%-10s : %s",depth*2,where,tostring(value))
747 end
748 end
749
750
751
752
753
754
755
756
757
758
759
760
761
762 local function xymoveto()
763 if keepcurve then
764 r = r + 1
765 result[r] = { x, y, "m" }
766 end
767 if checked then
768 if x > xmax then xmax = x elseif x < xmin then xmin = x end
769 if y > ymax then ymax = y elseif y < ymin then ymin = y end
770 else
771 xmin = x
772 ymin = y
773 xmax = x
774 ymax = y
775 checked = true
776 end
777 end
778
779 local function xmoveto()
780 if keepcurve then
781 r = r + 1
782 result[r] = { x, y, "m" }
783 end
784 if not checked then
785 xmin = x
786 ymin = y
787 xmax = x
788 ymax = y
789 checked = true
790 elseif x > xmax then
791 xmax = x
792 elseif x < xmin then
793 xmin = x
794 end
795 end
796
797 local function ymoveto()
798 if keepcurve then
799 r = r + 1
800 result[r] = { x, y, "m" }
801 end
802 if not checked then
803 xmin = x
804 ymin = y
805 xmax = x
806 ymax = y
807 checked = true
808 elseif y > ymax then
809 ymax = y
810 elseif y < ymin then
811 ymin = y
812 end
813 end
814
815 local function moveto()
816 if trace_charstrings then
817 showstate("moveto")
818 end
819 top = 0
820 xymoveto()
821 end
822
823 local function xylineto()
824 if keepcurve then
825 r = r + 1
826 result[r] = { x, y, "l" }
827 end
828 if checked then
829 if x > xmax then xmax = x elseif x < xmin then xmin = x end
830 if y > ymax then ymax = y elseif y < ymin then ymin = y end
831 else
832 xmin = x
833 ymin = y
834 xmax = x
835 ymax = y
836 checked = true
837 end
838 end
839
840 local function xlineto()
841 if keepcurve then
842 r = r + 1
843 result[r] = { x, y, "l" }
844 end
845 if not checked then
846 xmin = x
847 ymin = y
848 xmax = x
849 ymax = y
850 checked = true
851 elseif x > xmax then
852 xmax = x
853 elseif x < xmin then
854 xmin = x
855 end
856 end
857
858 local function ylineto()
859 if keepcurve then
860 r = r + 1
861 result[r] = { x, y, "l" }
862 end
863 if not checked then
864 xmin = x
865 ymin = y
866 xmax = x
867 ymax = y
868 checked = true
869 elseif y > ymax then
870 ymax = y
871 elseif y < ymin then
872 ymin = y
873 end
874 end
875
876 local function xycurveto(x1,y1,x2,y2,x3,y3)
877 if trace_charstrings then
878 showstate("curveto")
879 end
880 if keepcurve then
881 r = r + 1
882 result[r] = { x1, y1, x2, y2, x3, y3, "c" }
883 end
884 if checked then
885 if x1 > xmax then xmax = x1 elseif x1 < xmin then xmin = x1 end
886 if y1 > ymax then ymax = y1 elseif y1 < ymin then ymin = y1 end
887 else
888 xmin = x1
889 ymin = y1
890 xmax = x1
891 ymax = y1
892 checked = true
893 end
894 if x2 > xmax then xmax = x2 elseif x2 < xmin then xmin = x2 end
895 if y2 > ymax then ymax = y2 elseif y2 < ymin then ymin = y2 end
896 if x3 > xmax then xmax = x3 elseif x3 < xmin then xmin = x3 end
897 if y3 > ymax then ymax = y3 elseif y3 < ymin then ymin = y3 end
898 end
899
900 local function rmoveto()
901 if not width then
902 if top > 2 then
903 width = stack[1]
904 if trace_charstrings then
905 showvalue("backtrack width",width)
906 end
907 else
908 width = true
909 end
910 end
911 if trace_charstrings then
912 showstate("rmoveto")
913 end
914 x = x + stack[top-1]
915 y = y + stack[top]
916 top = 0
917 xymoveto()
918 end
919
920 local function hmoveto()
921 if not width then
922 if top > 1 then
923 width = stack[1]
924 if trace_charstrings then
925 showvalue("backtrack width",width)
926 end
927 else
928 width = true
929 end
930 end
931 if trace_charstrings then
932 showstate("hmoveto")
933 end
934 x = x + stack[top]
935 top = 0
936 xmoveto()
937 end
938
939 local function vmoveto()
940 if not width then
941 if top > 1 then
942 width = stack[1]
943 if trace_charstrings then
944 showvalue("backtrack width",width)
945 end
946 else
947 width = true
948 end
949 end
950 if trace_charstrings then
951 showstate("vmoveto")
952 end
953 y = y + stack[top]
954 top = 0
955 ymoveto()
956 end
957
958 local function rlineto()
959 if trace_charstrings then
960 showstate("rlineto")
961 end
962 for i=1,top,2 do
963 x = x + stack[i]
964 y = y + stack[i+1]
965 xylineto()
966 end
967 top = 0
968 end
969
970 local function hlineto()
971 if trace_charstrings then
972 showstate("hlineto")
973 end
974 if top == 1 then
975 x = x + stack[1]
976 xlineto()
977 else
978 local swap = true
979 for i=1,top do
980 if swap then
981 x = x + stack[i]
982 xlineto()
983 swap = false
984 else
985 y = y + stack[i]
986 ylineto()
987 swap = true
988 end
989 end
990 end
991 top = 0
992 end
993
994 local function vlineto()
995 if trace_charstrings then
996 showstate("vlineto")
997 end
998 if top == 1 then
999 y = y + stack[1]
1000 ylineto()
1001 else
1002 local swap = false
1003 for i=1,top do
1004 if swap then
1005 x = x + stack[i]
1006 xlineto()
1007 swap = false
1008 else
1009 y = y + stack[i]
1010 ylineto()
1011 swap = true
1012 end
1013 end
1014 end
1015 top = 0
1016 end
1017
1018 local function rrcurveto()
1019 if trace_charstrings then
1020 showstate("rrcurveto")
1021 end
1022 for i=1,top,6 do
1023 local ax = x + stack[i]
1024 local ay = y + stack[i+1]
1025 local bx = ax + stack[i+2]
1026 local by = ay + stack[i+3]
1027 x = bx + stack[i+4]
1028 y = by + stack[i+5]
1029 xycurveto(ax,ay,bx,by,x,y)
1030 end
1031 top = 0
1032 end
1033
1034 local function hhcurveto()
1035 if trace_charstrings then
1036 showstate("hhcurveto")
1037 end
1038 local s = 1
1039 if top % 2 ~= 0 then
1040 y = y + stack[1]
1041 s = 2
1042 end
1043 for i=s,top,4 do
1044 local ax = x + stack[i]
1045 local ay = y
1046 local bx = ax + stack[i+1]
1047 local by = ay + stack[i+2]
1048 x = bx + stack[i+3]
1049 y = by
1050 xycurveto(ax,ay,bx,by,x,y)
1051 end
1052 top = 0
1053 end
1054
1055 local function vvcurveto()
1056 if trace_charstrings then
1057 showstate("vvcurveto")
1058 end
1059 local s = 1
1060 local d = 0
1061 if top % 2 ~= 0 then
1062 d = stack[1]
1063 s = 2
1064 end
1065 for i=s,top,4 do
1066 local ax = x + d
1067 local ay = y + stack[i]
1068 local bx = ax + stack[i+1]
1069 local by = ay + stack[i+2]
1070 x = bx
1071 y = by + stack[i+3]
1072 xycurveto(ax,ay,bx,by,x,y)
1073 d = 0
1074 end
1075 top = 0
1076 end
1077
1078 local function xxcurveto(swap)
1079 local last = top % 4 ~= 0 and stack[top]
1080 if last then
1081 top = top - 1
1082 end
1083 for i=1,top,4 do
1084 local ax, ay, bx, by
1085 if swap then
1086 ax = x + stack[i]
1087 ay = y
1088 bx = ax + stack[i+1]
1089 by = ay + stack[i+2]
1090 y = by + stack[i+3]
1091 if last and i+3 == top then
1092 x = bx + last
1093 else
1094 x = bx
1095 end
1096 swap = false
1097 else
1098 ax = x
1099 ay = y + stack[i]
1100 bx = ax + stack[i+1]
1101 by = ay + stack[i+2]
1102 x = bx + stack[i+3]
1103 if last and i+3 == top then
1104 y = by + last
1105 else
1106 y = by
1107 end
1108 swap = true
1109 end
1110 xycurveto(ax,ay,bx,by,x,y)
1111 end
1112 top = 0
1113 end
1114
1115 local function hvcurveto()
1116 if trace_charstrings then
1117 showstate("hvcurveto")
1118 end
1119 xxcurveto(true)
1120 end
1121
1122 local function vhcurveto()
1123 if trace_charstrings then
1124 showstate("vhcurveto")
1125 end
1126 xxcurveto(false)
1127 end
1128
1129 local function rcurveline()
1130 if trace_charstrings then
1131 showstate("rcurveline")
1132 end
1133 for i=1,top-2,6 do
1134 local ax = x + stack[i]
1135 local ay = y + stack[i+1]
1136 local bx = ax + stack[i+2]
1137 local by = ay + stack[i+3]
1138 x = bx + stack[i+4]
1139 y = by + stack[i+5]
1140 xycurveto(ax,ay,bx,by,x,y)
1141 end
1142 x = x + stack[top-1]
1143 y = y + stack[top]
1144 xylineto()
1145 top = 0
1146 end
1147
1148 local function rlinecurve()
1149 if trace_charstrings then
1150 showstate("rlinecurve")
1151 end
1152 if top > 6 then
1153 for i=1,top-6,2 do
1154 x = x + stack[i]
1155 y = y + stack[i+1]
1156 xylineto()
1157 end
1158 end
1159 local ax = x + stack[top-5]
1160 local ay = y + stack[top-4]
1161 local bx = ax + stack[top-3]
1162 local by = ay + stack[top-2]
1163 x = bx + stack[top-1]
1164 y = by + stack[top]
1165 xycurveto(ax,ay,bx,by,x,y)
1166 top = 0
1167 end
1168
1169
1170
1171 local function flex()
1172 if trace_charstrings then
1173 showstate("flex")
1174 end
1175 local ax = x + stack[1]
1176 local ay = y + stack[2]
1177 local bx = ax + stack[3]
1178 local by = ay + stack[4]
1179 local cx = bx + stack[5]
1180 local cy = by + stack[6]
1181 xycurveto(ax,ay,bx,by,cx,cy)
1182 local dx = cx + stack[7]
1183 local dy = cy + stack[8]
1184 local ex = dx + stack[9]
1185 local ey = dy + stack[10]
1186 x = ex + stack[11]
1187 y = ey + stack[12]
1188 xycurveto(dx,dy,ex,ey,x,y)
1189 top = 0
1190 end
1191
1192 local function hflex()
1193 if trace_charstrings then
1194 showstate("hflex")
1195 end
1196 local ax = x + stack[1]
1197 local ay = y
1198 local bx = ax + stack[2]
1199 local by = ay + stack[3]
1200 local cx = bx + stack[4]
1201 local cy = by
1202 xycurveto(ax,ay,bx,by,cx,cy)
1203 local dx = cx + stack[5]
1204 local dy = by
1205 local ex = dx + stack[6]
1206 local ey = y
1207 x = ex + stack[7]
1208 xycurveto(dx,dy,ex,ey,x,y)
1209 top = 0
1210 end
1211
1212 local function hflex1()
1213 if trace_charstrings then
1214 showstate("hflex1")
1215 end
1216 local ax = x + stack[1]
1217 local ay = y + stack[2]
1218 local bx = ax + stack[3]
1219 local by = ay + stack[4]
1220 local cx = bx + stack[5]
1221 local cy = by
1222 xycurveto(ax,ay,bx,by,cx,cy)
1223 local dx = cx + stack[6]
1224 local dy = by
1225 local ex = dx + stack[7]
1226 local ey = dy + stack[8]
1227 x = ex + stack[9]
1228 xycurveto(dx,dy,ex,ey,x,y)
1229 top = 0
1230 end
1231
1232 local function flex1()
1233 if trace_charstrings then
1234 showstate("flex1")
1235 end
1236 local ax = x + stack[1]
1237 local ay = y + stack[2]
1238 local bx = ax + stack[3]
1239 local by = ay + stack[4]
1240 local cx = bx + stack[5]
1241 local cy = by + stack[6]
1242 xycurveto(ax,ay,bx,by,cx,cy)
1243 local dx = cx + stack[7]
1244 local dy = cy + stack[8]
1245 local ex = dx + stack[9]
1246 local ey = dy + stack[10]
1247 if abs(ex - x) > abs(ey - y) then
1248 x = ex + stack[11]
1249 else
1250 y = ey + stack[11]
1251 end
1252 xycurveto(dx,dy,ex,ey,x,y)
1253 top = 0
1254 end
1255
1256 local function getstem()
1257 if top == 0 then
1258
1259 elseif top % 2 ~= 0 then
1260 if width then
1261 remove(stack,1)
1262 else
1263 width = remove(stack,1)
1264 if trace_charstrings then
1265 showvalue("width",width)
1266 end
1267 end
1268 top = top - 1
1269 end
1270 if trace_charstrings then
1271 showstate("stem")
1272 end
1273 stems = stems + idiv(top,2)
1274 top = 0
1275 end
1276
1277 local function getmask()
1278 if top == 0 then
1279
1280 elseif top % 2 ~= 0 then
1281 if width then
1282 remove(stack,1)
1283 else
1284 width = remove(stack,1)
1285 if trace_charstrings then
1286 showvalue("width",width)
1287 end
1288 end
1289 top = top - 1
1290 end
1291 if trace_charstrings then
1292 showstate(operator == 19 and "hintmark" or "cntrmask")
1293 end
1294 stems = stems + idiv(top,2)
1295 top = 0
1296 if stems == 0 then
1297
1298 elseif stems <= 8 then
1299 return 1
1300 else
1301
1302 return idiv(stems+7,8)
1303 end
1304 end
1305
1306 local function unsupported(t)
1307 if trace_charstrings then
1308 showstate("unsupported " .. t)
1309 end
1310 top = 0
1311 end
1312
1313 local function unsupportedsub(t)
1314 if trace_charstrings then
1315 showstate("unsupported sub " .. t)
1316 end
1317 top = 0
1318 end
1319
1320
1321
1322 local function getstem3()
1323 if trace_charstrings then
1324 showstate("stem3")
1325 end
1326 top = 0
1327 end
1328
1329 local function divide()
1330 if version == "cff" then
1331 local d = stack[top]
1332 top = top - 1
1333 stack[top] = stack[top] / d
1334 end
1335 end
1336
1337 local function closepath()
1338 if version == "cff" then
1339 if trace_charstrings then
1340 showstate("closepath")
1341 end
1342 end
1343 top = 0
1344 end
1345
1346 local function hsbw()
1347 if version == "cff" then
1348 if trace_charstrings then
1349 showstate("hsbw")
1350 end
1351 lsb = stack[top-1] or 0
1352 width = stack[top]
1353 end
1354 top = 0
1355 end
1356
1357 local function sbw()
1358 if version == "cff" then
1359 if trace_charstrings then
1360 showstate("sbw")
1361 end
1362 lsb = stack[top-3]
1363 width = stack[top-1]
1364 end
1365 top = 0
1366 end
1367
1368
1369
1370 local function seac()
1371 if version == "cff" then
1372 if trace_charstrings then
1373 showstate("seac")
1374 end
1375 end
1376 top = 0
1377 end
1378
1379
1380
1381
1382
1383
1384 local popped = 3
1385 local hints = 3
1386
1387
1388
1389 local function callothersubr()
1390 if version == "cff" then
1391 if trace_charstrings then
1392 showstate("callothersubr")
1393 end
1394 if stack[top] == hints then
1395 popped = stack[top-2]
1396 else
1397 popped = 3
1398 end
1399 local t = stack[top-1]
1400 if t then
1401 top = top - (t + 2)
1402 if top < 0 then
1403 top = 0
1404 end
1405 else
1406 top = 0
1407 end
1408 else
1409 top = 0
1410 end
1411 end
1412
1413
1414
1415 local function pop()
1416 if version == "cff" then
1417 if trace_charstrings then
1418 showstate("pop")
1419 end
1420 top = top + 1
1421 stack[top] = popped
1422 else
1423 top = 0
1424 end
1425 end
1426
1427 local function setcurrentpoint()
1428 if version == "cff" then
1429 if trace_charstrings then
1430 showstate("setcurrentpoint (unsupported)")
1431 end
1432 x = x + stack[top-1]
1433 y = y + stack[top]
1434 end
1435 top = 0
1436 end
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446 local reginit = false
1447
1448 local function updateregions(n)
1449 if regions then
1450 local current = regions[n+1] or regions[1]
1451 nofregions = #current
1452 if axis and n ~= reginit then
1453 factors = { }
1454 for i=1,nofregions do
1455 local region = current[i]
1456 local s = 1
1457 for j=1,#axis do
1458 local f = axis[j]
1459 local r = region[j]
1460 local start = r.start
1461 local peak = r.peak
1462 local stop = r.stop
1463 if start > peak or peak > stop then
1464
1465 elseif start < 0 and stop > 0 and peak ~= 0 then
1466
1467 elseif peak == 0 then
1468
1469 elseif f < start or f > stop then
1470
1471 s = 0
1472 break
1473 elseif f < peak then
1474 s = s * (f - start) / (peak - start)
1475 elseif f > peak then
1476 s = s * (stop - f) / (stop - peak)
1477 else
1478
1479 end
1480 end
1481 factors[i] = s
1482 end
1483 end
1484 end
1485 reginit = n
1486 end
1487
1488 local function setvsindex()
1489 local vsindex = stack[top]
1490 if trace_charstrings then
1491 showstate(formatters["vsindex %i"](vsindex))
1492 end
1493 updateregions(vsindex)
1494 top = top - 1
1495 end
1496
1497 local function blend()
1498 local n = stack[top]
1499 top = top - 1
1500 if axis then
1501
1502
1503 if trace_charstrings then
1504 local t = top - nofregions * n
1505 local m = t - n
1506 for i=1,n do
1507 local k = m + i
1508 local d = m + n + (i-1)*nofregions
1509 local old = stack[k]
1510 local new = old
1511 for r=1,nofregions do
1512 new = new + stack[d+r] * factors[r]
1513 end
1514 stack[k] = new
1515 showstate(formatters["blend %i of %i: %s -> %s"](i,n,old,new))
1516 end
1517 top = t
1518 elseif n == 1 then
1519 top = top - nofregions
1520 local v = stack[top]
1521 for r=1,nofregions do
1522 v = v + stack[top+r] * factors[r]
1523 end
1524 stack[top] = v
1525 else
1526 top = top - nofregions * n
1527 local d = top
1528 local k = top - n
1529 for i=1,n do
1530 k = k + 1
1531 local v = stack[k]
1532 for r=1,nofregions do
1533 v = v + stack[d+r] * factors[r]
1534 end
1535 stack[k] = v
1536 d = d + nofregions
1537 end
1538 end
1539 else
1540 top = top - nofregions * n
1541 end
1542 end
1543
1544
1545
1546
1547 local actions = { [0] =
1548 unsupported,
1549 getstem,
1550 unsupported,
1551 getstem,
1552 vmoveto,
1553 rlineto,
1554 hlineto,
1555 vlineto,
1556 rrcurveto,
1557 unsupported,
1558 unsupported,
1559 unsupported,
1560 unsupported,
1561 hsbw,
1562 unsupported,
1563 setvsindex,
1564 blend,
1565 unsupported,
1566 getstem,
1567 getmask,
1568 getmask,
1569 rmoveto,
1570 hmoveto,
1571 getstem,
1572 rcurveline,
1573 rlinecurve,
1574 vvcurveto,
1575 hhcurveto,
1576 unsupported,
1577 unsupported,
1578 vhcurveto,
1579 hvcurveto,
1580 }
1581
1582 local reverse = { [0] =
1583 "unsupported",
1584 "getstem",
1585 "unsupported",
1586 "getstem",
1587 "vmoveto",
1588 "rlineto",
1589 "hlineto",
1590 "vlineto",
1591 "rrcurveto",
1592 "unsupported",
1593 "unsupported",
1594 "unsupported",
1595 "unsupported",
1596 "hsbw",
1597 "unsupported",
1598 "setvsindex",
1599 "blend",
1600 "unsupported",
1601 "getstem",
1602 "getmask",
1603 "getmask",
1604 "rmoveto",
1605 "hmoveto",
1606 "getstem",
1607 "rcurveline",
1608 "rlinecurve",
1609 "vvcurveto",
1610 "hhcurveto",
1611 "unsupported",
1612 "unsupported",
1613 "vhcurveto",
1614 "hvcurveto",
1615 }
1616
1617 local subactions = {
1618
1619 [000] = dotsection,
1620 [001] = getstem3,
1621 [002] = getstem3,
1622 [006] = seac,
1623 [007] = sbw,
1624 [012] = divide,
1625 [016] = callothersubr,
1626 [017] = pop,
1627 [033] = setcurrentpoint,
1628
1629 [034] = hflex,
1630 [035] = flex,
1631 [036] = hflex1,
1632 [037] = flex1,
1633 }
1634
1635 local chars = setmetatableindex(function (t,k)
1636 local v = char(k)
1637 t[k] = v
1638 return v
1639 end)
1640
1641 local c_endchar = chars[14]
1642
1643
1644
1645 local encode = { }
1646
1647
1648
1649 setmetatableindex(encode,function(t,i)
1650 for i=-2048,-1130 do
1651 t[i] = char(28,band(rshift(i,8),0xFF),band(i,0xFF))
1652 end
1653 for i=-1131,-108 do
1654 local v = 0xFB00 - i - 108
1655 t[i] = char(band(rshift(v,8),0xFF),band(v,0xFF))
1656 end
1657 for i=-107,107 do
1658 t[i] = chars[i + 139]
1659 end
1660 for i=108,1131 do
1661 local v = 0xF700 + i - 108
1662
1663 t[i] = char(extract(v,8,8),extract(v,0,8))
1664 end
1665 for i=1132,2048 do
1666 t[i] = char(28,band(rshift(i,8),0xFF),band(i,0xFF))
1667 end
1668
1669 setmetatableindex(encode,function(t,k)
1670
1671 local r = round(k)
1672 local v = rawget(t,r)
1673 if v then
1674 return v
1675 end
1676 local v1 = floor(k)
1677 local v2 = floor((k - v1) * 0x10000)
1678 return char(255,extract(v1,8,8),extract(v1,0,8),extract(v2,8,8),extract(v2,0,8))
1679 end)
1680 return t[i]
1681 end)
1682
1683 readers.cffencoder = encode
1684
1685 local function p_setvsindex()
1686 local vsindex = stack[top]
1687 updateregions(vsindex)
1688 top = top - 1
1689 end
1690
1691 local function p_blend()
1692
1693 local n = stack[top]
1694 top = top - 1
1695 if not axis then
1696
1697 elseif n == 1 then
1698 top = top - nofregions
1699 local v = stack[top]
1700 for r=1,nofregions do
1701 v = v + stack[top+r] * factors[r]
1702 end
1703 stack[top] = round(v)
1704 else
1705 top = top - nofregions * n
1706 local d = top
1707 local k = top - n
1708 for i=1,n do
1709 k = k + 1
1710 local v = stack[k]
1711 for r=1,nofregions do
1712 v = v + stack[d+r] * factors[r]
1713 end
1714 stack[k] = round(v)
1715 d = d + nofregions
1716 end
1717 end
1718 end
1719
1720 local function p_getstem()
1721 local n = 0
1722 if top % 2 ~= 0 then
1723 n = 1
1724 end
1725 if top > n then
1726 stems = stems + idiv(top-n,2)
1727 end
1728 end
1729
1730 local function p_getmask()
1731 local n = 0
1732 if top % 2 ~= 0 then
1733 n = 1
1734 end
1735 if top > n then
1736 stems = stems + idiv(top-n,2)
1737 end
1738 if stems == 0 then
1739 return 0
1740 elseif stems <= 8 then
1741 return 1
1742 else
1743 return idiv(stems+7,8)
1744 end
1745 end
1746
1747
1748
1749 local process
1750
1751 local function call(scope,list,bias)
1752 depth = depth + 1
1753 if top == 0 then
1754 showstate(formatters["unknown %s call %s, case %s"](scope,"?",1))
1755 top = 0
1756 else
1757 local index = stack[top] + bias
1758 top = top - 1
1759 if trace_charstrings then
1760 showvalue(scope,index,true)
1761 end
1762 local tab = list[index]
1763 if tab then
1764 process(tab)
1765 else
1766 showstate(formatters["unknown %s call %s, case %s"](scope,index,2))
1767 top = 0
1768 end
1769 end
1770 depth = depth - 1
1771 end
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811 process = function(tab)
1812 local i = 1
1813 local n = #tab
1814 while i <= n do
1815 local t = tab[i]
1816 if t >= 32 then
1817 top = top + 1
1818 if t <= 246 then
1819
1820 stack[top] = t - 139
1821 i = i + 1
1822 elseif t <= 250 then
1823
1824
1825
1826 stack[top] = t*256 - 63124 + tab[i+1]
1827 i = i + 2
1828 elseif t <= 254 then
1829
1830
1831
1832 stack[top] = -t*256 + 64148 - tab[i+1]
1833 i = i + 2
1834 else
1835
1836 local n1 = 0x100 * tab[i+1] + tab[i+2]
1837 local n2 = 0x100 * tab[i+3] + tab[i+4]
1838 if n1 >= 0x8000 then
1839 n1 = n1 - 0x10000
1840 end
1841 stack[top] = n1 + n2/0xFFFF
1842 i = i + 5
1843 end
1844 elseif t == 28 then
1845
1846 top = top + 1
1847 local n = 0x100 * tab[i+1] + tab[i+2]
1848 if n >= 0x8000 then
1849
1850 stack[top] = n - 0x10000
1851 else
1852 stack[top] = n
1853 end
1854 i = i + 3
1855 elseif t == 11 then
1856 if trace_charstrings then
1857 showstate("return")
1858 end
1859 return
1860 elseif t == 10 then
1861 call("local",locals,localbias)
1862 i = i + 1
1863 elseif t == 14 then
1864 if width then
1865
1866 elseif top > 0 then
1867 width = stack[1]
1868 if trace_charstrings then
1869 showvalue("width",width)
1870 end
1871 else
1872 width = true
1873 end
1874 if trace_charstrings then
1875 showstate("endchar")
1876 end
1877 return
1878 elseif t == 29 then
1879 call("global",globals,globalbias)
1880 i = i + 1
1881 elseif t == 12 then
1882 i = i + 1
1883 local t = tab[i]
1884 if justpass then
1885 if t >= 34 and t <= 37 then
1886 for i=1,top do
1887 r = r + 1 ; result[r] = encode[stack[i]]
1888 end
1889 r = r + 1 ; result[r] = chars[12]
1890 r = r + 1 ; result[r] = chars[t]
1891 top = 0
1892 elseif t == 6 then
1893 seacs[procidx] = {
1894 asb = stack[1],
1895 adx = stack[2],
1896 ady = stack[3],
1897 base = stack[4],
1898 accent = stack[5],
1899 width = width,
1900 lsb = lsb,
1901 }
1902 top = 0
1903 else
1904 local a = subactions[t]
1905 if a then
1906 a(t)
1907 else
1908 top = 0
1909 end
1910 end
1911 else
1912 local a = subactions[t]
1913 if a then
1914 a(t)
1915 else
1916 if trace_charstrings then
1917 showvalue("<subaction>",t)
1918 end
1919 top = 0
1920 end
1921 end
1922 i = i + 1
1923 elseif justpass then
1924
1925 if t == 15 then
1926 p_setvsindex()
1927 i = i + 1
1928 elseif t == 16 then
1929 local s = p_blend() or 0
1930 i = i + s + 1
1931
1932 elseif t == 1 or t == 3 or t == 18 or operation == 23 then
1933 p_getstem()
1934 if true then
1935 if top > 0 then
1936 for i=1,top do
1937 r = r + 1 ; result[r] = encode[stack[i]]
1938 end
1939 top = 0
1940 end
1941 r = r + 1 ; result[r] = chars[t]
1942 else
1943 top = 0
1944 end
1945 i = i + 1
1946
1947 elseif t == 19 or t == 20 then
1948 local s = p_getmask() or 0
1949 if true then
1950 if top > 0 then
1951 for i=1,top do
1952 r = r + 1 ; result[r] = encode[stack[i]]
1953 end
1954 top = 0
1955 end
1956 r = r + 1 ; result[r] = chars[t]
1957 for j=1,s do
1958 i = i + 1
1959 r = r + 1 ; result[r] = chars[tab[i]]
1960 end
1961 else
1962 i = i + s
1963 top = 0
1964 end
1965 i = i + 1
1966
1967 elseif t == 9 then
1968 top = 0
1969 i = i + 1
1970 elseif t == 13 then
1971 hsbw()
1972 if version == "cff" then
1973
1974 r = r + 1 ; result[r] = encode[lsb]
1975 r = r + 1 ; result[r] = chars[22]
1976 else
1977
1978 end
1979 i = i + 1
1980 else
1981 if trace_charstrings then
1982 showstate(reverse[t] or "<action>")
1983 end
1984 if top > 0 then
1985
1986 if t == 8 and top > 48 then
1987
1988
1989 local n = 0
1990 for i=1,top do
1991
1992 if n == 48 then
1993 local zero = encode[0]
1994 local res3 = result[r-3]
1995 local res2 = result[r-2]
1996 local res1 = result[r-1]
1997 local res0 = result[r]
1998 result[r-3] = zero
1999 result[r-2] = zero
2000 r = r + 1 ; result[r] = chars[t]
2001 r = r + 1 ; result[r] = zero
2002 r = r + 1 ; result[r] = zero
2003 r = r + 1 ; result[r] = res3
2004 r = r + 1 ; result[r] = res2
2005 r = r + 1 ; result[r] = res1
2006 r = r + 1 ; result[r] = res0
2007 n = 1
2008 else
2009 n = n + 1
2010 end
2011 r = r + 1 ; result[r] = encode[stack[i]]
2012 end
2013 else
2014 for i=1,top do
2015 r = r + 1 ; result[r] = encode[stack[i]]
2016 end
2017 end
2018 top = 0
2019 end
2020 r = r + 1 ; result[r] = chars[t]
2021 i = i + 1
2022 end
2023 else
2024 local a = actions[t]
2025 if a then
2026 local s = a(t)
2027 if s then
2028 i = i + s + 1
2029 else
2030 i = i + 1
2031 end
2032 else
2033 if trace_charstrings then
2034 showstate(reverse[t] or "<action>")
2035 end
2036 top = 0
2037 i = i + 1
2038 end
2039 end
2040 end
2041 end
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081 local function setbias(globals,locals,nobias)
2082 if nobias then
2083 return 0, 0
2084 else
2085 local g = #globals
2086 local l = #locals
2087 return
2088 ((g < 1240 and 107) or (g < 33900 and 1131) or 32768) + 1,
2089 ((l < 1240 and 107) or (l < 33900 and 1131) or 32768) + 1
2090 end
2091 end
2092
2093 local function processshape(tab,index,hack)
2094
2095 if not tab then
2096 glyphs[index] = {
2097 boundingbox = { 0, 0, 0, 0 },
2098 width = 0,
2099 name = charset and charset[index] or nil,
2100 }
2101 return
2102 end
2103
2104 tab = bytetable(tab)
2105
2106 x = 0
2107 y = 0
2108 width = false
2109 lsb = 0
2110 r = 0
2111 top = 0
2112 stems = 0
2113 result = { }
2114 popped = 3
2115 procidx = index
2116
2117 xmin = 0
2118 xmax = 0
2119 ymin = 0
2120 ymax = 0
2121 checked = false
2122 if trace_charstrings then
2123 report("glyph: %i",index)
2124 report("data : % t",tab)
2125 end
2126
2127 if regions then
2128 updateregions(vsindex)
2129 end
2130
2131 process(tab)
2132 if hack then
2133 return x, y
2134 end
2135
2136 local boundingbox = {
2137 round(xmin),
2138 round(ymin),
2139 round(xmax),
2140 round(ymax),
2141 }
2142
2143 if width == true or width == false then
2144 width = defaultwidth
2145 else
2146 width = nominalwidth + width
2147 end
2148
2149 local glyph = glyphs[index]
2150 if justpass then
2151 r = r + 1
2152 result[r] = c_endchar
2153 local stream = concat(result)
2154result = nil
2155
2156
2157
2158 if glyph then
2159 glyph.stream = stream
2160 else
2161 glyphs[index] = { stream = stream }
2162 end
2163 elseif glyph then
2164 glyph.segments = keepcurve ~= false and result or nil
2165 glyph.boundingbox = boundingbox
2166 if not glyph.width then
2167 glyph.width = width
2168 end
2169 if charset and not glyph.name then
2170 glyph.name = charset[index]
2171 end
2172
2173 elseif keepcurve then
2174 glyphs[index] = {
2175 segments = result,
2176 boundingbox = boundingbox,
2177 width = width,
2178 name = charset and charset[index] or nil,
2179
2180 }
2181result = nil
2182 else
2183 glyphs[index] = {
2184 boundingbox = boundingbox,
2185 width = width,
2186 name = charset and charset[index] or nil,
2187 }
2188 end
2189
2190 if trace_charstrings then
2191 report("width : %s",tostring(width))
2192 report("boundingbox: % t",boundingbox)
2193 end
2194
2195 end
2196
2197 startparsing = function(fontdata,data,streams)
2198 reginit = false
2199 axis = false
2200 regions = data.regions
2201 justpass = streams == true
2202 popped = 3
2203 seacs = { }
2204 if regions then
2205
2206
2207
2208 regions = { }
2209 local deltas = data.deltas
2210 for i = 1, #deltas do
2211 regions[i] = deltas[i].regions
2212 end
2213 axis = data.factors or false
2214 end
2215 end
2216
2217 stopparsing = function(fontdata,data)
2218 stack = { }
2219 glyphs = false
2220 result = { }
2221 top = 0
2222 locals = false
2223 globals = false
2224 strings = false
2225 popped = 3
2226 seacs = { }
2227 end
2228
2229 local function setwidths(private)
2230 if not private then
2231 return 0, 0
2232 end
2233 local privatedata = private.data
2234 if not privatedata then
2235 return 0, 0
2236 end
2237 return privatedata.nominalwidthx or 0, privatedata.defaultwidthx or 0
2238 end
2239
2240 parsecharstrings = function(fontdata,data,glphs,doshapes,tversion,streams,nobias)
2241
2242 local dictionary = data.dictionaries[1]
2243 local charstrings = dictionary.charstrings
2244
2245 keepcurve = doshapes
2246 version = tversion
2247 strings = data.strings
2248 globals = data.routines or { }
2249 locals = dictionary.subroutines or { }
2250 charset = dictionary.charset
2251 vsindex = dictionary.vsindex or 0
2252 glyphs = glphs or { }
2253
2254 globalbias, localbias = setbias(globals,locals,nobias)
2255 nominalwidth, defaultwidth = setwidths(dictionary.private)
2256
2257 if charstrings then
2258 startparsing(fontdata,data,streams)
2259 for index=1,#charstrings do
2260 processshape(charstrings[index],index-1)
2261 end
2262 if justpass and next(seacs) then
2263
2264 local charset = data.dictionaries[1].charset
2265 if charset then
2266 local lookup = table.swapped(charset)
2267 for index, v in next, seacs do
2268 local bindex = lookup[standardnames[v.base]]
2269 local aindex = lookup[standardnames[v.accent]]
2270 local bglyph = bindex and glyphs[bindex]
2271 local aglyph = aindex and glyphs[aindex]
2272 if bglyph and aglyph then
2273
2274 local jp = justpass
2275 justpass = false
2276 local x, y = processshape(charstrings[bindex+1],bindex,true)
2277 justpass = jp
2278
2279 local base = bglyph.stream
2280 local accent = aglyph.stream
2281 local moveto = encode[-x-v.asb+v.adx] .. chars[22]
2282 .. encode[-y +v.ady] .. chars[ 4]
2283
2284 base = sub(base,1,#base-1)
2285
2286 glyphs[index].stream = base .. moveto .. accent
2287 end
2288 end
2289 end
2290 end
2291 stopparsing(fontdata,data)
2292 else
2293 report("no charstrings")
2294 end
2295 return glyphs
2296 end
2297
2298 parsecharstring = function(fontdata,data,dictionary,tab,glphs,index,doshapes,tversion,streams)
2299
2300 keepcurve = doshapes
2301 version = tversion
2302 strings = data.strings
2303 globals = data.routines or { }
2304 locals = dictionary.subroutines or { }
2305 charset = false
2306 vsindex = dictionary.vsindex or 0
2307 glyphs = glphs or { }
2308
2309 justpass = streams == true
2310 seacs = { }
2311
2312 globalbias, localbias = setbias(globals,locals,nobias)
2313 nominalwidth, defaultwidth = setwidths(dictionary.private)
2314
2315 processshape(tab,index-1)
2316
2317
2318 end
2319
2320end
2321
2322local function readglobals(f,data,version)
2323 local routines = readlengths(f,version == "cff2")
2324 for i=1,#routines do
2325 routines[i] = readbytetable(f,routines[i])
2326 end
2327 data.routines = routines
2328end
2329
2330local function readencodings(f,data)
2331 data.encodings = { }
2332end
2333
2334local function readcharsets(f,data,dictionary)
2335 local header = data.header
2336 local strings = data.strings
2337 local nofglyphs = data.nofglyphs
2338 local charsetoffset = dictionary.charset
2339 if charsetoffset and charsetoffset ~= 0 then
2340 setposition(f,header.offset+charsetoffset)
2341 local format = readbyte(f)
2342 local charset = { [0] = ".notdef" }
2343 dictionary.charset = charset
2344 if format == 0 then
2345 for i=1,nofglyphs do
2346 charset[i] = strings[readushort(f)]
2347 end
2348 elseif format == 1 or format == 2 then
2349 local readcount = format == 1 and readbyte or readushort
2350 local i = 1
2351 while i <= nofglyphs do
2352 local sid = readushort(f)
2353 local n = readcount(f)
2354 for s=sid,sid+n do
2355 charset[i] = strings[s]
2356 i = i + 1
2357 if i > nofglyphs then
2358 break
2359 end
2360 end
2361 end
2362 else
2363 report("cff parser: unsupported charset format %a",format)
2364 end
2365 else
2366 dictionary.nocharset = true
2367 dictionary.charset = nil
2368 end
2369end
2370
2371local function readprivates(f,data)
2372 local header = data.header
2373 local dictionaries = data.dictionaries
2374 local private = dictionaries[1].private
2375 if private then
2376 setposition(f,header.offset+private.offset)
2377 private.data = readstring(f,private.size)
2378 end
2379end
2380
2381local function readlocals(f,data,dictionary,version)
2382 local header = data.header
2383 local private = dictionary.private
2384 if private then
2385 local subroutineoffset = private.data.subroutines
2386 if subroutineoffset ~= 0 then
2387 setposition(f,header.offset+private.offset+subroutineoffset)
2388 local subroutines = readlengths(f,version == "cff2")
2389 for i=1,#subroutines do
2390 subroutines[i] = readbytetable(f,subroutines[i])
2391 end
2392 dictionary.subroutines = subroutines
2393 private.data.subroutines = nil
2394 else
2395 dictionary.subroutines = { }
2396 end
2397 else
2398 dictionary.subroutines = { }
2399 end
2400end
2401
2402
2403
2404
2405local function readcharstrings(f,data,version)
2406 local header = data.header
2407 local dictionaries = data.dictionaries
2408 local dictionary = dictionaries[1]
2409 local stringtype = dictionary.charstringtype
2410 local offset = dictionary.charstrings
2411 if type(offset) ~= "number" then
2412
2413 elseif stringtype == 2 then
2414 setposition(f,header.offset+offset)
2415
2416 local charstrings = readlengths(f,version=="cff2")
2417 local nofglyphs = #charstrings
2418 for i=1,nofglyphs do
2419 charstrings[i] = readstring(f,charstrings[i])
2420 end
2421 data.nofglyphs = nofglyphs
2422 dictionary.charstrings = charstrings
2423 else
2424 report("unsupported charstr type %i",stringtype)
2425 data.nofglyphs = 0
2426 dictionary.charstrings = { }
2427 end
2428end
2429
2430
2431
2432local function readcidprivates(f,data)
2433 local header = data.header
2434 local dictionaries = data.dictionaries[1].cid.dictionaries
2435 for i=1,#dictionaries do
2436 local dictionary = dictionaries[i]
2437 local private = dictionary.private
2438 if private then
2439 setposition(f,header.offset+private.offset)
2440 private.data = readstring(f,private.size)
2441 end
2442 end
2443 parseprivates(data,dictionaries)
2444end
2445
2446readers.parsecharstrings = parsecharstrings
2447
2448local function readnoselect(f,fontdata,data,glyphs,doshapes,version,streams)
2449 local dictionaries = data.dictionaries
2450 local dictionary = dictionaries[1]
2451 local cid = not dictionary.private and dictionary.cid
2452 readglobals(f,data,version)
2453 readcharstrings(f,data,version)
2454 if version == "cff2" then
2455 dictionary.charset = nil
2456 else
2457 readencodings(f,data)
2458 readcharsets(f,data,dictionary)
2459 end
2460 if cid then
2461 local fdarray = cid.fdarray
2462 if fdarray then
2463 setposition(f,data.header.offset + fdarray)
2464 local dictionaries = readlengths(f,version=="cff2")
2465 local nofdictionaries = #dictionaries
2466 if nofdictionaries > 0 then
2467 for i=1,nofdictionaries do
2468 dictionaries[i] = readstring(f,dictionaries[i])
2469 end
2470 parsedictionaries(data,dictionaries)
2471 dictionary.private = dictionaries[1].private
2472 if nofdictionaries > 1 then
2473 report("ignoring dictionaries > 1 in cid font")
2474 end
2475 end
2476 end
2477 end
2478 readprivates(f,data)
2479 parseprivates(data,data.dictionaries)
2480 readlocals(f,data,dictionary,version)
2481 startparsing(fontdata,data,streams)
2482 parsecharstrings(fontdata,data,glyphs,doshapes,version,streams)
2483 stopparsing(fontdata,data)
2484end
2485
2486local function readfdselect(f,fontdata,data,glyphs,doshapes,version,streams)
2487 local header = data.header
2488 local dictionaries = data.dictionaries
2489 local dictionary = dictionaries[1]
2490 local cid = dictionary.cid
2491 local cidselect = cid and cid.fdselect
2492 readglobals(f,data,version)
2493 readcharstrings(f,data,version)
2494 if version ~= "cff2" then
2495 readencodings(f,data)
2496 end
2497 local charstrings = dictionary.charstrings
2498 local fdindex = { }
2499 local nofglyphs = data.nofglyphs
2500 local maxindex = -1
2501 setposition(f,header.offset+cidselect)
2502 local format = readbyte(f)
2503 if format == 1 then
2504 for i=0,nofglyphs do
2505 local index = readbyte(f)
2506 fdindex[i] = index
2507 if index > maxindex then
2508 maxindex = index
2509 end
2510 end
2511 elseif format == 3 then
2512 local nofranges = readushort(f)
2513 local first = readushort(f)
2514 local index = readbyte(f)
2515 while true do
2516 local last = readushort(f)
2517 if index > maxindex then
2518 maxindex = index
2519 end
2520 for i=first,last do
2521 fdindex[i] = index
2522 end
2523 if last >= nofglyphs then
2524 break
2525 else
2526 first = last + 1
2527 index = readbyte(f)
2528 end
2529 end
2530 else
2531
2532 end
2533
2534 if maxindex >= 0 then
2535 local cidarray = cid.fdarray
2536 if cidarray then
2537 setposition(f,header.offset+cidarray)
2538 local dictionaries = readlengths(f,version == "cff2")
2539 for i=1,#dictionaries do
2540 dictionaries[i] = readstring(f,dictionaries[i])
2541 end
2542 parsedictionaries(data,dictionaries)
2543 cid.dictionaries = dictionaries
2544 readcidprivates(f,data)
2545 for i=1,#dictionaries do
2546 readlocals(f,data,dictionaries[i],version)
2547 end
2548 startparsing(fontdata,data,streams)
2549 for i=1,#charstrings do
2550 parsecharstring(fontdata,data,dictionaries[fdindex[i]+1],charstrings[i],glyphs,i,doshapes,version,streams)
2551
2552 end
2553 stopparsing(fontdata,data)
2554 else
2555 report("no cid array")
2556 end
2557 end
2558end
2559
2560local gotodatatable = readers.helpers.gotodatatable
2561
2562local function cleanup(data,dictionaries)
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572end
2573
2574function readers.cff(f,fontdata,specification)
2575 local tableoffset = gotodatatable(f,fontdata,"cff",specification.details or specification.glyphs)
2576 if tableoffset then
2577 local header = readheader(f)
2578 if header.major ~= 1 then
2579 report("only version %s is supported for table %a",1,"cff")
2580 return
2581 end
2582 local glyphs = fontdata.glyphs
2583 local names = readfontnames(f)
2584 local dictionaries = readtopdictionaries(f)
2585 local strings = readstrings(f)
2586 local data = {
2587 header = header,
2588 names = names,
2589 dictionaries = dictionaries,
2590 strings = strings,
2591 nofglyphs = fontdata.nofglyphs,
2592 }
2593
2594 parsedictionaries(data,dictionaries,"cff")
2595
2596 local dic = dictionaries[1]
2597 local cid = dic.cid
2598
2599 local cffinfo = {
2600 familyname = dic.familyname,
2601 fullname = dic.fullname,
2602 boundingbox = dic.boundingbox,
2603 weight = dic.weight,
2604 italicangle = dic.italicangle,
2605 underlineposition = dic.underlineposition,
2606 underlinethickness = dic.underlinethickness,
2607 defaultwidth = dic.defaultwidthx,
2608 nominalwidth = dic.nominalwidthx,
2609 monospaced = dic.monospaced,
2610 }
2611 fontdata.cidinfo = cid and {
2612 registry = cid.registry,
2613 ordering = cid.ordering,
2614 supplement = cid.supplement,
2615 }
2616 fontdata.cffinfo = cffinfo
2617
2618 local all = specification.shapes or specification.streams or false
2619 if specification.glyphs or all then
2620 if cid and cid.fdselect then
2621 readfdselect(f,fontdata,data,glyphs,all,"cff",specification.streams)
2622 else
2623 readnoselect(f,fontdata,data,glyphs,all,"cff",specification.streams)
2624 end
2625 end
2626 local private = dic.private
2627 if private then
2628 local data = private.data
2629 if type(data) == "table" then
2630 cffinfo.defaultwidth = data.defaultwidthx or cffinfo.defaultwidth
2631 cffinfo.nominalwidth = data.nominalwidthx or cffinfo.nominalwidth
2632 cffinfo.bluevalues = data.bluevalues
2633 cffinfo.otherblues = data.otherblues
2634 cffinfo.familyblues = data.familyblues
2635 cffinfo.familyotherblues = data.familyotherblues
2636 cffinfo.bluescale = data.bluescale
2637 cffinfo.blueshift = data.blueshift
2638 cffinfo.bluefuzz = data.bluefuzz
2639 cffinfo.stdhw = data.stdhw
2640 cffinfo.stdvw = data.stdvw
2641 end
2642 end
2643 cleanup(data,dictionaries)
2644 end
2645end
2646
2647function readers.cff2(f,fontdata,specification)
2648 local tableoffset = gotodatatable(f,fontdata,"cff2",specification.glyphs)
2649 if tableoffset then
2650 local header = readheader(f)
2651 if header.major ~= 2 then
2652 report("only version %s is supported for table %a",2,"cff2")
2653 return
2654 end
2655 local glyphs = fontdata.glyphs
2656 local dictionaries = { readstring(f,header.dsize) }
2657 local data = {
2658 header = header,
2659 dictionaries = dictionaries,
2660 nofglyphs = fontdata.nofglyphs,
2661 }
2662
2663 parsedictionaries(data,dictionaries,"cff2")
2664
2665 local offset = dictionaries[1].vstore
2666 if offset > 0 then
2667 local storeoffset = dictionaries[1].vstore + data.header.offset + 2
2668 local regions, deltas = readers.helpers.readvariationdata(f,storeoffset,factors)
2669
2670 data.regions = regions
2671 data.deltas = deltas
2672 else
2673 data.regions = { }
2674 data.deltas = { }
2675 end
2676 data.factors = specification.factors
2677
2678 local cid = data.dictionaries[1].cid
2679 local all = specification.shapes or specification.streams or false
2680 if cid and cid.fdselect then
2681 readfdselect(f,fontdata,data,glyphs,all,"cff2",specification.streams)
2682 else
2683 readnoselect(f,fontdata,data,glyphs,all,"cff2",specification.streams)
2684 end
2685 cleanup(data,dictionaries)
2686 end
2687end
2688
2689
2690
2691function readers.cffcheck(filename)
2692 local f = io.open(filename,"rb")
2693 if f then
2694 local fontdata = {
2695 glyphs = { },
2696 }
2697 local header = readheader(f)
2698 if header.major ~= 1 then
2699 report("only version %s is supported for table %a",1,"cff")
2700 return
2701 end
2702 local names = readfontnames(f)
2703 local dictionaries = readtopdictionaries(f)
2704 local strings = readstrings(f)
2705 local glyphs = { }
2706 local data = {
2707 header = header,
2708 names = names,
2709 dictionaries = dictionaries,
2710 strings = strings,
2711 glyphs = glyphs,
2712 nofglyphs = 0,
2713 }
2714
2715 parsedictionaries(data,dictionaries,"cff")
2716
2717 local cid = data.dictionaries[1].cid
2718 if cid and cid.fdselect then
2719 readfdselect(f,fontdata,data,glyphs,false)
2720 else
2721 readnoselect(f,fontdata,data,glyphs,false)
2722 end
2723 return data
2724 end
2725end
2726 |