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_single =
309 P("\00") / function()
310 result.version = strings[stack[top]] or "unset"
311 top = 0
312 end
313 + P("\01") / function()
314 result.notice = strings[stack[top]] or "unset"
315 top = 0
316 end
317 + P("\02") / function()
318 result.fullname = strings[stack[top]] or "unset"
319 top = 0
320 end
321 + P("\03") / function()
322 result.familyname = strings[stack[top]] or "unset"
323 top = 0
324 end
325 + P("\04") / function()
326 result.weight = strings[stack[top]] or "unset"
327 top = 0
328 end
329 + P("\05") / function()
330 result.fontbbox = { unpack(stack,1,4) }
331 top = 0
332 end
333 + P("\06") / function()
334 result.bluevalues = { unpack(stack,1,top) }
335 top = 0
336 end
337 + P("\07") / function()
338 result.otherblues = { unpack(stack,1,top) }
339 top = 0
340 end
341 + P("\08") / function()
342 result.familyblues = { unpack(stack,1,top) }
343 top = 0
344 end
345 + P("\09") / function()
346 result.familyotherblues = { unpack(stack,1,top) }
347 top = 0
348 end
349 + P("\10") / function()
350 result.stdhw = stack[top]
351 top = 0
352 end
353 + P("\11") / function()
354 result.stdvw = stack[top]
355 top = 0
356 end
357 + P("\13") / function()
358 result.uniqueid = stack[top]
359 top = 0
360 end
361 + P("\14") / function()
362 result.xuid = concat(stack,"",1,top)
363 top = 0
364 end
365 + P("\15") / function()
366 result.charset = stack[top]
367 top = 0
368 end
369 + P("\16") / function()
370 result.encoding = stack[top]
371 top = 0
372 end
373 + P("\17") / function()
374 result.charstrings = stack[top]
375 top = 0
376 end
377 + P("\18") / function()
378 result.private = {
379 size = stack[top-1],
380 offset = stack[top],
381 }
382 top = 0
383 end
384 + P("\19") / function()
385 result.subroutines = stack[top]
386 top = 0
387 end
388 + P("\20") / function()
389 result.defaultwidthx = stack[top]
390 top = 0
391 end
392 + P("\21") / function()
393 result.nominalwidthx = stack[top]
394 top = 0
395 end
396
397
398
399
400 + P("\24") / function()
401 result.vstore = stack[top]
402 top = 0
403 end
404 + P("\25") / function()
405 result.maxstack = stack[top]
406 top = 0
407 end
408
409
410
411
412
413 local p_double = P("\12") * (
414 P("\00") / function()
415 result.copyright = stack[top]
416 top = 0
417 end
418 + P("\01") / function()
419 result.monospaced = stack[top] == 1 and true or false
420 top = 0
421 end
422 + P("\02") / function()
423 result.italicangle = stack[top]
424 top = 0
425 end
426 + P("\03") / function()
427 result.underlineposition = stack[top]
428 top = 0
429 end
430 + P("\04") / function()
431 result.underlinethickness = stack[top]
432 top = 0
433 end
434 + P("\05") / function()
435 result.painttype = stack[top]
436 top = 0
437 end
438 + P("\06") / function()
439 result.charstringtype = stack[top]
440 top = 0
441 end
442 + P("\07") / function()
443 result.fontmatrix = { unpack(stack,1,6) }
444 top = 0
445 end
446 + P("\08") / function()
447 result.strokewidth = stack[top]
448 top = 0
449 end
450 + P("\09") / function()
451 result.bluescale = stack[top]
452 top = 0
453 end
454 + P("\10") / function()
455 result.blueshift = stack[top]
456 top = 0
457 end
458 + P("\11") / function()
459 result.bluefuzz = stack[top]
460 top = 0
461 end
462 + P("\12") / function()
463 result.stemsnaph = { unpack(stack,1,top) }
464 top = 0
465 end
466 + P("\13") / function()
467 result.stemsnapv = { unpack(stack,1,top) }
468 top = 0
469 end
470 + P("\20") / function()
471 result.syntheticbase = stack[top]
472 top = 0
473 end
474 + P("\21") / function()
475 result.postscript = strings[stack[top]] or "unset"
476 top = 0
477 end
478 + P("\22") / function()
479 result.basefontname = strings[stack[top]] or "unset"
480 top = 0
481 end
482 + P("\21") / function()
483 result.basefontblend = stack[top]
484 top = 0
485 end
486 + P("\30") / function()
487 result.cid.registry = strings[stack[top-2]] or "unset"
488 result.cid.ordering = strings[stack[top-1]] or "unset"
489 result.cid.supplement = stack[top]
490 top = 0
491 end
492 + P("\31") / function()
493 result.cid.fontversion = stack[top]
494 top = 0
495 end
496 + P("\32") / function()
497 result.cid.fontrevision= stack[top]
498 top = 0
499 end
500 + P("\33") / function()
501 result.cid.fonttype = stack[top]
502 top = 0
503 end
504 + P("\34") / function()
505 result.cid.count = stack[top]
506 top = 0
507 end
508 + P("\35") / function()
509 result.cid.uidbase = stack[top]
510 top = 0
511 end
512 + P("\36") / function()
513 result.cid.fdarray = stack[top]
514 top = 0
515 end
516 + P("\37") / function()
517 result.cid.fdselect = stack[top]
518 top = 0
519 end
520 + P("\38") / function()
521 result.cid.fontname = strings[stack[top]] or "unset"
522 top = 0
523 end
524 )
525
526
527
528
529
530 local remap_1 = {
531 ["\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",
532 ["\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",
533 ["\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",
534 ["\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",
535 ["\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",
536 ["\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",
537 ["\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",
538 ["\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",
539 ["\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",
540 ["\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",
541 ["\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"] = ".",
542 ["\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",
543 ["\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-",
544 ["\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"] = "-",
545 }
546 local remap_2 = {
547 ["\x0F"] = "0", ["\x1F"] = "1", ["\x2F"] = "2", ["\x3F"] = "3", ["\x4F"] = "4",
548 ["\x5F"] = "5", ["\x6F"] = "6", ["\x7F"] = "7", ["\x8F"] = "8", ["\x9F"] = "9",
549 }
550
551 local p_last_1 = S("\x0F\x1F\x2F\x3F\x4F\x5F\x6F\x7F\x8F\x9F\xAF\xBF")
552 local p_last_2 = R("\xF0\xFF")
553
554
555
556
557 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)
558
559 top = top + 1
560 stack[top] = tonumber(n) or 0
561 end
562
563 local p_byte = C(R("\32\246")) / function(b0)
564
565 top = top + 1
566 stack[top] = byte(b0) - 139
567 end
568
569 local p_positive = C(R("\247\250")) * C(1) / function(b0,b1)
570
571 top = top + 1
572 stack[top] = (byte(b0)-247)*256 + byte(b1) + 108
573 end
574
575 local p_negative = C(R("\251\254")) * C(1) / function(b0,b1)
576
577 top = top + 1
578 stack[top] = -(byte(b0)-251)*256 - byte(b1) - 108
579 end
580
581
582
583
584
585
586 local p_short = P("\28") * C(1) * C(1) / function(b1,b2)
587
588 top = top + 1
589 local n = 0x100 * byte(b1) + byte(b2)
590 if n >= 0x8000 then
591 stack[top] = n - 0xFFFF - 1
592 else
593 stack[top] = n
594 end
595 end
596
597 local p_long = P("\29") * C(1) * C(1) * C(1) * C(1) / function(b1,b2,b3,b4)
598
599 top = top + 1
600 local n = 0x1000000 * byte(b1) + 0x10000 * byte(b2) + 0x100 * byte(b3) + byte(b4)
601 if n >= 0x8000000 then
602 stack[top] = n - 0xFFFFFFFF - 1
603 else
604 stack[top] = n
605 end
606 end
607
608 local p_unsupported = P(1) / function(detail)
609 top = 0
610 end
611
612 local p_dictionary = (
613 p_byte
614 + p_positive
615 + p_negative
616 + p_short
617 + p_long
618 + p_nibbles
619 + p_single
620 + p_double
621
622 + p_unsupported
623 )^1
624
625 parsedictionaries = function(data,dictionaries,version)
626 stack = { }
627 strings = data.strings
628 if trace_charstrings then
629 report("charstring format %a",version)
630 end
631 for i=1,#dictionaries do
632 top = 0
633 result = version == "cff" and {
634 monospaced = false,
635 italicangle = 0,
636 underlineposition = -100,
637 underlinethickness = 50,
638 painttype = 0,
639 charstringtype = 2,
640 fontmatrix = { 0.001, 0, 0, 0.001, 0, 0 },
641 fontbbox = { 0, 0, 0, 0 },
642 strokewidth = 0,
643 charset = 0,
644 encoding = 0,
645 cid = {
646 fontversion = 0,
647 fontrevision = 0,
648 fonttype = 0,
649 count = 8720,
650 }
651 } or {
652 charstringtype = 2,
653 charset = 0,
654 vstore = 0,
655 cid = {
656
657 },
658 }
659 lpegmatch(p_dictionary,dictionaries[i])
660 dictionaries[i] = result
661 end
662
663 result = { }
664 top = 0
665 stack = { }
666 end
667
668 parseprivates = function(data,dictionaries)
669 stack = { }
670 strings = data.strings
671 for i=1,#dictionaries do
672 local private = dictionaries[i].private
673 if private and private.data then
674 top = 0
675 result = {
676 forcebold = false,
677 languagegroup = 0,
678 expansionfactor = 0.06,
679 initialrandomseed = 0,
680 subroutines = 0,
681 defaultwidthx = 0,
682 nominalwidthx = 0,
683 cid = {
684
685 },
686 }
687 lpegmatch(p_dictionary,private.data)
688 private.data = result
689 end
690 end
691 result = { }
692 top = 0
693 stack = { }
694 end
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712 local x = 0
713 local y = 0
714 local width = false
715 local lsb = 0
716 local result = { }
717 local r = 0
718 local stems = 0
719 local globalbias = 0
720 local localbias = 0
721 local nominalwidth = 0
722 local defaultwidth = 0
723 local charset = false
724 local globals = false
725 local locals = false
726 local depth = 1
727 local xmin = 0
728 local xmax = 0
729 local ymin = 0
730 local ymax = 0
731 local checked = false
732 local keepcurve = false
733 local version = 2
734 local regions = false
735 local nofregions = 0
736 local region = false
737 local factors = false
738 local axis = false
739 local vsindex = 0
740 local justpass = false
741 local seacs = { }
742 local procidx = nil
743
744 local function showstate(where,i,n)
745 if i then
746 local j = i + n - 1
747 report("%w%-10s : [%s] step",depth*2+2,where,concat(stack," ",i,j <= top and j or top))
748 else
749 report("%w%-10s : [%s] n=%i",depth*2,where,concat(stack," ",1,top),top)
750 end
751 end
752
753 local function showvalue(where,value,showstack)
754 if showstack then
755 report("%w%-10s : %s : [%s] n=%i",depth*2,where,tostring(value),concat(stack," ",1,top),top)
756 else
757 report("%w%-10s : %s",depth*2,where,tostring(value))
758 end
759 end
760
761
762
763
764
765
766
767
768
769
770
771
772
773 local function xymoveto()
774 if keepcurve then
775 r = r + 1
776 result[r] = { x, y, "m" }
777 end
778 if checked then
779 if x > xmax then xmax = x elseif x < xmin then xmin = x end
780 if y > ymax then ymax = y elseif y < ymin then ymin = y end
781 else
782 xmin = x
783 ymin = y
784 xmax = x
785 ymax = y
786 checked = true
787 end
788 end
789
790 local function xmoveto()
791 if keepcurve then
792 r = r + 1
793 result[r] = { x, y, "m" }
794 end
795 if not checked then
796 xmin = x
797 ymin = y
798 xmax = x
799 ymax = y
800 checked = true
801 elseif x > xmax then
802 xmax = x
803 elseif x < xmin then
804 xmin = x
805 end
806 end
807
808 local function ymoveto()
809 if keepcurve then
810 r = r + 1
811 result[r] = { x, y, "m" }
812 end
813 if not checked then
814 xmin = x
815 ymin = y
816 xmax = x
817 ymax = y
818 checked = true
819 elseif y > ymax then
820 ymax = y
821 elseif y < ymin then
822 ymin = y
823 end
824 end
825
826 local function moveto()
827 if trace_charstrings then
828 showstate("moveto")
829 end
830 top = 0
831 xymoveto()
832 end
833
834 local function xylineto()
835 if keepcurve then
836 r = r + 1
837 result[r] = { x, y, "l" }
838 end
839 if checked then
840 if x > xmax then xmax = x elseif x < xmin then xmin = x end
841 if y > ymax then ymax = y elseif y < ymin then ymin = y end
842 else
843 xmin = x
844 ymin = y
845 xmax = x
846 ymax = y
847 checked = true
848 end
849 end
850
851 local function xlineto()
852 if keepcurve then
853 r = r + 1
854 result[r] = { x, y, "l" }
855 end
856 if not checked then
857 xmin = x
858 ymin = y
859 xmax = x
860 ymax = y
861 checked = true
862 elseif x > xmax then
863 xmax = x
864 elseif x < xmin then
865 xmin = x
866 end
867 end
868
869 local function ylineto()
870 if keepcurve then
871 r = r + 1
872 result[r] = { x, y, "l" }
873 end
874 if not checked then
875 xmin = x
876 ymin = y
877 xmax = x
878 ymax = y
879 checked = true
880 elseif y > ymax then
881 ymax = y
882 elseif y < ymin then
883 ymin = y
884 end
885 end
886
887 local function xycurveto(x1,y1,x2,y2,x3,y3,i,n)
888 if trace_charstrings then
889 showstate("curveto",i,n)
890 end
891 if keepcurve then
892 r = r + 1
893 result[r] = { x1, y1, x2, y2, x3, y3, "c" }
894 end
895 if checked then
896 if x1 > xmax then xmax = x1 elseif x1 < xmin then xmin = x1 end
897 if y1 > ymax then ymax = y1 elseif y1 < ymin then ymin = y1 end
898 else
899 xmin = x1
900 ymin = y1
901 xmax = x1
902 ymax = y1
903 checked = true
904 end
905 if x2 > xmax then xmax = x2 elseif x2 < xmin then xmin = x2 end
906 if y2 > ymax then ymax = y2 elseif y2 < ymin then ymin = y2 end
907 if x3 > xmax then xmax = x3 elseif x3 < xmin then xmin = x3 end
908 if y3 > ymax then ymax = y3 elseif y3 < ymin then ymin = y3 end
909 end
910
911 local function rmoveto()
912 if not width then
913 if top > 2 then
914 width = stack[1]
915 if trace_charstrings then
916 showvalue("backtrack width",width)
917 end
918 else
919 width = true
920 end
921 end
922 if trace_charstrings then
923 showstate("rmoveto")
924 end
925 x = x + stack[top-1]
926 y = y + stack[top]
927 top = 0
928 xymoveto()
929 end
930
931 local function hmoveto()
932 if not width then
933 if top > 1 then
934 width = stack[1]
935 if trace_charstrings then
936 showvalue("backtrack width",width)
937 end
938 else
939 width = true
940 end
941 end
942 if trace_charstrings then
943 showstate("hmoveto")
944 end
945 x = x + stack[top]
946 top = 0
947 xmoveto()
948 end
949
950 local function vmoveto()
951 if not width then
952 if top > 1 then
953 width = stack[1]
954 if trace_charstrings then
955 showvalue("backtrack width",width)
956 end
957 else
958 width = true
959 end
960 end
961 if trace_charstrings then
962 showstate("vmoveto")
963 end
964 y = y + stack[top]
965 top = 0
966 ymoveto()
967 end
968
969 local function rlineto()
970 if trace_charstrings then
971 showstate("rlineto")
972 end
973 for i=1,top,2 do
974 x = x + stack[i]
975 y = y + stack[i+1]
976 xylineto()
977 end
978 top = 0
979 end
980
981 local function hlineto()
982 if trace_charstrings then
983 showstate("hlineto")
984 end
985 if top == 1 then
986 x = x + stack[1]
987 xlineto()
988 else
989 local swap = true
990 for i=1,top do
991 if swap then
992 x = x + stack[i]
993 xlineto()
994 swap = false
995 else
996 y = y + stack[i]
997 ylineto()
998 swap = true
999 end
1000 end
1001 end
1002 top = 0
1003 end
1004
1005 local function vlineto()
1006 if trace_charstrings then
1007 showstate("vlineto")
1008 end
1009 if top == 1 then
1010 y = y + stack[1]
1011 ylineto()
1012 else
1013 local swap = false
1014 for i=1,top do
1015 if swap then
1016 x = x + stack[i]
1017 xlineto()
1018 swap = false
1019 else
1020 y = y + stack[i]
1021 ylineto()
1022 swap = true
1023 end
1024 end
1025 end
1026 top = 0
1027 end
1028
1029 local function rrcurveto()
1030 if trace_charstrings then
1031 showstate("rrcurveto")
1032 end
1033if top == 6 then
1034 local ax = x + stack[1]
1035 local ay = y + stack[2]
1036 local bx = ax + stack[3]
1037 local by = ay + stack[4]
1038 x = bx + stack[5]
1039 y = by + stack[6]
1040 xycurveto(ax,ay,bx,by,x,y,1,6)
1041else
1042
1043 for i=1,top,6 do
1044 local ax = x + stack[i]
1045 local ay = y + stack[i+1]
1046 local bx = ax + stack[i+2]
1047 local by = ay + stack[i+3]
1048 x = bx + stack[i+4]
1049 y = by + stack[i+5]
1050 xycurveto(ax,ay,bx,by,x,y,i,6)
1051 end
1052end
1053 top = 0
1054 end
1055
1056 local function hhcurveto()
1057 if trace_charstrings then
1058 showstate("hhcurveto")
1059 end
1060 local s = 1
1061 if top % 2 ~= 0 then
1062 y = y + stack[1]
1063 s = 2
1064 end
1065if top == 4 then
1066 local ax = x + stack[1]
1067 local ay = y
1068 local bx = ax + stack[2]
1069 local by = ay + stack[3]
1070 x = bx + stack[4]
1071 y = by
1072 xycurveto(ax,ay,bx,by,x,y,1,4)
1073else
1074 for i=s,top,4 do
1075 local ax = x + stack[i]
1076 local ay = y
1077 local bx = ax + stack[i+1]
1078 local by = ay + stack[i+2]
1079 x = bx + stack[i+3]
1080 y = by
1081 xycurveto(ax,ay,bx,by,x,y,i,4)
1082 end
1083end
1084 top = 0
1085 end
1086
1087 local function vvcurveto()
1088 if trace_charstrings then
1089 showstate("vvcurveto")
1090 end
1091 local s = 1
1092 local d = 0
1093 if top % 2 ~= 0 then
1094 d = stack[1]
1095 s = 2
1096 end
1097if top == 4 then
1098 local ax = x + d
1099 local ay = y + stack[1]
1100 local bx = ax + stack[2]
1101 local by = ay + stack[3]
1102 x = bx
1103 y = by + stack[4]
1104 xycurveto(ax,ay,bx,by,x,y,1,4)
1105 d = 0
1106else
1107 for i=s,top,4 do
1108 local ax = x + d
1109 local ay = y + stack[i]
1110 local bx = ax + stack[i+1]
1111 local by = ay + stack[i+2]
1112 x = bx
1113 y = by + stack[i+3]
1114 xycurveto(ax,ay,bx,by,x,y,i,4)
1115 d = 0
1116 end
1117end
1118 top = 0
1119 end
1120
1121 local function xxcurveto(swap)
1122 local last = top % 4 ~= 0 and stack[top]
1123 if last then
1124 top = top - 1
1125 end
1126if top == 4 then
1127 local ax, ay, bx, by
1128 if swap then
1129 ax = x + stack[1]
1130 ay = y
1131 bx = ax + stack[2]
1132 by = ay + stack[3]
1133 y = by + stack[4]
1134 if last then
1135 x = bx + last
1136 else
1137 x = bx
1138 end
1139 else
1140 ax = x
1141 ay = y + stack[1]
1142 bx = ax + stack[2]
1143 by = ay + stack[3]
1144 x = bx + stack[4]
1145 if last then
1146 y = by + last
1147 else
1148 y = by
1149 end
1150 end
1151 xycurveto(ax,ay,bx,by,x,y,1 ,4)
1152else
1153 for i=1,top,4 do
1154 local ax, ay, bx, by
1155 if swap then
1156 ax = x + stack[i]
1157 ay = y
1158 bx = ax + stack[i+1]
1159 by = ay + stack[i+2]
1160 y = by + stack[i+3]
1161 if last and i+3 == top then
1162 x = bx + last
1163 else
1164 x = bx
1165 end
1166 swap = false
1167 else
1168 ax = x
1169 ay = y + stack[i]
1170 bx = ax + stack[i+1]
1171 by = ay + stack[i+2]
1172 x = bx + stack[i+3]
1173 if last and i+3 == top then
1174 y = by + last
1175 else
1176 y = by
1177 end
1178 swap = true
1179 end
1180 xycurveto(ax,ay,bx,by,x,y,i,4)
1181 end
1182end
1183 top = 0
1184 end
1185
1186 local function hvcurveto()
1187 if trace_charstrings then
1188 showstate("hvcurveto")
1189 end
1190 xxcurveto(true)
1191 end
1192
1193 local function vhcurveto()
1194 if trace_charstrings then
1195 showstate("vhcurveto")
1196 end
1197 xxcurveto(false)
1198 end
1199
1200 local function rcurveline()
1201 if trace_charstrings then
1202 showstate("rcurveline")
1203 end
1204 for i=1,top-2,6 do
1205 local ax = x + stack[i]
1206 local ay = y + stack[i+1]
1207 local bx = ax + stack[i+2]
1208 local by = ay + stack[i+3]
1209 x = bx + stack[i+4]
1210 y = by + stack[i+5]
1211 xycurveto(ax,ay,bx,by,x,y,i,6)
1212 end
1213 x = x + stack[top-1]
1214 y = y + stack[top]
1215 xylineto()
1216 top = 0
1217 end
1218
1219 local function rlinecurve()
1220 if trace_charstrings then
1221 showstate("rlinecurve")
1222 end
1223 if top > 6 then
1224 for i=1,top-6,2 do
1225 x = x + stack[i]
1226 y = y + stack[i+1]
1227 xylineto()
1228 end
1229 end
1230 local ax = x + stack[top-5]
1231 local ay = y + stack[top-4]
1232 local bx = ax + stack[top-3]
1233 local by = ay + stack[top-2]
1234 x = bx + stack[top-1]
1235 y = by + stack[top]
1236 xycurveto(ax,ay,bx,by,x,y)
1237 top = 0
1238 end
1239
1240
1241
1242 local function flex()
1243 if trace_charstrings then
1244 showstate("flex")
1245 end
1246 local ax = x + stack[1]
1247 local ay = y + stack[2]
1248 local bx = ax + stack[3]
1249 local by = ay + stack[4]
1250 local cx = bx + stack[5]
1251 local cy = by + stack[6]
1252 xycurveto(ax,ay,bx,by,cx,cy)
1253 local dx = cx + stack[7]
1254 local dy = cy + stack[8]
1255 local ex = dx + stack[9]
1256 local ey = dy + stack[10]
1257 x = ex + stack[11]
1258 y = ey + stack[12]
1259 xycurveto(dx,dy,ex,ey,x,y)
1260 top = 0
1261 end
1262
1263 local function hflex()
1264 if trace_charstrings then
1265 showstate("hflex")
1266 end
1267 local ax = x + stack[1]
1268 local ay = y
1269 local bx = ax + stack[2]
1270 local by = ay + stack[3]
1271 local cx = bx + stack[4]
1272 local cy = by
1273 xycurveto(ax,ay,bx,by,cx,cy)
1274 local dx = cx + stack[5]
1275 local dy = by
1276 local ex = dx + stack[6]
1277 local ey = y
1278 x = ex + stack[7]
1279 xycurveto(dx,dy,ex,ey,x,y)
1280 top = 0
1281 end
1282
1283 local function hflex1()
1284 if trace_charstrings then
1285 showstate("hflex1")
1286 end
1287 local ax = x + stack[1]
1288 local ay = y + stack[2]
1289 local bx = ax + stack[3]
1290 local by = ay + stack[4]
1291 local cx = bx + stack[5]
1292 local cy = by
1293 xycurveto(ax,ay,bx,by,cx,cy)
1294 local dx = cx + stack[6]
1295 local dy = by
1296 local ex = dx + stack[7]
1297 local ey = dy + stack[8]
1298 x = ex + stack[9]
1299 xycurveto(dx,dy,ex,ey,x,y)
1300 top = 0
1301 end
1302
1303 local function flex1()
1304 if trace_charstrings then
1305 showstate("flex1")
1306 end
1307 local ax = x + stack[1]
1308 local ay = y + stack[2]
1309 local bx = ax + stack[3]
1310 local by = ay + stack[4]
1311 local cx = bx + stack[5]
1312 local cy = by + stack[6]
1313 xycurveto(ax,ay,bx,by,cx,cy)
1314 local dx = cx + stack[7]
1315 local dy = cy + stack[8]
1316 local ex = dx + stack[9]
1317 local ey = dy + stack[10]
1318 if abs(ex - x) > abs(ey - y) then
1319 x = ex + stack[11]
1320 else
1321 y = ey + stack[11]
1322 end
1323 xycurveto(dx,dy,ex,ey,x,y)
1324 top = 0
1325 end
1326
1327 local function getstem()
1328 if top == 0 then
1329
1330 elseif top % 2 ~= 0 then
1331 if width then
1332 remove(stack,1)
1333 else
1334 width = remove(stack,1)
1335 if trace_charstrings then
1336 showvalue("width",width)
1337 end
1338 end
1339 top = top - 1
1340 end
1341 if trace_charstrings then
1342 showstate("stem")
1343 end
1344 stems = stems + (top // 2)
1345 top = 0
1346 end
1347
1348 local function getmask()
1349 if top == 0 then
1350
1351 elseif top % 2 ~= 0 then
1352 if width then
1353 remove(stack,1)
1354 else
1355 width = remove(stack,1)
1356 if trace_charstrings then
1357 showvalue("width",width)
1358 end
1359 end
1360 top = top - 1
1361 end
1362 if trace_charstrings then
1363 showstate(operator == 19 and "hintmark" or "cntrmask")
1364 end
1365 stems = stems + (top // 2)
1366 top = 0
1367 if stems == 0 then
1368
1369 elseif stems <= 8 then
1370 return 1
1371 else
1372 return (stems + 7) // 8
1373 end
1374 end
1375
1376 local function unsupported(t)
1377 if trace_charstrings then
1378 showstate("unsupported " .. t)
1379 end
1380 top = 0
1381 end
1382
1383 local function unsupportedsub(t)
1384 if trace_charstrings then
1385 showstate("unsupported sub " .. t)
1386 end
1387 top = 0
1388 end
1389
1390
1391
1392 local function getstem3()
1393 if trace_charstrings then
1394 showstate("stem3")
1395 end
1396 top = 0
1397 end
1398
1399 local function divide()
1400 if version == "cff" then
1401 local d = stack[top]
1402 top = top - 1
1403 stack[top] = stack[top] / d
1404 end
1405 end
1406
1407 local function closepath()
1408 if version == "cff" then
1409 if trace_charstrings then
1410 showstate("closepath")
1411 end
1412 end
1413 top = 0
1414 end
1415
1416 local function hsbw()
1417 if version == "cff" then
1418 if trace_charstrings then
1419 showstate("hsbw")
1420 end
1421 lsb = stack[top-1] or 0
1422 width = stack[top]
1423 end
1424 top = 0
1425 end
1426
1427 local function sbw()
1428 if version == "cff" then
1429 if trace_charstrings then
1430 showstate("sbw")
1431 end
1432 lsb = stack[top-3]
1433 width = stack[top-1]
1434 end
1435 top = 0
1436 end
1437
1438
1439
1440 local function seac()
1441 if version == "cff" then
1442 if trace_charstrings then
1443 showstate("seac")
1444 end
1445 end
1446 top = 0
1447 end
1448
1449
1450
1451
1452
1453
1454 local popped = 3
1455 local hints = 3
1456
1457
1458
1459 local function callothersubr()
1460 if version == "cff" then
1461 if trace_charstrings then
1462 showstate("callothersubr")
1463 end
1464 if stack[top] == hints then
1465 popped = stack[top-2]
1466 else
1467 popped = 3
1468 end
1469 local t = stack[top-1]
1470 if t then
1471 top = top - (t + 2)
1472 if top < 0 then
1473 top = 0
1474 end
1475 else
1476 top = 0
1477 end
1478 else
1479 top = 0
1480 end
1481 end
1482
1483
1484
1485 local function pop()
1486 if version == "cff" then
1487 if trace_charstrings then
1488 showstate("pop")
1489 end
1490 top = top + 1
1491 stack[top] = popped
1492 else
1493 top = 0
1494 end
1495 end
1496
1497 local function setcurrentpoint()
1498 if version == "cff" then
1499 if trace_charstrings then
1500 showstate("setcurrentpoint (unsupported)")
1501 end
1502 x = x + stack[top-1]
1503 y = y + stack[top]
1504 end
1505 top = 0
1506 end
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516 local reginit = false
1517
1518 local function updateregions(n)
1519 if regions then
1520 local current = regions[n+1] or regions[1]
1521 nofregions = #current
1522 if axis and n ~= reginit then
1523 factors = { }
1524 for i=1,nofregions do
1525 local region = current[i]
1526 local s = 1
1527 for j=1,#axis do
1528 local f = axis[j]
1529 local r = region[j]
1530 local start = r.start
1531 local peak = r.peak
1532 local stop = r.stop
1533 if start > peak or peak > stop then
1534
1535 elseif start < 0 and stop > 0 and peak ~= 0 then
1536
1537 elseif peak == 0 then
1538
1539 elseif f < start or f > stop then
1540
1541 s = 0
1542 break
1543 elseif f < peak then
1544 s = s * (f - start) / (peak - start)
1545 elseif f > peak then
1546 s = s * (stop - f) / (stop - peak)
1547 else
1548
1549 end
1550 end
1551 factors[i] = s
1552 end
1553 end
1554 end
1555 reginit = n
1556 end
1557
1558 local function setvsindex()
1559 local vsindex = stack[top]
1560 if trace_charstrings then
1561 showstate(formatters["vsindex %i"](vsindex))
1562 end
1563 updateregions(vsindex)
1564 top = top - 1
1565 end
1566
1567 local function blend()
1568 local n = stack[top]
1569 top = top - 1
1570 if axis then
1571
1572
1573 if trace_charstrings then
1574 local t = top - nofregions * n
1575 local m = t - n
1576 for i=1,n do
1577 local k = m + i
1578 local d = m + n + (i-1)*nofregions
1579 local old = stack[k]
1580 local new = old
1581 for r=1,nofregions do
1582 new = new + stack[d+r] * factors[r]
1583 end
1584 stack[k] = new
1585 showstate(formatters["blend %i of %i: %s -> %s"](i,n,old,new))
1586 end
1587 top = t
1588 elseif n == 1 then
1589 top = top - nofregions
1590 local v = stack[top]
1591 for r=1,nofregions do
1592 v = v + stack[top+r] * factors[r]
1593 end
1594 stack[top] = v
1595 else
1596 top = top - nofregions * n
1597 local d = top
1598 local k = top - n
1599 for i=1,n do
1600 k = k + 1
1601 local v = stack[k]
1602 for r=1,nofregions do
1603 v = v + stack[d+r] * factors[r]
1604 end
1605 stack[k] = v
1606 d = d + nofregions
1607 end
1608 end
1609 else
1610 top = top - nofregions * n
1611 end
1612 end
1613
1614
1615
1616
1617 local actions = { [0] =
1618 unsupported,
1619 getstem,
1620 unsupported,
1621 getstem,
1622 vmoveto,
1623 rlineto,
1624 hlineto,
1625 vlineto,
1626 rrcurveto,
1627 unsupported,
1628 unsupported,
1629 unsupported,
1630 unsupported,
1631 hsbw,
1632 unsupported,
1633 setvsindex,
1634 blend,
1635 unsupported,
1636 getstem,
1637 getmask,
1638 getmask,
1639 rmoveto,
1640 hmoveto,
1641 getstem,
1642 rcurveline,
1643 rlinecurve,
1644 vvcurveto,
1645 hhcurveto,
1646 unsupported,
1647 unsupported,
1648 vhcurveto,
1649 hvcurveto,
1650 }
1651
1652 local reverse = { [0] =
1653 "unsupported",
1654 "getstem",
1655 "unsupported",
1656 "getstem",
1657 "vmoveto",
1658 "rlineto",
1659 "hlineto",
1660 "vlineto",
1661 "rrcurveto",
1662 "unsupported",
1663 "unsupported",
1664 "unsupported",
1665 "unsupported",
1666 "hsbw",
1667 "unsupported",
1668 "setvsindex",
1669 "blend",
1670 "unsupported",
1671 "getstem",
1672 "getmask",
1673 "getmask",
1674 "rmoveto",
1675 "hmoveto",
1676 "getstem",
1677 "rcurveline",
1678 "rlinecurve",
1679 "vvcurveto",
1680 "hhcurveto",
1681 "unsupported",
1682 "unsupported",
1683 "vhcurveto",
1684 "hvcurveto",
1685 }
1686
1687 local subactions = {
1688
1689 [000] = dotsection,
1690 [001] = getstem3,
1691 [002] = getstem3,
1692 [006] = seac,
1693 [007] = sbw,
1694 [012] = divide,
1695 [016] = callothersubr,
1696 [017] = pop,
1697 [033] = setcurrentpoint,
1698
1699 [034] = hflex,
1700 [035] = flex,
1701 [036] = hflex1,
1702 [037] = flex1,
1703 }
1704
1705 local chars = setmetatableindex(function (t,k)
1706 local v = char(k)
1707 t[k] = v
1708 return v
1709 end)
1710
1711 local c_endchar = chars[14]
1712
1713
1714
1715 local encode = { }
1716 local typeone = false
1717
1718
1719
1720 setmetatableindex(encode,function(t,i)
1721 for i=-2048,-1130 do
1722
1723 t[i] = char(28,(i >> 8) & 0xFF,i & 0xFF)
1724 end
1725 for i=-1131,-108 do
1726 local v = 0xFB00 - i - 108
1727
1728 t[i] = char((v >> 8) & 0xFF,v & 0xFF)
1729 end
1730 for i=-107,107 do
1731 t[i] = chars[i + 139]
1732 end
1733 for i=108,1131 do
1734 local v = 0xF700 + i - 108
1735
1736 t[i] = char((v >> 8) & 0xFF,v & 0xFF)
1737 end
1738 for i=1132,2048 do
1739
1740 t[i] = char(28,(i >> 8) & 0xFF,i & 0xFF)
1741 end
1742 setmetatableindex(encode,function(t,k)
1743
1744 local r = round(k)
1745 local v = rawget(t,r)
1746 if v then
1747 return v
1748 end
1749 local v1 = floor(k)
1750 local v2 = floor((k - v1) * 0x10000)
1751
1752 return char(255,(v1 >> 8) & 0xFF,v1 & 0xFF,(v2 >> 8) & 0xFF,v2 & 0xFF)
1753 end)
1754 return t[i]
1755 end)
1756
1757 readers.cffencoder = encode
1758
1759 local function p_setvsindex()
1760 local vsindex = stack[top]
1761 updateregions(vsindex)
1762 top = top - 1
1763 end
1764
1765 local function p_blend()
1766
1767 local n = stack[top]
1768 top = top - 1
1769 if not axis then
1770
1771 elseif n == 1 then
1772 top = top - nofregions
1773 local v = stack[top]
1774 for r=1,nofregions do
1775 v = v + stack[top+r] * factors[r]
1776 end
1777 stack[top] = round(v)
1778 else
1779 top = top - nofregions * n
1780 local d = top
1781 local k = top - n
1782 for i=1,n do
1783 k = k + 1
1784 local v = stack[k]
1785 for r=1,nofregions do
1786 v = v + stack[d+r] * factors[r]
1787 end
1788 stack[k] = round(v)
1789 d = d + nofregions
1790 end
1791 end
1792 end
1793
1794 local function p_getstem()
1795 local n = 0
1796 if top % 2 ~= 0 then
1797 n = 1
1798 end
1799 if top > n then
1800 stems = stems + ((top - n) // 2)
1801 end
1802 end
1803
1804 local function p_getmask()
1805 local n = 0
1806 if top % 2 ~= 0 then
1807 n = 1
1808 end
1809 if top > n then
1810 stems = stems + ((top - n) // 2)
1811 end
1812 if stems == 0 then
1813 return 0
1814 elseif stems <= 8 then
1815 return 1
1816 else
1817 return (stems + 7) // 8
1818 end
1819 end
1820
1821
1822
1823 local process
1824
1825 local function call(scope,list,bias)
1826 depth = depth + 1
1827 if top == 0 then
1828 showstate(formatters["unknown %s call %s, case %s"](scope,"?",1))
1829 top = 0
1830 else
1831 local index = stack[top] + bias
1832 top = top - 1
1833 if trace_charstrings then
1834 showvalue(scope,index,true)
1835 end
1836 local tab = list[index]
1837 if tab then
1838 process(tab)
1839 else
1840 showstate(formatters["unknown %s call %s, case %s"](scope,index,2))
1841 top = 0
1842 end
1843 end
1844 depth = depth - 1
1845 end
1846
1847
1848
1849 process = function(tab)
1850 local i = 1
1851 local n = #tab
1852 while i <= n do
1853 local t = tab[i]
1854 if t >= 32 then
1855 top = top + 1
1856 if t <= 246 then
1857
1858 stack[top] = t - 139
1859 i = i + 1
1860 elseif t <= 250 then
1861
1862
1863
1864 stack[top] = t*256 - 63124 + tab[i+1]
1865 i = i + 2
1866 elseif t <= 254 then
1867
1868
1869
1870 stack[top] = -t*256 + 64148 - tab[i+1]
1871 i = i + 2
1872 elseif typeone then
1873 local n = 0x1000000 * tab[i+1] + 0x10000 * tab[i+2] + 0x100 * tab[i+3] + tab[i+4]
1874 if n >= 0x8000000 then
1875 n = n - 0xFFFFFFFF - 1
1876 end
1877 stack[top] = n
1878 i = i + 5
1879 else
1880 local n1 = 0x100 * tab[i+1] + tab[i+2]
1881 local n2 = 0x100 * tab[i+3] + tab[i+4]
1882 if n1 >= 0x8000 then
1883 n1 = n1 - 0x10000
1884 end
1885 stack[top] = n1 + n2/0xFFFF
1886 i = i + 5
1887 end
1888 elseif t == 28 then
1889
1890 top = top + 1
1891 local n = 0x100 * tab[i+1] + tab[i+2]
1892 if n >= 0x8000 then
1893
1894 stack[top] = n - 0x10000
1895 else
1896 stack[top] = n
1897 end
1898 i = i + 3
1899 elseif t == 11 then
1900 if trace_charstrings then
1901 showstate("return")
1902 end
1903 return
1904 elseif t == 10 then
1905 call("local",locals,localbias)
1906 i = i + 1
1907 elseif t == 14 then
1908 if width then
1909
1910 elseif top > 0 then
1911 width = stack[1]
1912 if r == 0 and justpass then
1913
1914 r = r + 1 ; result[r] = encode[width]
1915 r = r + 1 ; result[r] = c_endchar
1916 end
1917 if trace_charstrings then
1918 showvalue("width",width)
1919 end
1920 else
1921 width = true
1922 end
1923 if trace_charstrings then
1924 showstate("endchar")
1925 end
1926 return
1927 elseif t == 29 then
1928 call("global",globals,globalbias)
1929 i = i + 1
1930 elseif t == 12 then
1931 i = i + 1
1932 local t = tab[i]
1933 if justpass then
1934 if t >= 34 and t <= 37 then
1935 for i=1,top do
1936 r = r + 1 ; result[r] = encode[stack[i]]
1937 end
1938 r = r + 1 ; result[r] = chars[12]
1939 r = r + 1 ; result[r] = chars[t]
1940 top = 0
1941 elseif t == 6 then
1942 seacs[procidx] = {
1943 asb = stack[1],
1944 adx = stack[2],
1945 ady = stack[3],
1946 base = stack[4],
1947 accent = stack[5],
1948 width = width,
1949 lsb = lsb,
1950 }
1951 top = 0
1952 else
1953 local a = subactions[t]
1954 if a then
1955 a(t)
1956 else
1957 top = 0
1958 end
1959 end
1960 else
1961 local a = subactions[t]
1962 if a then
1963 a(t)
1964 else
1965 if trace_charstrings then
1966 showvalue("<subaction>",t)
1967 end
1968 top = 0
1969 end
1970 end
1971 i = i + 1
1972 elseif justpass then
1973
1974 if t == 15 then
1975 p_setvsindex()
1976 i = i + 1
1977 elseif t == 16 then
1978 local s = p_blend() or 0
1979 i = i + s + 1
1980
1981 elseif t == 1 or t == 3 or t == 18 or operation == 23 then
1982 p_getstem()
1983 if version == "cff" then
1984
1985 if top > 0 then
1986 for i=1,top do
1987 r = r + 1 ; result[r] = encode[stack[i]]
1988 end
1989 top = 0
1990 end
1991 r = r + 1 ; result[r] = chars[t]
1992 else
1993 top = 0
1994 end
1995 i = i + 1
1996
1997 elseif t == 19 or t == 20 then
1998 local s = p_getmask() or 0
1999
2000 if true then
2001 if top > 0 then
2002 for i=1,top do
2003 r = r + 1 ; result[r] = encode[stack[i]]
2004 end
2005 top = 0
2006 end
2007 r = r + 1 ; result[r] = chars[t]
2008 for j=1,s do
2009 i = i + 1
2010 r = r + 1 ; result[r] = chars[tab[i]]
2011 end
2012 else
2013 i = i + s
2014 top = 0
2015 end
2016 i = i + 1
2017
2018 elseif t == 9 then
2019 top = 0
2020 i = i + 1
2021 elseif t == 13 then
2022 hsbw()
2023
2024 if true then
2025
2026 r = r + 1 ; result[r] = encode[lsb]
2027 r = r + 1 ; result[r] = chars[22]
2028 else
2029
2030 end
2031 i = i + 1
2032 else
2033 if trace_charstrings then
2034 showstate(reverse[t] or "<action>")
2035 end
2036 if top > 0 then
2037
2038 if t == 8 and top > 48 then
2039
2040
2041
2042
2043 local n = 0
2044 for i=1,top do
2045
2046 if n == 48 then
2047
2048
2049
2050
2051
2052
2053
2054 r = r + 1 ; result[r] = chars[t]
2055
2056
2057
2058
2059
2060
2061 n = 1
2062 else
2063 n = n + 1
2064 end
2065 r = r + 1 ; result[r] = encode[stack[i]]
2066 end
2067 else
2068 for i=1,top do
2069 r = r + 1 ; result[r] = encode[stack[i]]
2070 end
2071 end
2072 top = 0
2073 end
2074 r = r + 1 ; result[r] = chars[t]
2075 i = i + 1
2076 end
2077 else
2078 local a = actions[t]
2079 if a then
2080 local s = a(t)
2081 if s then
2082 i = i + s + 1
2083 else
2084 i = i + 1
2085 end
2086 else
2087 if trace_charstrings then
2088 showstate(reverse[t] or "<action>")
2089 end
2090 top = 0
2091 i = i + 1
2092 end
2093 end
2094 end
2095 end
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137 readers.potracetocff = potrace and function(glyph,settings)
2138 local xsize = glyph.xsize or 0
2139 local ysize = glyph.ysize or 0
2140 local xoffset = glyph.xoffset or 0
2141 local yoffset = glyph.yoffset or 0
2142 local llx = - xoffset
2143 local lly = yoffset - ysize + 1
2144 local urx = llx + xsize + 1
2145 local ury = lly + ysize
2146
2147 local b, w, h = fonts.handlers.tfm.readers.showpk(glyph,true)
2148 if not b then
2149 return
2150 end
2151 local t = potrace.convert(b,settings,w,h)
2152
2153 llx = round(10*llx)
2154 lly = round(10*lly)
2155 urx = round(10*urx)
2156 ury = round(10*ury)
2157 xoffset = llx
2158 yoffset = -lly
2159
2160 local width = round(10*glyph.width/65536)
2161
2162 for i=1,#t do
2163 local ti = t[i]
2164 for j=1,#ti do
2165 local tj = ti[j]
2166 for k=1,#tj do
2167 tj[k] = round(10*tj[k])
2168 end
2169 end
2170 end
2171
2172 local result = { }
2173 local r = 0
2174 local x = 0
2175 local y = yoffset
2176 r = r + 1 ; result[r] = encode[width]
2177 r = r + 1 ; result[r] = encode[xoffset]
2178 r = r + 1 ; result[r] = chars[22]
2179 for i=1,#t do
2180 local ti = t[i]
2181 local ni = #ti
2182 for j=1,ni do
2183 local tj = ti[j]
2184 local nj = #tj
2185 local x1 = tj[1]
2186 local y1 = tj[2]
2187 if nj == 6 then
2188 local x2 = tj[3]
2189 local y2 = tj[4]
2190 local x3 = tj[5]
2191 local y3 = tj[6]
2192 local d1 = x2 - x
2193 local d2 = y2 - y
2194 local d3 = x3 - x2
2195 local d4 = y3 - y2
2196 local d5 = x1 - x3
2197 local d6 = y1 - y3
2198 if d1 == 0 and d6 == 0 then
2199 r = r + 1 ; result[r] = encode[d2]
2200 r = r + 1 ; result[r] = encode[d3]
2201 r = r + 1 ; result[r] = encode[d4]
2202 r = r + 1 ; result[r] = encode[d5]
2203 r = r + 1 ; result[r] = chars[30]
2204 elseif d2 == 0 and d5 == 0 then
2205 r = r + 1 ; result[r] = encode[d1]
2206 r = r + 1 ; result[r] = encode[d3]
2207 r = r + 1 ; result[r] = encode[d4]
2208 r = r + 1 ; result[r] = encode[d6]
2209 r = r + 1 ; result[r] = chars[31]
2210 else
2211 r = r + 1 ; result[r] = encode[d1]
2212 r = r + 1 ; result[r] = encode[d2]
2213 r = r + 1 ; result[r] = encode[d3]
2214 r = r + 1 ; result[r] = encode[d4]
2215 r = r + 1 ; result[r] = encode[d5]
2216 r = r + 1 ; result[r] = encode[d6]
2217 r = r + 1 ; result[r] = chars[8]
2218 end
2219 elseif j == 1 then
2220 x = x1 - x
2221 y = y1 - y
2222 if x == 0 then
2223 r = r + 1 ; result[r] = encode[y]
2224 r = r + 1 ; result[r] = chars[4]
2225 elseif y == 0 then
2226 r = r + 1 ; result[r] = encode[x]
2227 r = r + 1 ; result[r] = chars[22]
2228 else
2229 r = r + 1 ; result[r] = encode[x]
2230 r = r + 1 ; result[r] = encode[y]
2231 r = r + 1 ; result[r] = chars[21]
2232 end
2233 else
2234 x = x1 - x
2235 y = y1 - y
2236 if x == 0 then
2237 r = r + 1 ; result[r] = encode[y]
2238 r = r + 1 ; result[r] = chars[7]
2239 elseif y == 0 then
2240 r = r + 1 ; result[r] = encode[x]
2241 r = r + 1 ; result[r] = chars[6]
2242 else
2243 r = r + 1 ; result[r] = encode[x]
2244 r = r + 1 ; result[r] = encode[y]
2245 r = r + 1 ; result[r] = chars[5]
2246 end
2247 end
2248 x = x1
2249 y = y1
2250 end
2251 end
2252 r = r + 1 ; result[r] = chars[9]
2253 r = r + 1 ; result[r] = chars[14]
2254 return llx, lly, urx, ury, concat(result)
2255 end or function()
2256 return 0, 0, 0, 0, chars[14]
2257 end
2258
2259
2260
2261
2262 local function setbias(globals,locals,nobias)
2263 if nobias then
2264 return 0, 0
2265 else
2266 local g = #globals
2267 local l = #locals
2268 return
2269 ((g < 1240 and 107) or (g < 33900 and 1131) or 32768) + 1,
2270 ((l < 1240 and 107) or (l < 33900 and 1131) or 32768) + 1
2271 end
2272 end
2273
2274 local function processshape(glyphs,tab,index,hack)
2275
2276 if not tab then
2277 glyphs[index] = {
2278 boundingbox = { 0, 0, 0, 0 },
2279 width = 0,
2280 name = charset and charset[index] or nil,
2281 }
2282 return
2283 end
2284
2285 tab = bytetable(tab)
2286
2287 x = 0
2288 y = 0
2289 width = false
2290 lsb = 0
2291 r = 0
2292 top = 0
2293 stems = 0
2294 result = { }
2295 popped = 3
2296 procidx = index
2297
2298 xmin = 0
2299 xmax = 0
2300 ymin = 0
2301 ymax = 0
2302 checked = false
2303 if trace_charstrings then
2304 report("glyph: %i",index)
2305 report("data : % t",tab)
2306 end
2307
2308 if regions then
2309 updateregions(vsindex)
2310 end
2311 process(tab)
2312 if hack then
2313 return x, y
2314 end
2315
2316 local boundingbox = {
2317 round(xmin),
2318 round(ymin),
2319 round(xmax),
2320 round(ymax),
2321 }
2322
2323 if width == true or width == false then
2324 width = defaultwidth
2325 else
2326 width = nominalwidth + width
2327 end
2328
2329 local glyph = glyphs[index]
2330 if justpass then
2331 r = r + 1
2332 result[r] = c_endchar
2333 local stream = concat(result)
2334result = nil
2335
2336
2337
2338 if glyph then
2339 glyph.stream = stream
2340 glyph.width = width
2341 else
2342 glyphs[index] = { stream = stream, width = width }
2343 end
2344 elseif glyph then
2345 glyph.segments = keepcurve ~= false and result or nil
2346 glyph.boundingbox = boundingbox
2347 if not glyph.width then
2348 glyph.width = width
2349 end
2350 if charset and not glyph.name then
2351 glyph.name = charset[index]
2352 end
2353
2354 elseif keepcurve then
2355 glyphs[index] = {
2356 segments = result,
2357 boundingbox = boundingbox,
2358 width = width,
2359 name = charset and charset[index] or nil,
2360
2361 }
2362result = nil
2363 else
2364 glyphs[index] = {
2365 boundingbox = boundingbox,
2366 width = width,
2367 name = charset and charset[index] or nil,
2368 }
2369 end
2370 if trace_charstrings then
2371 report("width : %s",tostring(width))
2372 report("boundingbox: % t",boundingbox)
2373 end
2374
2375 end
2376
2377 startparsing = function(fontdata,data,streams)
2378 reginit = false
2379 axis = false
2380 regions = data.regions
2381 justpass = streams == true
2382 popped = 3
2383 seacs = { }
2384 if regions then
2385
2386
2387
2388 regions = { }
2389 local deltas = data.deltas
2390 for i = 1, #deltas do
2391 regions[i] = deltas[i].regions
2392 end
2393 axis = data.factors or false
2394 end
2395 end
2396
2397 stopparsing = function(fontdata,data)
2398 stack = { }
2399 glyphs = false
2400 result = { }
2401 top = 0
2402 locals = false
2403 globals = false
2404 strings = false
2405 popped = 3
2406 seacs = { }
2407 end
2408
2409 local function setwidths(private)
2410 if not private then
2411 return 0, 0
2412 end
2413 local privatedata = private.data
2414 if not privatedata then
2415 return 0, 0
2416 end
2417 return privatedata.nominalwidthx or 0, privatedata.defaultwidthx or 0
2418 end
2419
2420 parsecharstrings = function(fontdata,data,glphs,doshapes,tversion,streams,nobias,istypeone)
2421
2422 local dictionary = data.dictionaries[1]
2423 local charstrings = dictionary.charstrings
2424
2425 keepcurve = doshapes
2426 version = tversion
2427 typeone = istypeone or false
2428 strings = data.strings
2429 globals = data.routines or { }
2430 locals = dictionary.subroutines or { }
2431 charset = dictionary.charset
2432 vsindex = dictionary.vsindex or 0
2433
2434 local glyphs = glphs or { }
2435
2436 globalbias, localbias = setbias(globals,locals,nobias)
2437 nominalwidth, defaultwidth = setwidths(dictionary.private)
2438
2439 if charstrings then
2440 startparsing(fontdata,data,streams)
2441 for index=1,#charstrings do
2442 processshape(glyphs,charstrings[index],index-1)
2443 end
2444 if justpass and next(seacs) then
2445
2446 local charset = data.dictionaries[1].charset
2447 if charset then
2448 local lookup = table.swapped(charset)
2449 for index, v in next, seacs do
2450 local bindex = lookup[standardnames[v.base]]
2451 local aindex = lookup[standardnames[v.accent]]
2452 local bglyph = bindex and glyphs[bindex]
2453 local aglyph = aindex and glyphs[aindex]
2454 if bglyph and aglyph then
2455
2456 local jp = justpass
2457 justpass = false
2458 local x, y = processshape(glyphs,charstrings[bindex+1],bindex,true)
2459 justpass = jp
2460
2461 local base = bglyph.stream
2462 local accent = aglyph.stream
2463 local moveto = encode[-x-v.asb+v.adx] .. chars[22]
2464 .. encode[-y +v.ady] .. chars[ 4]
2465
2466 base = sub(base,1,#base-1)
2467
2468 glyphs[index].stream = base .. moveto .. accent
2469 end
2470 end
2471 end
2472 end
2473 stopparsing(fontdata,data)
2474 else
2475 report("no charstrings")
2476 end
2477 return glyphs
2478 end
2479
2480 parsecharstring = function(fontdata,data,dictionary,tab,glphs,index,doshapes,tversion,streams)
2481
2482 keepcurve = doshapes
2483 version = tversion
2484 strings = data.strings
2485 globals = data.routines or { }
2486 locals = dictionary.subroutines or { }
2487 charset = false
2488 vsindex = dictionary.vsindex or 0
2489
2490 local glyphs = glphs or { }
2491
2492 justpass = streams == true
2493 seacs = { }
2494
2495 globalbias, localbias = setbias(globals,locals,nobias)
2496 nominalwidth, defaultwidth = setwidths(dictionary.private)
2497
2498 processshape(glyphs,tab,index-1)
2499
2500 return glyphs[index]
2501 end
2502
2503end
2504
2505local function readglobals(f,data,version)
2506 local routines = readlengths(f,version == "cff2")
2507 for i=1,#routines do
2508 routines[i] = readbytetable(f,routines[i])
2509 end
2510 data.routines = routines
2511end
2512
2513local function readencodings(f,data)
2514 data.encodings = { }
2515end
2516
2517local function readcharsets(f,data,dictionary)
2518 local header = data.header
2519 local strings = data.strings
2520 local nofglyphs = data.nofglyphs
2521 local charsetoffset = dictionary.charset
2522 if charsetoffset and charsetoffset ~= 0 then
2523 setposition(f,header.offset+charsetoffset)
2524 local format = readbyte(f)
2525 local charset = { [0] = ".notdef" }
2526 dictionary.charset = charset
2527 if format == 0 then
2528 for i=1,nofglyphs do
2529 charset[i] = strings[readushort(f)]
2530 end
2531 elseif format == 1 or format == 2 then
2532 local readcount = format == 1 and readbyte or readushort
2533 local i = 1
2534 while i <= nofglyphs do
2535 local sid = readushort(f)
2536 local n = readcount(f)
2537 for s=sid,sid+n do
2538 charset[i] = strings[s]
2539 i = i + 1
2540 if i > nofglyphs then
2541 break
2542 end
2543 end
2544 end
2545 else
2546 report("cff parser: unsupported charset format %a",format)
2547 end
2548 else
2549 dictionary.nocharset = true
2550 dictionary.charset = nil
2551 end
2552end
2553
2554local function readprivates(f,data)
2555 local header = data.header
2556 local dictionaries = data.dictionaries
2557 local private = dictionaries[1].private
2558 if private then
2559 setposition(f,header.offset+private.offset)
2560 private.data = readstring(f,private.size)
2561 end
2562end
2563
2564local function readlocals(f,data,dictionary,cff2)
2565 local header = data.header
2566 local private = dictionary.private
2567 if private then
2568 local subroutineoffset = private.data.subroutines
2569 if subroutineoffset ~= 0 then
2570 setposition(f,header.offset+private.offset+subroutineoffset)
2571 local subroutines = readlengths(f,version == "cff2")
2572 for i=1,#subroutines do
2573 subroutines[i] = readbytetable(f,subroutines[i])
2574 end
2575 dictionary.subroutines = subroutines
2576 private.data.subroutines = nil
2577 else
2578 dictionary.subroutines = { }
2579 end
2580 else
2581 dictionary.subroutines = { }
2582 end
2583end
2584
2585
2586
2587
2588local function readcharstrings(f,data,version)
2589 local header = data.header
2590 local dictionaries = data.dictionaries
2591 local dictionary = dictionaries[1]
2592 local stringtype = dictionary.charstringtype
2593 local offset = dictionary.charstrings
2594 if type(offset) ~= "number" then
2595
2596 elseif stringtype == 2 then
2597 setposition(f,header.offset+offset)
2598
2599 local charstrings = readlengths(f,version=="cff2")
2600 local nofglyphs = #charstrings
2601 for i=1,nofglyphs do
2602 charstrings[i] = readstring(f,charstrings[i])
2603 end
2604 data.nofglyphs = nofglyphs
2605 dictionary.charstrings = charstrings
2606 else
2607 report("unsupported charstr type %i",stringtype)
2608 data.nofglyphs = 0
2609 dictionary.charstrings = { }
2610 end
2611end
2612
2613
2614
2615local function readcidprivates(f,data)
2616 local header = data.header
2617 local dictionaries = data.dictionaries[1].cid.dictionaries
2618 for i=1,#dictionaries do
2619 local dictionary = dictionaries[i]
2620 local private = dictionary.private
2621 if private then
2622 setposition(f,header.offset+private.offset)
2623 private.data = readstring(f,private.size)
2624 end
2625 end
2626 parseprivates(data,dictionaries)
2627end
2628
2629readers.parsecharstrings = parsecharstrings
2630
2631local function readnoselect(f,fontdata,data,glyphs,doshapes,version,streams)
2632 local dictionaries = data.dictionaries
2633 local dictionary = dictionaries[1]
2634 local cid = not dictionary.private and dictionary.cid
2635 readglobals(f,data,version)
2636 readcharstrings(f,data,version)
2637 if version == "cff2" then
2638 dictionary.charset = nil
2639 else
2640 readencodings(f,data)
2641 readcharsets(f,data,dictionary)
2642 end
2643 if cid then
2644 local fdarray = cid.fdarray
2645 if fdarray then
2646 setposition(f,data.header.offset + fdarray)
2647 local dictionaries = readlengths(f,version=="cff2")
2648 local nofdictionaries = #dictionaries
2649 if nofdictionaries > 0 then
2650 for i=1,nofdictionaries do
2651 dictionaries[i] = readstring(f,dictionaries[i])
2652 end
2653 parsedictionaries(data,dictionaries)
2654 dictionary.private = dictionaries[1].private
2655 if nofdictionaries > 1 then
2656 report("ignoring dictionaries > 1 in cid font")
2657 end
2658 end
2659 end
2660 end
2661 readprivates(f,data)
2662 parseprivates(data,data.dictionaries)
2663 readlocals(f,data,dictionary,version)
2664 startparsing(fontdata,data,streams)
2665 parsecharstrings(fontdata,data,glyphs,doshapes,version,streams,false)
2666 stopparsing(fontdata,data)
2667end
2668
2669local function readfdselect(f,fontdata,data,glyphs,doshapes,version,streams)
2670 local header = data.header
2671 local dictionaries = data.dictionaries
2672 local dictionary = dictionaries[1]
2673 local cid = dictionary.cid
2674 local cidselect = cid and cid.fdselect
2675 readglobals(f,data,version)
2676 readcharstrings(f,data,version)
2677 if version ~= "cff2" then
2678 readencodings(f,data)
2679 end
2680 local charstrings = dictionary.charstrings
2681 local fdindex = { }
2682 local nofglyphs = data.nofglyphs
2683 local maxindex = -1
2684 setposition(f,header.offset+cidselect)
2685 local format = readbyte(f)
2686 if format == 1 then
2687 for i=0,nofglyphs do
2688 local index = readbyte(f)
2689 fdindex[i] = index
2690 if index > maxindex then
2691 maxindex = index
2692 end
2693 end
2694 elseif format == 3 then
2695 local nofranges = readushort(f)
2696 local first = readushort(f)
2697 local index = readbyte(f)
2698 while true do
2699 local last = readushort(f)
2700 if index > maxindex then
2701 maxindex = index
2702 end
2703 for i=first,last do
2704 fdindex[i] = index
2705 end
2706 if last >= nofglyphs then
2707 break
2708 else
2709 first = last + 1
2710 index = readbyte(f)
2711 end
2712 end
2713 else
2714 report("unsupported fd index format %i",format)
2715 end
2716
2717 if maxindex >= 0 then
2718 local cidarray = cid.fdarray
2719 if cidarray then
2720 setposition(f,header.offset+cidarray)
2721 local dictionaries = readlengths(f,version == "cff2")
2722 if #dictionaries > 0 then
2723 for i=1,#dictionaries do
2724 dictionaries[i] = readstring(f,dictionaries[i])
2725 end
2726 parsedictionaries(data,dictionaries)
2727 cid.dictionaries = dictionaries
2728 readcidprivates(f,data)
2729 for i=1,#dictionaries do
2730 readlocals(f,data,dictionaries[i],version)
2731 end
2732 startparsing(fontdata,data,streams)
2733 for i=1,#charstrings do
2734 local dictionary = dictionaries[fdindex[i]+1]
2735 if dictionary then
2736 parsecharstring(fontdata,data,dictionary,charstrings[i],glyphs,i,doshapes,version,streams)
2737 else
2738
2739 end
2740
2741 end
2742 stopparsing(fontdata,data)
2743 else
2744 report("no cid dictionaries")
2745 end
2746 else
2747 report("no cid array")
2748 end
2749 end
2750end
2751
2752local gotodatatable = readers.helpers.gotodatatable
2753
2754local function cleanup(data,dictionaries)
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764end
2765
2766function readers.cff(f,fontdata,specification)
2767 local tableoffset = gotodatatable(f,fontdata,"cff",specification.details or specification.glyphs)
2768 if tableoffset then
2769 local header = readheader(f)
2770 if header.major ~= 1 then
2771 report("only version %s is supported for table %a",1,"cff")
2772 return
2773 end
2774 local glyphs = fontdata.glyphs
2775 local names = readfontnames(f)
2776 local dictionaries = readtopdictionaries(f)
2777 local strings = readstrings(f)
2778 local data = {
2779 header = header,
2780 names = names,
2781 dictionaries = dictionaries,
2782 strings = strings,
2783 nofglyphs = fontdata.nofglyphs,
2784 }
2785
2786 parsedictionaries(data,dictionaries,"cff")
2787
2788 local dic = dictionaries[1]
2789 local cid = dic.cid
2790
2791 local cffinfo = {
2792 familyname = dic.familyname,
2793 fullname = dic.fullname,
2794 boundingbox = dic.boundingbox,
2795 weight = dic.weight,
2796 italicangle = dic.italicangle,
2797 underlineposition = dic.underlineposition,
2798 underlinethickness = dic.underlinethickness,
2799 defaultwidth = dic.defaultwidthx,
2800 nominalwidth = dic.nominalwidthx,
2801 monospaced = dic.monospaced,
2802 }
2803 fontdata.cidinfo = cid and {
2804 registry = cid.registry,
2805 ordering = cid.ordering,
2806 supplement = cid.supplement,
2807 }
2808 fontdata.cffinfo = cffinfo
2809
2810 local all = specification.shapes or specification.streams or false
2811 if specification.glyphs or all then
2812 if cid and cid.fdselect then
2813 readfdselect(f,fontdata,data,glyphs,all,"cff",specification.streams)
2814 else
2815 readnoselect(f,fontdata,data,glyphs,all,"cff",specification.streams)
2816 end
2817 end
2818 local private = dic.private
2819 if private then
2820 local data = private.data
2821 if type(data) == "table" then
2822 cffinfo.defaultwidth = data.defaultwidthx or cffinfo.defaultwidth
2823 cffinfo.nominalwidth = data.nominalwidthx or cffinfo.nominalwidth
2824 cffinfo.bluevalues = data.bluevalues
2825 cffinfo.otherblues = data.otherblues
2826 cffinfo.familyblues = data.familyblues
2827 cffinfo.familyotherblues = data.familyotherblues
2828 cffinfo.bluescale = data.bluescale
2829 cffinfo.blueshift = data.blueshift
2830 cffinfo.bluefuzz = data.bluefuzz
2831 cffinfo.stdhw = data.stdhw
2832 cffinfo.stdvw = data.stdvw
2833 cffinfo.stemsnaph = data.stemsnaph
2834 cffinfo.stemsnapv = data.stemsnapv
2835 end
2836 end
2837 cleanup(data,dictionaries)
2838 end
2839end
2840
2841function readers.cff2(f,fontdata,specification)
2842 local tableoffset = gotodatatable(f,fontdata,"cff2",specification.glyphs)
2843 if tableoffset then
2844 local header = readheader(f)
2845 if header.major ~= 2 then
2846 report("only version %s is supported for table %a",2,"cff2")
2847 return
2848 end
2849 local glyphs = fontdata.glyphs
2850 local dictionaries = { readstring(f,header.dsize) }
2851 local data = {
2852 header = header,
2853 dictionaries = dictionaries,
2854 nofglyphs = fontdata.nofglyphs,
2855 }
2856
2857 parsedictionaries(data,dictionaries,"cff2")
2858
2859 local offset = dictionaries[1].vstore
2860 if offset > 0 then
2861 local storeoffset = dictionaries[1].vstore + data.header.offset + 2
2862 local regions, deltas = readers.helpers.readvariationdata(f,storeoffset,factors)
2863
2864 data.regions = regions
2865 data.deltas = deltas
2866 else
2867 data.regions = { }
2868 data.deltas = { }
2869 end
2870 data.factors = specification.factors
2871
2872 local cid = data.dictionaries[1].cid
2873 local all = specification.shapes or specification.streams or false
2874 if cid and cid.fdselect then
2875 readfdselect(f,fontdata,data,glyphs,all,"cff2",specification.streams)
2876 else
2877 readnoselect(f,fontdata,data,glyphs,all,"cff2",specification.streams)
2878 end
2879 cleanup(data,dictionaries)
2880 end
2881end
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920 |