summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-cff.lua
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2016-01-23 22:23:23 +0000
committerKarl Berry <karl@freefriends.org>2016-01-23 22:23:23 +0000
commit1fe8051f9151dd435a55d4f5e0932fd0b37eea74 (patch)
tree8721d7ee24c405d10907428b3336cbda4a1f686c /Master/texmf-dist/tex/luatex/luaotfload/fontloader-font-cff.lua
parent9e3236ef10e2f9ee8a507bd5f34b83eb8de9d2f7 (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.lua1697
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