diff options
author | Karl Berry <karl@freefriends.org> | 2016-01-23 22:23:23 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2016-01-23 22:23:23 +0000 |
commit | 1fe8051f9151dd435a55d4f5e0932fd0b37eea74 (patch) | |
tree | 8721d7ee24c405d10907428b3336cbda4a1f686c /Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-cff.lua | |
parent | 9e3236ef10e2f9ee8a507bd5f34b83eb8de9d2f7 (diff) |
luaotfload (22jan16)
git-svn-id: svn://tug.org/texlive/trunk@39466 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-cff.lua')
-rw-r--r-- | Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-cff.lua | 1697 |
1 files changed, 0 insertions, 1697 deletions
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-cff.lua b/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-cff.lua deleted file mode 100644 index 0314e4ac4a1..00000000000 --- a/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-cff.lua +++ /dev/null @@ -1,1697 +0,0 @@ -if not modules then modules = { } end modules ['font-cff'] = { - version = 1.001, - comment = "companion to font-ini.mkiv", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - --- todo: option.outlines --- todo: option.boundingbox --- per charstring (less memory) - --- This is a heavy one as it is a rather packed format. We don't need al the information --- now but we might need it later (who know what magic we can do with metapost). So at --- some point this might become a module. We just follow Adobe Technical Notes #5176 and --- #5177. In case of doubt I looked in the fontforge code that comes with LuaTeX. - --- For now we save the segments in a list of segments with the operator last in an entry --- because that reflects the original. But it might make more sense to use a single array --- per segment. For pdf a simple concat works ok, but for other purposes a operator first --- flush is nicer. - -local next, type, tonumber = next, type, tonumber -local byte = string.byte -local concat, remove = table.concat, table.remove -local floor, abs, round, ceil = math.floor, math.abs, math.round, math.ceil -local P, C, R, S, C, Cs, Ct = lpeg.P, lpeg.C, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpeg.Ct -local lpegmatch = lpeg.match - -local readers = fonts.handlers.otf.readers -local streamreader = readers.streamreader - -local readbytes = streamreader.readbytes -local readstring = streamreader.readstring -local readbyte = streamreader.readcardinal1 -- 8-bit unsigned integer -local readushort = streamreader.readcardinal2 -- 16-bit unsigned integer -local readuint = streamreader.readcardinal3 -- 24-bit unsigned integer -local readulong = streamreader.readcardinal4 -- 24-bit unsigned integer -local setposition = streamreader.setposition -local getposition = streamreader.getposition - -local setmetatableindex = table.setmetatableindex - -local trace_charstrings = false trackers.register("fonts.cff.charstrings",function(v) trace_charstrings = v end) -local report = logs.reporter("otf reader","cff") - -local parsedictionaries -local parsecharstring -local parsecharstrings -local resetcharstrings -local parseprivates - -local defaultstrings = { [0] = -- taken from ff - ".notdef", "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", - "ampersand", "quoteright", "parenleft", "parenright", "asterisk", "plus", - "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four", - "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", - "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", - "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", - "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", - "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", - "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", - "z", "braceleft", "bar", "braceright", "asciitilde", "exclamdown", "cent", - "sterling", "fraction", "yen", "florin", "section", "currency", - "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft", - "guilsinglright", "fi", "fl", "endash", "dagger", "daggerdbl", - "periodcentered", "paragraph", "bullet", "quotesinglbase", "quotedblbase", - "quotedblright", "guillemotright", "ellipsis", "perthousand", "questiondown", - "grave", "acute", "circumflex", "tilde", "macron", "breve", "dotaccent", - "dieresis", "ring", "cedilla", "hungarumlaut", "ogonek", "caron", "emdash", - "AE", "ordfeminine", "Lslash", "Oslash", "OE", "ordmasculine", "ae", - "dotlessi", "lslash", "oslash", "oe", "germandbls", "onesuperior", - "logicalnot", "mu", "trademark", "Eth", "onehalf", "plusminus", "Thorn", - "onequarter", "divide", "brokenbar", "degree", "thorn", "threequarters", - "twosuperior", "registered", "minus", "eth", "multiply", "threesuperior", - "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave", "Aring", - "Atilde", "Ccedilla", "Eacute", "Ecircumflex", "Edieresis", "Egrave", - "Iacute", "Icircumflex", "Idieresis", "Igrave", "Ntilde", "Oacute", - "Ocircumflex", "Odieresis", "Ograve", "Otilde", "Scaron", "Uacute", - "Ucircumflex", "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron", - "aacute", "acircumflex", "adieresis", "agrave", "aring", "atilde", - "ccedilla", "eacute", "ecircumflex", "edieresis", "egrave", "iacute", - "icircumflex", "idieresis", "igrave", "ntilde", "oacute", "ocircumflex", - "odieresis", "ograve", "otilde", "scaron", "uacute", "ucircumflex", - "udieresis", "ugrave", "yacute", "ydieresis", "zcaron", "exclamsmall", - "Hungarumlautsmall", "dollaroldstyle", "dollarsuperior", "ampersandsmall", - "Acutesmall", "parenleftsuperior", "parenrightsuperior", "twodotenleader", - "onedotenleader", "zerooldstyle", "oneoldstyle", "twooldstyle", - "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", - "sevenoldstyle", "eightoldstyle", "nineoldstyle", "commasuperior", - "threequartersemdash", "periodsuperior", "questionsmall", "asuperior", - "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior", - "lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior", - "tsuperior", "ff", "ffi", "ffl", "parenleftinferior", "parenrightinferior", - "Circumflexsmall", "hyphensuperior", "Gravesmall", "Asmall", "Bsmall", - "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", "Hsmall", "Ismall", - "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall", - "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall", - "Xsmall", "Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah", - "Tildesmall", "exclamdownsmall", "centoldstyle", "Lslashsmall", - "Scaronsmall", "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall", - "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior", - "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall", "oneeighth", - "threeeighths", "fiveeighths", "seveneighths", "onethird", "twothirds", - "zerosuperior", "foursuperior", "fivesuperior", "sixsuperior", - "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior", - "oneinferior", "twoinferior", "threeinferior", "fourinferior", - "fiveinferior", "sixinferior", "seveninferior", "eightinferior", - "nineinferior", "centinferior", "dollarinferior", "periodinferior", - "commainferior", "Agravesmall", "Aacutesmall", "Acircumflexsmall", - "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall", - "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", - "Igravesmall", "Iacutesmall", "Icircumflexsmall", "Idieresissmall", - "Ethsmall", "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", - "Otildesmall", "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", - "Uacutesmall", "Ucircumflexsmall", "Udieresissmall", "Yacutesmall", - "Thornsmall", "Ydieresissmall", "001.000", "001.001", "001.002", "001.003", - "Black", "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold", -} - -local cffreaders = { - readbyte, - readushort, - readuint, - readulong, -} - --- The header contains information about its own size. - -local function readheader(f) - local offset = getposition(f) - local header = { - offset = offset, - major = readbyte(f), - minor = readbyte(f), - size = readbyte(f), -- headersize - osize = readbyte(f), -- for offsets to start - } - setposition(f,offset+header.size) - return header -end - --- The indexes all look the same, so we share a loader. We could pass a handler --- and run over the array but why bother, we only have a few uses. - -local function readlengths(f) - local count = readushort(f) - if count == 0 then - return { } - end - local osize = readbyte(f) - local read = cffreaders[osize] - if not read then - report("bad offset size: %i",osize) - return { } - end - local lengths = { } - local previous = read(f) - for i=1,count do - local offset = read(f) - lengths[i] = offset - previous - previous = offset - end - return lengths -end - --- There can be subfonts so names is an array. However, in our case it's always --- one font. The same is true for the top dictionaries. Watch how we only load --- the dictionary string as for interpretation we need to have the strings loaded --- as well. - -local function readfontnames(f) - local names = readlengths(f) - for i=1,#names do - names[i] = readstring(f,names[i]) - end - return names -end - -local function readtopdictionaries(f) - local dictionaries = readlengths(f) - for i=1,#dictionaries do - dictionaries[i] = readstring(f,dictionaries[i]) - end - return dictionaries -end - --- Strings are added to a list of standard strings so we start the font specific --- one with an offset. Strings are shared so we have one table. - -local function readstrings(f) - local lengths = readlengths(f) - local strings = setmetatableindex({ }, defaultstrings) - local index = #defaultstrings - for i=1,#lengths do - index = index + 1 - strings[index] = readstring(f,lengths[i]) - end - return strings -end - --- Parsing the dictionaries is delayed till we have the strings loaded. The parser --- is stack based so the operands come before the operator (like in postscript). - --- local function delta(t) --- local n = #t --- if n > 1 then --- local p = t[1] --- for i=2,n do --- local c = t[i] --- t[i] = c + p --- p = c --- end --- end --- end - -do - - -- We use a closure so that we don't need to pass too much around. - - local stack = { } - local top = 0 - local result = { } - local strings = { } - - local p_single = - P("\00") / function() - result.version = strings[stack[top]] or "unset" - top = 0 - end - + P("\01") / function() - result.notice = strings[stack[top]] or "unset" - top = 0 - end - + P("\02") / function() - result.fullname = strings[stack[top]] or "unset" - top = 0 - end - + P("\03") / function() - result.familyname = strings[stack[top]] or "unset" - top = 0 - end - + P("\04") / function() - result.weight = strings[stack[top]] or "unset" - top = 0 - end - + P("\05") / function() - result.fontbbox = { unpack(stack,1,4) } - top = 0 - end - -- + P("\06") / function() end -- bluevalues - -- + P("\07") / function() end -- otherblues - -- + P("\08") / function() end -- familyblues - -- + P("\09") / function() end -- familyotherblues - -- + P("\10") / function() end -- strhw - -- + P("\11") / function() end -- stdvw - + P("\13") / function() - result.uniqueid = stack[top] - top = 0 - end - + P("\14") / function() - result.xuid = concat(stack,"",1,top) - top = 0 - end - + P("\15") / function() - result.charset = stack[top] - top = 0 - end - + P("\16") / function() - result.encoding = stack[top] - top = 0 - end - + P("\17") / function() - result.charstrings = stack[top] - top = 0 - end - + P("\18") / function() - result.private = { - size = stack[top-1], - offset = stack[top], - } - top = 0 - end - + P("\19") / function() - result.subroutines = stack[top] - end - + P("\20") / function() - result.defaultwidthx = stack[top] - end - + P("\21") / function() - result.nominalwidthx = stack[top] - end - -- + P("\22") / function() end -- reserved - -- + P("\23") / function() end -- reserved - -- + P("\24") / function() end -- reserved - -- + P("\25") / function() end -- reserved - -- + P("\26") / function() end -- reserved - -- + P("\27") / function() end -- reserved - - local p_double = P("\12") * ( - P("\00") / function() - result.copyright = stack[top] - top = 0 - end - + P("\01") / function() - result.monospaced = stack[top] == 1 and true or false -- isfixedpitch - top = 0 - end - + P("\02") / function() - result.italicangle = stack[top] - top = 0 - end - + P("\03") / function() - result.underlineposition = stack[top] - top = 0 - end - + P("\04") / function() - result.underlinethickness = stack[top] - top = 0 - end - + P("\05") / function() - result.painttype = stack[top] - top = 0 - end - + P("\06") / function() - result.charstringtype = stack[top] - top = 0 - end - + P("\07") / function() - result.fontmatrix = { unpack(stack,1,6) } - top = 0 - end - + P("\08") / function() - result.strokewidth = stack[top] - top = 0 - end - + P("\20") / function() - result.syntheticbase = stack[top] - top = 0 - end - + P("\21") / function() - result.postscript = strings[stack[top]] or "unset" - top = 0 - end - + P("\22") / function() - result.basefontname = strings[stack[top]] or "unset" - top = 0 - end - + P("\21") / function() - result.basefontblend = stack[top] - top = 0 - end - + P("\30") / function() - result.cid.registry = strings[stack[top-2]] or "unset" - result.cid.ordering = strings[stack[top-1]] or "unset" - result.cid.supplement = stack[top] - top = 0 - end - + P("\31") / function() - result.cid.fontversion = stack[top] - top = 0 - end - + P("\32") / function() - result.cid.fontrevision= stack[top] - top = 0 - end - + P("\33") / function() - result.cid.fonttype = stack[top] - top = 0 - end - + P("\34") / function() - result.cid.count = stack[top] - top = 0 - end - + P("\35") / function() - result.cid.uidbase = stack[top] - top = 0 - end - + P("\36") / function() - result.cid.fdarray = stack[top] - top = 0 - end - + P("\37") / function() - result.cid.fdselect = stack[top] - top = 0 - end - + P("\38") / function() - result.cid.fontname = strings[stack[top]] or "unset" - top = 0 - end - ) - - -- Some lpeg fun ... a first variant split the byte and made a new string but - -- the second variant is much faster. Not that it matters much as we don't see - -- such numbers often. - - local p_last = P("\x0F") / "0" + P("\x1F") / "1" + P("\x2F") / "2" + P("\x3F") / "3" - + P("\x4F") / "4" + P("\x5F") / "5" + P("\x6F") / "6" + P("\x7F") / "7" - + P("\x8F") / "8" + P("\x9F") / "9" + P("\xAF") / "" + P("\xBF") / "" - + P("\xCF") / "" + P("\xDF") / "" + P("\xEF") / "" + R("\xF0\xFF") / "" - - -- local remap = { [0] = - -- "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0.", "0E", "0E-", "0", "0-", "0", - -- "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "0.", "0E", "0E-", "0", "0-", "0", - -- "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "0.", "0E", "0E-", "0", "0-", "0", - -- "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "0.", "0E", "0E-", "0", "0-", "0", - -- "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "0.", "0E", "0E-", "0", "0-", "0", - -- "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "0.", "0E", "0E-", "0", "0-", "0", - -- "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "0.", "0E", "0E-", "0", "0-", "0", - -- "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "0.", "0E", "0E-", "0", "0-", "0", - -- "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "0.", "0E", "0E-", "0", "0-", "0", - -- "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "0.", "0E", "0E-", "0", "0-", "0", - -- ".0", ".1", ".2", ".3", ".4", ".5", ".6", ".7", ".8", ".9", "..", ".E", ".E-", ".", ".-", ".", - -- "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "E.", "EE", "EE-", "E", "E-", "E", - -- "E-0", "E-1", "E-2", "E-3", "E-4", "E-5", "E-6", "E-7", "E-8", "E-9", "E-.", "E-E", "E-E-", "E-", "E--", "E-", - -- "-0", "-1", "-2", "-3", "-4", "-5", "-6", "-7", "-8", "-9", "-.", "-E", "-E-", "-", "--", "-", - -- } - - -- local p_nibbles = Cs(((1-p_last)/byte/remap)^0+p_last) - - -- local p = P("\30") * p_nibbles / function(t) - -- print(tonumber(t)) - -- end - - local remap = { - ["\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", - ["\x10"] = "10", ["\x11"] = "11", ["\x12"] = "12", ["\x13"] = "13", ["\x14"] = "14", ["\x15"] = "15", ["\x16"] = "16", ["\x17"] = "17", ["\x18"] = "18", ["\x19"] = "19", ["\x1A"] = "0.", ["\x1B"] = "0E", ["\x1C"] = "0E-", ["\x1D"] = "0", ["\x1E"] = "0-", ["\x1F"] = "0", - ["\x20"] = "20", ["\x21"] = "21", ["\x22"] = "22", ["\x23"] = "23", ["\x24"] = "24", ["\x25"] = "25", ["\x26"] = "26", ["\x27"] = "27", ["\x28"] = "28", ["\x29"] = "29", ["\x2A"] = "0.", ["\x2B"] = "0E", ["\x2C"] = "0E-", ["\x2D"] = "0", ["\x2E"] = "0-", ["\x2F"] = "0", - ["\x30"] = "30", ["\x31"] = "31", ["\x32"] = "32", ["\x33"] = "33", ["\x34"] = "34", ["\x35"] = "35", ["\x36"] = "36", ["\x37"] = "37", ["\x38"] = "38", ["\x39"] = "39", ["\x3A"] = "0.", ["\x3B"] = "0E", ["\x3C"] = "0E-", ["\x3D"] = "0", ["\x3E"] = "0-", ["\x3F"] = "0", - ["\x40"] = "40", ["\x41"] = "41", ["\x42"] = "42", ["\x43"] = "43", ["\x44"] = "44", ["\x45"] = "45", ["\x46"] = "46", ["\x47"] = "47", ["\x48"] = "48", ["\x49"] = "49", ["\x4A"] = "0.", ["\x4B"] = "0E", ["\x4C"] = "0E-", ["\x4D"] = "0", ["\x4E"] = "0-", ["\x4F"] = "0", - ["\x50"] = "50", ["\x51"] = "51", ["\x52"] = "52", ["\x53"] = "53", ["\x54"] = "54", ["\x55"] = "55", ["\x56"] = "56", ["\x57"] = "57", ["\x58"] = "58", ["\x59"] = "59", ["\x5A"] = "0.", ["\x5B"] = "0E", ["\x5C"] = "0E-", ["\x5D"] = "0", ["\x5E"] = "0-", ["\x5F"] = "0", - ["\x60"] = "60", ["\x61"] = "61", ["\x62"] = "62", ["\x63"] = "63", ["\x64"] = "64", ["\x65"] = "65", ["\x66"] = "66", ["\x67"] = "67", ["\x68"] = "68", ["\x69"] = "69", ["\x6A"] = "0.", ["\x6B"] = "0E", ["\x6C"] = "0E-", ["\x6D"] = "0", ["\x6E"] = "0-", ["\x6F"] = "0", - ["\x70"] = "70", ["\x71"] = "71", ["\x72"] = "72", ["\x73"] = "73", ["\x74"] = "74", ["\x75"] = "75", ["\x76"] = "76", ["\x77"] = "77", ["\x78"] = "78", ["\x79"] = "79", ["\x7A"] = "0.", ["\x7B"] = "0E", ["\x7C"] = "0E-", ["\x7D"] = "0", ["\x7E"] = "0-", ["\x7F"] = "0", - ["\x80"] = "80", ["\x81"] = "81", ["\x82"] = "82", ["\x83"] = "83", ["\x84"] = "84", ["\x85"] = "85", ["\x86"] = "86", ["\x87"] = "87", ["\x88"] = "88", ["\x89"] = "89", ["\x8A"] = "0.", ["\x8B"] = "0E", ["\x8C"] = "0E-", ["\x8D"] = "0", ["\x8E"] = "0-", ["\x8F"] = "0", - ["\x90"] = "90", ["\x91"] = "91", ["\x92"] = "92", ["\x93"] = "93", ["\x94"] = "94", ["\x95"] = "95", ["\x96"] = "96", ["\x97"] = "97", ["\x98"] = "98", ["\x99"] = "99", ["\x9A"] = "0.", ["\x9B"] = "0E", ["\x9C"] = "0E-", ["\x9D"] = "0", ["\x9E"] = "0-", ["\x9F"] = "0", - ["\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"] = ".", - ["\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", - ["\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-", - ["\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"] = "-", - } - - local p_nibbles = P("\30") * Cs(((1-p_last)/remap)^0+p_last) / function(n) - -- 0-9=digit a=. b=E c=E- d=reserved e=- f=finish - top = top + 1 - stack[top] = tonumber(n) or 0 - end - - local p_byte = C(R("\32\246")) / function(b0) - -- -107 .. +107 - top = top + 1 - stack[top] = byte(b0) - 139 - end - - local p_positive = C(R("\247\250")) * C(1) / function(b0,b1) - -- +108 .. +1131 - top = top + 1 - stack[top] = (byte(b0)-247)*256 + byte(b1) + 108 - end - - local p_negative = C(R("\251\254")) * C(1) / function(b0,b1) - -- -1131 .. -108 - top = top + 1 - stack[top] = -(byte(b0)-251)*256 - byte(b1) - 108 - end - - local p_short = P("\28") * C(1) * C(1) / function(b1,b2) - -- -32768 .. +32767 : b1<<8 | b2 - top = top + 1 - local n = 0x100 * byte(b1) + byte(b2) - if n >= 0x8000 then - stack[top] = n - 0xFFFF - 1 - else - stack[top] = n - end - end - - local p_long = P("\29") * C(1) * C(1) * C(1) * C(1) / function(b1,b2,b3,b4) - -- -2^31 .. +2^31-1 : b1<<24 | b2<<16 | b3<<8 | b4 - top = top + 1 - local n = 0x1000000 * byte(b1) + 0x10000 * byte(b2) + 0x100 * byte(b3) + byte(b4) - if n >= 0x8000000 then - stack[top] = n - 0xFFFFFFFF - 1 - else - stack[top] = n - end - end - - local p_unsupported = P(1) / function(detail) - top = 0 - end - - local p_dictionary = ( - p_byte - + p_positive - + p_negative - + p_short - + p_long - + p_nibbles - + p_single - + p_double - + p_unsupported - )^1 - - parsedictionaries = function(data,dictionaries) - stack = { } - strings = data.strings - for i=1,#dictionaries do - top = 0 - result = { - monospaced = false, - italicangle = 0, - underlineposition = -100, - underlinethickness = 50, - painttype = 0, - charstringtype = 2, - fontmatrix = { 0.001, 0, 0, 0.001, 0, 0 }, - fontbbox = { 0, 0, 0, 0 }, - strokewidth = 0, - charset = 0, - encoding = 0, - cid = { - fontversion = 0, - fontrevision = 0, - fonttype = 0, - count = 8720, - } - } - lpegmatch(p_dictionary,dictionaries[i]) - dictionaries[i] = result - end - -- - result = { } - top = 0 - stack = { } - end - - parseprivates = function(data,dictionaries) - stack = { } - strings = data.strings - for i=1,#dictionaries do - local private = dictionaries[i].private - if private and private.data then - top = 0 - result = { - forcebold = false, - languagegroup = 0, - expansionfactor = 0.06, - initialrandomseed = 0, - subroutines = 0, - defaultwidthx = 0, - nominalwidthx = 0, - cid = { - -- actually an error - }, - } - lpegmatch(p_dictionary,private.data) - private.data = result - end - end - result = { } - top = 0 - stack = { } - end - - -- All bezier curves have 6 points with successive pairs relative to - -- the previous pair. Some can be left out and are then copied or zero - -- (optimization). - -- - -- We are not really interested in all the details of a glyph because we - -- only need to calculate the boundingbox. So, todo: a quick no result but - -- calculate only variant. - -- - -- The conversion is straightforward and the specification os clear once - -- you understand that the x and y needs to be updates each step. It's also - -- quite easy to test because in mp a shape will look bad when a few variables - -- are swapped. But still there might be bugs down here because not all - -- variants are seen in a font so far. We are less compact that the ff code - -- because there quite some variants are done in one helper with a lot of - -- testing for states. - - local x = 0 - local y = 0 - local width = false - local r = 0 - local stems = 0 - local globalbias = 0 - local localbias = 0 - local globals = false - local locals = false - local depth = 1 - local xmin = 0 - local xmax = 0 - local ymin = 0 - local ymax = 0 - local checked = false - local keepcurve = false - - local function showstate(where) - report("%w%-10s : [%s] n=%i",depth*2,where,concat(stack," ",1,top),top) - end - - local function showvalue(where,value,showstack) - if showstack then - report("%w%-10s : %s : [%s] n=%i",depth*2,where,tostring(value),concat(stack," ",1,top),top) - else - report("%w%-10s : %s",depth*2,where,tostring(value)) - end - end - - -- All these indirect calls make this run slower but it's cleaner this way - -- and we cache the result. As we moved the boundingbox code inline we gain - -- some back. - - local function moveto(x,y) - if keepcurve then - r = r + 1 - result[r] = { x, y, "m" } - end - if checked then - if x < xmin then xmin = x elseif x > xmax then xmax = x end - if y < ymin then ymin = y elseif y > ymax then ymax = y end - else - xmin = x - ymin = y - xmax = x - ymax = y - checked = true - end - end - - local function lineto(x,y) - if keepcurve then - r = r + 1 - result[r] = { x, y, "l" } - end - if checked then - if x < xmin then xmin = x elseif x > xmax then xmax = x end - if y < ymin then ymin = y elseif y > ymax then ymax = y end - else - xmin = x - ymin = y - xmax = x - ymax = y - checked = true - end - end - - local function curveto(x1,y1,x2,y2,x3,y3) - if keepcurve then - r = r + 1 - result[r] = { x1, y1, x2, y2, x3, y3, "c" } - end - if checked then - if x1 < xmin then xmin = x1 elseif x1 > xmax then xmax = x1 end - if y1 < ymin then ymin = y1 elseif y1 > ymax then ymax = y1 end - else - xmin = x1 - ymin = y1 - xmax = x1 - ymax = y1 - checked = true - end - if x2 < xmin then xmin = x2 elseif x2 > xmax then xmax = x2 end - if y2 < ymin then ymin = y2 elseif y2 > ymax then ymax = y2 end - if x3 < xmin then xmin = x3 elseif x3 > xmax then xmax = x3 end - if y3 < ymin then ymin = y3 elseif y3 > ymax then ymax = y3 end - end - - local function rmoveto() - if top > 2 then - if not width then - width = stack[1] - if trace_charstrings then - showvalue("width",width) - end - end - elseif not width then - width = true - end - if trace_charstrings then - showstate("rmoveto") - end - x = x + stack[top-1] -- dx1 - y = y + stack[top] -- dy1 - top = 0 - moveto(x,y) - end - - local function hmoveto() - if top > 1 then - if not width then - width = stack[1] - if trace_charstrings then - showvalue("width",width) - end - end - elseif not width then - width = true - end - if trace_charstrings then - showstate("hmoveto") - end - x = x + stack[top] -- dx1 - top = 0 - moveto(x,y) - end - - local function vmoveto() - if top > 1 then - if not width then - width = stack[1] - if trace_charstrings then - showvalue("width",width) - end - end - elseif not width then - width = true - end - if trace_charstrings then - showstate("vmoveto") - end - y = y + stack[top] -- dy1 - top = 0 - moveto(x,y) - end - - local function rlineto() - if trace_charstrings then - showstate("rlineto") - end - for i=1,top,2 do - x = x + stack[i] -- dxa - y = y + stack[i+1] -- dya - lineto(x,y) - end - top = 0 - end - - local function xlineto(swap) -- x (y,x)+ | (x,y)+ - for i=1,top do - if swap then - x = x + stack[i] - swap = false - else - y = y + stack[i] - swap = true - end - lineto(x,y) - end - top = 0 - end - - local function hlineto() -- x (y,x)+ | (x,y)+ - if trace_charstrings then - showstate("hlineto") - end - xlineto(true) - end - - local function vlineto() -- y (x,y)+ | (y,x)+ - if trace_charstrings then - showstate("vlineto") - end - xlineto(false) - end - - local function rrcurveto() - if trace_charstrings then - showstate("rrcurveto") - end - for i=1,top,6 do - local ax = x + stack[i] -- dxa - local ay = y + stack[i+1] -- dya - local bx = ax + stack[i+2] -- dxb - local by = ay + stack[i+3] -- dyb - x = bx + stack[i+4] -- dxc - y = by + stack[i+5] -- dyc - curveto(ax,ay,bx,by,x,y) - end - top = 0 - end - - local function hhcurveto() - if trace_charstrings then - showstate("hhcurveto") - end - local s = 1 - if top % 2 ~= 0 then - y = y + stack[1] -- dy1 - s = 2 - end - for i=s,top,4 do - local ax = x + stack[i] -- dxa - local ay = y - local bx = ax + stack[i+1] -- dxb - local by = ay + stack[i+2] -- dyb - x = bx + stack[i+3] -- dxc - y = by - curveto(ax,ay,bx,by,x,y) - end - top = 0 - end - - local function vvcurveto() - if trace_charstrings then - showstate("vvcurveto") - end - local s = 1 - local d = 0 - if top % 2 ~= 0 then - d = stack[1] -- dx1 - s = 2 - end - for i=s,top,4 do - local ax = x + d - local ay = y + stack[i] -- dya - local bx = ax + stack[i+1] -- dxb - local by = ay + stack[i+2] -- dyb - x = bx - y = by + stack[i+3] -- dyc - curveto(ax,ay,bx,by,x,y) - d = 0 - end - top = 0 - end - - local function xxcurveto(swap) - local last = top % 4 ~= 0 and stack[top] - if last then - top = top - 1 - end - local sw = swap - for i=1,top,4 do - local ax, ay, bx, by - if swap then - ax = x + stack[i] - ay = y - bx = ax + stack[i+1] - by = ay + stack[i+2] - y = by + stack[i+3] - if last and i+3 == top then - x = bx + last - else - x = bx - end - swap = false - else - ax = x - ay = y + stack[i] - bx = ax + stack[i+1] - by = ay + stack[i+2] - x = bx + stack[i+3] - if last and i+3 == top then - y = by + last - else - y = by - end - swap = true - end - curveto(ax,ay,bx,by,x,y) - end - top = 0 - end - - local function hvcurveto() - if trace_charstrings then - showstate("hvcurveto") - end - xxcurveto(true) - end - - local function vhcurveto() - if trace_charstrings then - showstate("vhcurveto") - end - xxcurveto(false) - end - - local function rcurveline() - if trace_charstrings then - showstate("rcurveline") - end - for i=1,top-2,6 do - local ax = x + stack[i] -- dxa - local ay = y + stack[i+1] -- dya - local bx = ax + stack[i+2] -- dxb - local by = ay + stack[i+3] -- dyb - x = bx + stack[i+4] -- dxc - y = by + stack[i+5] -- dyc - curveto(ax,ay,bx,by,x,y) - end - x = x + stack[top-1] -- dxc - y = y + stack[top] -- dyc - lineto(x,y) - top = 0 - end - - local function rlinecurve() - if trace_charstrings then - showstate("rlinecurve") - end - if top > 6 then - for i=1,top-6,2 do - x = x + stack[i] - y = y + stack[i+1] - lineto(x,y) - end - end - local ax = x + stack[top-5] - local ay = y + stack[top-4] - local bx = ax + stack[top-3] - local by = ay + stack[top-2] - x = bx + stack[top-1] - y = by + stack[top] - curveto(ax,ay,bx,by,x,y) - top = 0 - end - - -- flex is not yet tested! no loop - - local function flex() -- fd not used - if trace_charstrings then - showstate("flex") - end - local ax = x + stack[1] -- dx1 - local ay = y + stack[2] -- dy1 - local bx = ax + stack[3] -- dx2 - local by = ay + stack[4] -- dy2 - local cx = bx + stack[5] -- dx3 - local cy = by + stack[6] -- dy3 - curveto(ax,ay,bx,by,cx,cy) - local dx = cx + stack[7] -- dx4 - local dy = cy + stack[8] -- dy4 - local ex = dx + stack[9] -- dx5 - local ey = dy + stack[10] -- dy5 - x = ex + stack[11] -- dx6 - y = ey + stack[12] -- dy6 - curveto(dx,dy,ex,ey,x,y) - top = 0 - end - - local function hflex() - if trace_charstrings then - showstate("hflex") - end - local ax = x + stack[1] -- dx1 - local ay = y - local bx = ax + stack[2] -- dx2 - local by = ay + stack[3] -- dy2 - local cx = bx + stack[4] -- dx3 - local cy = by - curveto(ax,ay,bx,by,cx,cy) - local dx = cx + stack[5] -- dx4 - local dy = by - local ex = dx + stack[6] -- dx5 - local ey = y - x = ex + stack[7] -- dx6 - curveto(dx,dy,ex,ey,x,y) - top = 0 - end - - local function hflex1() - if trace_charstrings then - showstate("hflex1") - end - local ax = x + stack[1] -- dx1 - local ay = y + stack[2] -- dy1 - local bx = ax + stack[3] -- dx2 - local by = ay + stack[4] -- dy2 - local cx = bx + stack[5] -- dx3 - local cy = by - curveto(ax,ay,bx,by,cx,cy) - local dx = cx + stack[6] -- dx4 - local dy = by - local ex = dx + stack[7] -- dx5 - local ey = dy + stack[8] -- dy5 - x = ex + stack[9] -- dx6 - curveto(dx,dy,ex,ey,x,y) - top = 0 - end - - local function flex1() - if trace_charstrings then - showstate("flex1") - end - local ax = x + stack[1] --dx1 - local ay = y + stack[2] --dy1 - local bx = ax + stack[3] --dx2 - local by = ay + stack[4] --dy2 - local cx = bx + stack[5] --dx3 - local cy = by + stack[6] --dy3 - curveto(ax,ay,bx,by,cx,cy) - local dx = cx + stack[7] --dx4 - local dy = cy + stack[8] --dy4 - local ex = dx + stack[9] --dx5 - local ey = dy + stack[10] --dy5 - if abs(ex - x) > abs(ey - y) then -- spec: abs(dx) > abs(dy) - x = ex + stack[11] - else - y = ey + stack[11] - end - curveto(dx,dy,ex,ey,x,y) - top = 0 - end - - local function getstem() - if top == 0 then - -- bad - elseif top % 2 ~= 0 then - if width then - remove(stack,1) - else - width = remove(stack,1) - if trace_charstrings then - showvalue("width",width) - end - end - top = top - 1 - end - if trace_charstrings then - showstate("stem") - end - stems = stems + top/2 - top = 0 - end - - local function getmask() - if top == 0 then - -- bad - elseif top % 2 ~= 0 then - if width then - remove(stack,1) - else - width = remove(stack,1) - if trace_charstrings then - showvalue("width",width) - end - end - top = top - 1 - end - if trace_charstrings then - showstate(operator == 19 and "hintmark" or "cntrmask") - end - stems = stems + top/2 - top = 0 - if stems == 0 then - -- forget about it - elseif stems <= 8 then - return 1 - else - return floor((stems+7)/8) - end - end - - local function unsupported() - if trace_charstrings then - showstate("unsupported") - end - top = 0 - end - - -- Bah, we cannot use a fast lpeg because a hint has an unknown size and a - -- runtime capture cannot handle that well. - - local actions = { [0] = - unsupported, -- 0 - getstem, -- 1 -- hstem - unsupported, -- 2 - getstem, -- 3 -- vstem - vmoveto, -- 4 - rlineto, -- 5 - hlineto, -- 6 - vlineto, -- 7 - rrcurveto, -- 8 - unsupported, -- 9 -- closepath - unsupported, -- 10 -- calllocal, - unsupported, -- 11 -- callreturn, - unsupported, -- 12 -- elsewhere - unsupported, -- 13 -- hsbw - unsupported, -- 14 -- endchar, - unsupported, -- 15 - unsupported, -- 16 - unsupported, -- 17 - getstem, -- 18 -- hstemhm - getmask, -- 19 -- hintmask - getmask, -- 20 -- cntrmask - rmoveto, -- 21 - hmoveto, -- 22 - getstem, -- 23 -- vstemhm - rcurveline, -- 24 - rlinecurve, -- 25 - vvcurveto, -- 26 - hhcurveto, -- 27 - unsupported, -- 28 -- elsewhere - unsupported, -- 29 -- elsewhere - vhcurveto, -- 30 - hvcurveto, -- 31 - } - - local subactions = { - [034] = hflex, - [035] = flex, - [036] = hflex1, - [037] = flex1, - } - - local p_bytes = Ct((P(1)/byte)^0) - - local function call(scope,list,bias,process) - local index = stack[top] + bias - top = top - 1 - if trace_charstrings then - showvalue(scope,index,true) - end - local str = list[index] - if str then - if type(str) == "string" then - str = lpegmatch(p_bytes,str) - list[index] = str - end - depth = depth + 1 - process(str) - depth = depth - 1 - else - report("unknown %s %i",scope,index) - end - end - - local function process(tab) - local i = 1 - local n = #tab - while i <= n do - local t = tab[i] - if t >= 32 and t<=246 then - -- -107 .. +107 - top = top + 1 - stack[top] = t - 139 - i = i + 1 - elseif t >= 247 and t <= 250 then - -- +108 .. +1131 - top = top + 1 - stack[top] = (t-247)*256 + tab[i+1] + 108 - i = i + 2 - elseif t >= 251 and t <= 254 then - -- -1131 .. -108 - top = top + 1 - stack[top] = -(t-251)*256 - tab[i+1] - 108 - i = i + 2 - elseif t == 28 then - -- -32768 .. +32767 : b1<<8 | b2 - top = top + 1 - local n = 0x100 * tab[i+1] + tab[i+2] - if n >= 0x8000 then - stack[top] = n - 0xFFFF - 1 - else - stack[top] = n - end - i = i + 3 - elseif t == 255 then - local n = 0x100 * tab[i+1] + tab[i+2] - top = top + 1 - if n >= 0x8000 then - stack[top] = n - 0xFFFF - 1 + (0x100 * tab[i+3] + tab[i+4])/0xFFFF - else - stack[top] = n + (0x100 * tab[i+3] + tab[i+4])/0xFFFF - end - i = i + 5 - elseif t == 11 then - if trace_charstrings then - showstate("return") - end - return - elseif t == 10 then - call("local",locals,localbias,process) - i = i + 1 - elseif t == 14 then -- endchar - if width then - -- okay - elseif top > 0 then - width = stack[1] - if trace_charstrings then - showvalue("width",width) - end - else - width = true - end - if trace_charstrings then - showstate("endchar") - end - return - elseif t == 29 then - call("global",globals,globalbias,process) - i = i + 1 - elseif t == 12 then - i = i + 1 - local t = tab[i] - local a = subactions[t] - if a then - a() - else - if trace_charstrings then - showvalue("<subaction>",t) - end - top = 0 - end - i = i + 1 - else - local a = actions[t] - if a then - local s = a() - if s then - i = i + s - end - else - if trace_charstrings then - showvalue("<action>",t) - end - top = 0 - end - i = i + 1 - end - end - end - - -- local function calculatebounds(segments,x,y) - -- local nofsegments = #segments - -- if nofsegments == 0 then - -- return { x, y, x, y } - -- else - -- local xmin = 10000 - -- local xmax = -10000 - -- local ymin = 10000 - -- local ymax = -10000 - -- if x < xmin then xmin = x end - -- if x > xmax then xmax = x end - -- if y < ymin then ymin = y end - -- if y > ymax then ymax = y end - -- -- we now have a reasonable start so we could - -- -- simplyfy the next checks - -- for i=1,nofsegments do - -- local s = segments[i] - -- local x = s[1] - -- local y = s[2] - -- if x < xmin then xmin = x end - -- if x > xmax then xmax = x end - -- if y < ymin then ymin = y end - -- if y > ymax then ymax = y end - -- if s[#s] == "c" then -- "curveto" - -- local x = s[3] - -- local y = s[4] - -- if x < xmin then xmin = x elseif x > xmax then xmax = x end - -- if y < ymin then ymin = y elseif y > ymax then ymax = y end - -- local x = s[5] - -- local y = s[6] - -- if x < xmin then xmin = x elseif x > xmax then xmax = x end - -- if y < ymin then ymin = y elseif y > ymax then ymax = y end - -- end - -- end - -- return { round(xmin), round(ymin), round(xmax), round(ymax) } -- doesn't make ceil more sense - -- end - -- end - - parsecharstrings = function(data,glyphs,doshapes) - -- for all charstrings - local dictionary = data.dictionaries[1] - local charstrings = dictionary.charstrings - local charset = dictionary.charset - keepcurve = doshapes - stack = { } - glyphs = glyphs or { } - strings = data.strings - locals = dictionary.subroutines - globals = data.routines - globalbias = #globals - localbias = #locals - globalbias = ((globalbias < 1240 and 107) or (globalbias < 33900 and 1131) or 32768) + 1 - localbias = ((localbias < 1240 and 107) or (localbias < 33900 and 1131) or 32768) + 1 - local nominalwidth = dictionary.private.data.nominalwidthx or 0 - local defaultwidth = dictionary.private.data.defaultwidthx or 0 - - for i=1,#charstrings do - local str = charstrings[i] - local tab = lpegmatch(p_bytes,str) - local index = i - 1 - x = 0 - y = 0 - width = false - r = 0 - top = 0 - stems = 0 - result = { } - -- - xmin = 0 - xmax = 0 - ymin = 0 - ymax = 0 - checked = false - -- - if trace_charstrings then - report("glyph: %i",index) - report("data: % t",tab) - end - -- - process(tab) - -- - local boundingbox = { round(xmin), round(ymin), round(xmax), round(ymax) } - -- - if width == true or width == false then - width = defaultwidth - else - width = nominalwidth + width - end - -- - -- trace_charstrings = index == 3078 -- todo: make tracker - local glyph = glyphs[index] -- can be autodefined in otr - if not glyph then - glyphs[index] = { - segments = doshapes ~= false and result or nil, -- optional - boundingbox = boundingbox, - width = width, - name = charset[index], - -- sidebearing = 0, - } - else - glyph.segments = doshapes ~= false and result or nil - glyph.boundingbox = boundingbox - if not glyph.width then - glyph.width = width - end - if charset and not glyph.name then - glyph.name = charset[index] - end - -- glyph.sidebearing = 0 -- todo - end - if trace_charstrings then - report("width: %s",tostring(width)) - report("boundingbox: % t",boundingbox) - end - charstrings[i] = nil -- free memory - end - return glyphs - end - - parsecharstring = function(data,dictionary,charstring,glyphs,index,doshapes) - local private = dictionary.private - keepcurve = doshapes - strings = data.strings -- or in dict? - locals = dictionary.subroutines or { } - globals = data.routines or { } - globalbias = #globals - localbias = #locals - globalbias = ((globalbias < 1240 and 107) or (globalbias < 33900 and 1131) or 32768) + 1 - localbias = ((localbias < 1240 and 107) or (localbias < 33900 and 1131) or 32768) + 1 - local nominalwidth = private and private.data.nominalwidthx or 0 - local defaultwidth = private and private.data.defaultwidthx or 0 - -- - local tab = lpegmatch(p_bytes,charstring) - x = 0 - y = 0 - width = false - r = 0 - top = 0 - stems = 0 - result = { } - -- - xmin = 0 - xmax = 0 - ymin = 0 - ymax = 0 - checked = false - -- - if trace_charstrings then - report("glyph: %i",index) - report("data: % t",tab) - end - -- - process(tab) - -- - local boundingbox = { xmin, ymin, xmax, ymax } - -- - if width == true or width == false then - width = defaultwidth - else - width = nominalwidth + width - end - -- - local glyph = glyphs[index] -- can be autodefined in otr - if not glyph then - glyphs[index] = { - segments = doshapes ~= false and result or nil, -- optional - boundingbox = boundingbox, - width = width, - name = charset[index], - -- sidebearing = 0, - } - else - glyph.segments = doshapes ~= false and result or nil - glyph.boundingbox = boundingbox - if not glyph.width then - glyph.width = width - end - if charset and not glyph.name then - glyph.name = charset[index] - end - -- glyph.sidebearing = 0 -- todo - end - -- - if trace_charstrings then - report("width: %s",tostring(width)) - report("boundingbox: % t",boundingbox) - end - -- - return charstring - end - - resetcharstrings = function() - result = { } - top = 0 - stack = { } - end - -end - -local function readglobals(f,data) - local routines = readlengths(f) - for i=1,#routines do - routines[i] = readstring(f,routines[i]) - end - data.routines = routines -end - -local function readencodings(f,data) - data.encodings = { } -end - -local function readcharsets(f,data,dictionary) - local header = data.header - local strings = data.strings - local nofglyphs = data.nofglyphs - local charsetoffset = dictionary.charset - - if charsetoffset ~= 0 then - setposition(f,header.offset+charsetoffset) - local format = readbyte(f) - local charset = { [0] = ".notdef" } - dictionary.charset = charset - if format == 0 then - for i=1,nofglyphs do - charset[i] = strings[readushort(f)] - end - elseif format == 1 or format == 2 then - local readcount = format == 1 and readbyte or readushort - local i = 1 - while i <= nofglyphs do - local sid = readushort(f) - local n = readcount(f) - for s=sid,sid+n do - charset[i] = strings[s] - i = i + 1 - if i > nofglyphs then - break - end - end - end - else - report("cff parser: unsupported charset format %a",format) - end - end -end - -local function readprivates(f,data) - local header = data.header - local dictionaries = data.dictionaries - local private = dictionaries[1].private - if private then - setposition(f,header.offset+private.offset) - private.data = readstring(f,private.size) - end -end - -local function readlocals(f,data,dictionary) - local header = data.header - local private = dictionary.private - if private then - local subroutineoffset = private.data.subroutines - if subroutineoffset ~= 0 then - setposition(f,header.offset+private.offset+subroutineoffset) - local subroutines = readlengths(f) - for i=1,#subroutines do - subroutines[i] = readstring(f,subroutines[i]) - end - dictionary.subroutines = subroutines - private.data.subroutines = nil - else - dictionary.subroutines = { } - end - else - dictionary.subroutines = { } - end -end - --- These charstrings are little programs and described in: Technical Note #5177. A truetype --- font has only one dictionary. - -local function readcharstrings(f,data) - local header = data.header - local dictionaries = data.dictionaries - local dictionary = dictionaries[1] - local type = dictionary.charstringtype - local offset = dictionary.charstrings - if type == 2 then - setposition(f,header.offset+offset) - -- could be a metatable .. delayed loading - local charstrings = readlengths(f) - local nofglyphs = #charstrings - for i=1,nofglyphs do - charstrings[i] = readstring(f,charstrings[i]) - end - data.nofglyphs = nofglyphs - dictionary.charstrings = charstrings - else - report("unsupported charstr type %i",type) - data.nofglyphs = 0 - dictionary.charstrings = { } - end -end - --- cid (maybe do this stepwise so less mem) -- share with above - -local function readcidprivates(f,data) - local header = data.header - local dictionaries = data.dictionaries[1].cid.dictionaries - for i=1,#dictionaries do - local dictionary = dictionaries[i] - local private = dictionary.private - if private then - setposition(f,header.offset+private.offset) - private.data = readstring(f,private.size) - end - end - parseprivates(data,dictionaries) -end - -local function readnoselect(f,data,glyphs,doshapes) - local dictionaries = data.dictionaries - local dictionary = dictionaries[1] - readglobals(f,data) - readcharstrings(f,data) - readencodings(f,data) - readcharsets(f,data,dictionary) - readprivates(f,data) - parseprivates(data,data.dictionaries) - readlocals(f,data,dictionary) - parsecharstrings(data,glyphs,doshapes) - resetcharstrings() -end - -local function readfdselect(f,data,glyphs,doshapes) - local header = data.header - local dictionaries = data.dictionaries - local dictionary = dictionaries[1] - local cid = dictionary.cid - local cidselect = cid and cid.fdselect - readglobals(f,data) - readcharstrings(f,data) - readencodings(f,data) - local charstrings = dictionary.charstrings - local fdindex = { } - local nofglyphs = data.nofglyphs - local maxindex = -1 - setposition(f,header.offset+cidselect) - local format = readbyte(f) - if format == 1 then - for i=0,nofglyphs do -- notdef included (needs checking) - local index = readbyte(i) - fdindex[i] = index - if index > maxindex then - maxindex = index - end - end - elseif format == 3 then - local nofranges = readushort(f) - local first = readushort(f) - local index = readbyte(f) - while true do - local last = readushort(f) - if index > maxindex then - maxindex = index - end - for i=first,last do - fdindex[i] = index - end - if last >= nofglyphs then - break - else - first = last + 1 - index = readbyte(f) - end - end - else - -- unsupported format - end - if maxindex >= 0 then - local cidarray = cid.fdarray - setposition(f,header.offset+cidarray) - local dictionaries = readlengths(f) - for i=1,#dictionaries do - dictionaries[i] = readstring(f,dictionaries[i]) - end - parsedictionaries(data,dictionaries) - cid.dictionaries = dictionaries - readcidprivates(f,data) - for i=1,#dictionaries do - readlocals(f,data,dictionaries[i]) - end - for i=1,#charstrings do - parsecharstring(data,dictionaries[fdindex[i]+1],charstrings[i],glyphs,i,doshapes) - end - resetcharstrings() - end -end - -function readers.cff(f,fontdata,specification) --- if specification.glyphs then - if specification.details then - local datatable = fontdata.tables.cff - if datatable then - local offset = datatable.offset - local glyphs = fontdata.glyphs - if not f then - report("invalid filehandle") - return - end - if offset then - setposition(f,offset) - end - local header = readheader(f) - if header.major > 1 then - report("version mismatch") - return - end - local names = readfontnames(f) - local dictionaries = readtopdictionaries(f) - local strings = readstrings(f) - local data = { - header = header, - names = names, - dictionaries = dictionaries, - strings = strings, - nofglyphs = fontdata.nofglyphs, - } - -- - parsedictionaries(data,data.dictionaries) - -- - local d = dictionaries[1] - local c = d.cid - fontdata.cffinfo = { - familynamename = d.familyname, - fullname = d.fullname, - boundingbox = d.boundingbox, - weight = d.weight, - italicangle = d.italicangle, - underlineposition = d.underlineposition, - underlinethickness = d.underlinethickness, - monospaced = d.monospaced, - } - fontdata.cidinfo = c and { - registry = c.registry, - ordering = c.ordering, - supplement = c.supplement, - } - -- - if not specification.glyphs then - -- we only want some metadata - else - local cid = d.cid - if cid and cid.fdselect then - readfdselect(f,data,glyphs,specification.shapes or false) - else - readnoselect(f,data,glyphs,specification.shapes or false) - end - end - -- - -- cleanup (probably more can go) - -- - -- for i=1,#dictionaries do - -- local d = dictionaries[i] - -- d.subroutines = nil - -- end - -- data.strings = nil - -- if data then - -- data.charstrings = nil - -- data.routines = nil - -- end - end - end -end |