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