diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkiv/font-cff.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/mkiv/font-cff.lua | 340 |
1 files changed, 231 insertions, 109 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-cff.lua b/Master/texmf-dist/tex/context/base/mkiv/font-cff.lua index 46deedb5f93..72b0a038f17 100644 --- a/Master/texmf-dist/tex/context/base/mkiv/font-cff.lua +++ b/Master/texmf-dist/tex/context/base/mkiv/font-cff.lua @@ -27,7 +27,7 @@ if not modules then modules = { } end modules ['font-cff'] = { -- the other hand, we can now feed back cff2 stuff. local next, type, tonumber, rawget = next, type, tonumber, rawget -local byte, char, gmatch = string.byte, string.char, string.gmatch +local byte, char, gmatch, sub = string.byte, string.char, string.gmatch, string.sub local concat, remove, unpack = table.concat, table.remove, table.unpack local floor, abs, round, ceil, min, max = math.floor, math.abs, math.round, math.ceil, math.min, math.max local P, C, R, S, C, Cs, Ct = lpeg.P, lpeg.C, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpeg.Ct @@ -145,6 +145,38 @@ local defaultstrings = { [0] = -- taken from ff "Black", "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold", } +local standardnames = { [0] = -- needed for seac + false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, + "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", false, false, false, + false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, "exclamdown", + "cent", "sterling", "fraction", "yen", "florin", "section", "currency", + "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft", + "guilsinglright", "fi", "fl", false, "endash", "dagger", "daggerdbl", + "periodcentered", false, "paragraph", "bullet", "quotesinglbase", + "quotedblbase", "quotedblright", "guillemotright", "ellipsis", "perthousand", + false, "questiondown", false, "grave", "acute", "circumflex", "tilde", + "macron", "breve", "dotaccent", "dieresis", false, "ring", "cedilla", false, + "hungarumlaut", "ogonek", "caron", "emdash", false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, + false, "AE", false, "ordfeminine", false, false, false, false, "Lslash", + "Oslash", "OE", "ordmasculine", false, false, false, false, false, "ae", + false, false, false, "dotlessi", false, false, "lslash", "oslash", "oe", + "germandbls", false, false, false, false +} + local cffreaders = { readbyte, readushort, @@ -152,6 +184,15 @@ local cffreaders = { readulong, } +directives.register("fonts.streamreader",function() + cffreaders = { + readbyte, + readushort, + readuint, + readulong, + } +end) + -- The header contains information about its own size. local function readheader(f) @@ -655,6 +696,7 @@ do local x = 0 local y = 0 local width = false + local lsb = 0 local r = 0 local stems = 0 local globalbias = 0 @@ -678,6 +720,9 @@ do local factors = false local axis = false local vsindex = 0 + local justpass = false + local seacs = { } + local procidx = nil local function showstate(where) report("%w%-10s : [%s] n=%i",depth*2,where,concat(stack," ",1,top),top) @@ -1012,43 +1057,6 @@ do top = 0 end --- local function xxcurveto(swap) --- local last = top % 4 ~= 0 and stack[top] --- if last then --- top = top - 1 --- end --- 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 --- xycurveto(ax,ay,bx,by,x,y) --- end --- top = 0 --- end - local function xxcurveto(swap) local last = top % 4 ~= 0 and stack[top] if last then @@ -1086,7 +1094,6 @@ do top = 0 end - local function hvcurveto() if trace_charstrings then showstate("hvcurveto") @@ -1302,7 +1309,7 @@ do end local function divide() - if version == 1 then + if version == "cff" then local d = stack[top] top = top - 1 stack[top] = stack[top] / d @@ -1310,7 +1317,7 @@ do end local function closepath() - if version == 1 then + if version == "cff" then if trace_charstrings then showstate("closepath") end @@ -1319,65 +1326,90 @@ do end local function hsbw() - if version == 1 then + if version == "cff" then if trace_charstrings then showstate("hsbw") end - -- lsb = stack[top-1] + lsb = stack[top-1] or 0 width = stack[top] end top = 0 end - local function seac() - if version == 1 then + local function sbw() + if version == "cff" then if trace_charstrings then - showstate("seac") + showstate("sbw") end + lsb = stack[top-3] + width = stack[top-1] end top = 0 end - local function sbw() - if version == 1 then + -- asb adx ady bchar achar seac (accented characters) + + local function seac() + if version == "cff" then if trace_charstrings then - showstate("sbw") + showstate("seac") end - width = stack[top-1] end top = 0 end - -- these are probably used for special cases i.e. call out to postscript + -- These are probably used for special cases i.e. call out to the + -- postscript interpreter (p 61 of the spec as well as chapter 8). + -- + -- This needs checking (I have to ask Taco next time we meet.) + + local popped = 3 + local hints = 3 + + -- arg1 ... argn n othersubr# <callothersubr> (on postscript stack) local function callothersubr() - if version == 1 then - -- we don't support this (ok, we could mimick these othersubs) + if version == "cff" then if trace_charstrings then - showstate("callothersubr (unsupported)") + showstate("callothersubr") + end + if stack[top] == hints then + popped = stack[top-2] + else + popped = 3 + end + local t = stack[top-1] + if t then + top = top - (t + 2) + if top < 0 then + top = 0 + end + else + top = 0 end + else + top = 0 end - top = 0 end + -- <pop> number (from postscript stack) + local function pop() - if version == 1 then - -- we don't support this + if version == "cff" then if trace_charstrings then - showstate("pop (unsupported)") + showstate("pop") end top = top + 1 - stack[top] = 0 -- a dummy + stack[top] = popped else top = 0 end end local function setcurrentpoint() - if version == 1 then - -- we don't support this + if version == "cff" then if trace_charstrings then - showstate("pop (unsupported)") + showstate("setcurrentpoint (unsupported)") end x = x + stack[top-1] y = y + stack[top] @@ -1527,6 +1559,41 @@ do hvcurveto, -- 31 } + local reverse = { [0] = + "unsupported", + "getstem", + "unsupported", + "getstem", + "vmoveto", + "rlineto", + "hlineto", + "vlineto", + "rrcurveto", + "unsupported", + "unsupported", + "unsupported", + "unsupported", + "hsbw", + "unsupported", + "setvsindex", + "blend", + "unsupported", + "getstem", + "getmask", + "getmask", + "rmoveto", + "hmoveto", + "getstem", + "rcurveline", + "rlinecurve", + "vvcurveto", + "hhcurveto", + "unsupported", + "unsupported", + "vhcurveto", + "hvcurveto", + } + local subactions = { -- cff 1 [000] = dotsection, @@ -1578,6 +1645,7 @@ do for i=1132,2048 do t[i] = char(28,band(rshift(i,8),0xFF),band(i,0xFF)) end + -- we could inline some ... setmetatableindex(encode,function(t,k) -- 16.16-bit signed fixed value local r = round(k) @@ -1663,7 +1731,7 @@ do local function call(scope,list,bias) -- ,process) depth = depth + 1 if top == 0 then - showstate(formatters["unknown %s call"](scope)) + showstate(formatters["unknown %s call %s, case %s"](scope,"?",1)) top = 0 else local index = stack[top] + bias @@ -1675,7 +1743,7 @@ do if tab then process(tab) else - showstate(formatters["unknown %s call %i"](scope,index)) + showstate(formatters["unknown %s call %s, case %s"](scope,index,2)) top = 0 end end @@ -1684,8 +1752,6 @@ do -- precompiling and reuse is much slower than redoing the calls - local justpass = false - -- local function decode(str) -- local a, b, c, d, e = byte(str,1,5) -- if a == 28 then @@ -1796,13 +1862,24 @@ do i = i + 1 local t = tab[i] if justpass then - if t >= 34 or t <= 37 then -- flexes + if t >= 34 and t <= 37 then -- flexes for i=1,top do r = r + 1 ; result[r] = encode[stack[i]] end r = r + 1 ; result[r] = chars[12] r = r + 1 ; result[r] = chars[t] top = 0 + elseif t == 6 then + seacs[procidx] = { + asb = stack[1], + adx = stack[2], + ady = stack[3], + base = stack[4], + accent = stack[5], + width = width, + lsb = lsb, + } + top = 0 else local a = subactions[t] if a then @@ -1834,46 +1911,56 @@ do -- cff 1: (when cff2 strip them) elseif t == 1 or t == 3 or t == 18 or operation == 23 then p_getstem() -- at the start -if true then - if top > 0 then - for i=1,top do - r = r + 1 ; result[r] = encode[stack[i]] + if true then + if top > 0 then + for i=1,top do + r = r + 1 ; result[r] = encode[stack[i]] + end + top = 0 end + r = r + 1 ; result[r] = chars[t] + else top = 0 end - r = r + 1 ; result[r] = chars[t] -else - top = 0 -end i = i + 1 -- cff 1: (when cff2 strip them) elseif t == 19 or t == 20 then local s = p_getmask() or 0 -- after the stems -if true then - if top > 0 then - for i=1,top do - r = r + 1 ; result[r] = encode[stack[i]] + if true then + if top > 0 then + for i=1,top do + r = r + 1 ; result[r] = encode[stack[i]] + end + top = 0 end + r = r + 1 ; result[r] = chars[t] + for j=1,s do + i = i + 1 + r = r + 1 ; result[r] = chars[tab[i]] + end + else + i = i + s top = 0 end - r = r + 1 ; result[r] = chars[t] - for j=1,s do - i = i + 1 - r = r + 1 ; result[r] = chars[tab[i]] - end -else - i = i + s - top = 0 -end i = i + 1 -- cff 1: closepath elseif t == 9 then top = 0 i = i + 1 elseif t == 13 then - local s = hsbw() or 0 - i = i + s + 1 + hsbw() + if version == "cff" then + -- we do a moveto over lsb + r = r + 1 ; result[r] = encode[lsb] + r = r + 1 ; result[r] = chars[22] + else + -- lsb is supposed to be zero + end + i = i + 1 else + if trace_charstrings then + showstate(reverse[t] or "<action>") + end if top > 0 then for i=1,top do r = r + 1 ; result[r] = encode[stack[i]] @@ -1894,7 +1981,7 @@ end end else if trace_charstrings then - showvalue("<action>",t) + showstate(reverse[t] or "<action>") end top = 0 i = i + 1 @@ -1941,24 +2028,19 @@ end -- end -- end - local function setbias(globals,locals) --- if version == 1 then -- charstring version, not cff --- return --- 0, --- 0 --- return --- 1, --- 1 --- else + local function setbias(globals,locals,nobias) + if nobias then + return 0, 0 + else local g = #globals local l = #locals return ((g < 1240 and 107) or (g < 33900 and 1131) or 32768) + 1, ((l < 1240 and 107) or (l < 33900 and 1131) or 32768) + 1 --- end + end end - local function processshape(tab,index) + local function processshape(tab,index,hack) if not tab then glyphs[index] = { @@ -1974,10 +2056,13 @@ end x = 0 y = 0 width = false + lsb = 0 r = 0 top = 0 stems = 0 result = { } -- we could reuse it when only boundingbox calculations are needed + popped = 3 + procidx = index xmin = 0 xmax = 0 @@ -1995,6 +2080,10 @@ end process(tab) + if hack then + return x, y + end + local boundingbox = { round(xmin), round(ymin), @@ -2059,6 +2148,8 @@ end axis = false regions = data.regions justpass = streams == true + popped = 3 + seacs = { } if regions then regions = { regions } -- needs checking axis = data.factors or false @@ -2073,6 +2164,8 @@ end locals = false globals = false strings = false + popped = 3 + seacs = { } end local function setwidths(private) @@ -2086,7 +2179,7 @@ end return privatedata.nominalwidthx or 0, privatedata.defaultwidthx or 0 end - parsecharstrings = function(fontdata,data,glphs,doshapes,tversion,streams) + parsecharstrings = function(fontdata,data,glphs,doshapes,tversion,streams,nobias) local dictionary = data.dictionaries[1] local charstrings = dictionary.charstrings @@ -2100,14 +2193,42 @@ end vsindex = dictionary.vsindex or 0 glyphs = glphs or { } - globalbias, localbias = setbias(globals,locals) + globalbias, localbias = setbias(globals,locals,nobias) nominalwidth, defaultwidth = setwidths(dictionary.private) if charstrings then startparsing(fontdata,data,streams) for index=1,#charstrings do processshape(charstrings[index],index-1) --- charstrings[index] = nil -- free memory (what if used more often?) + end + if justpass and next(seacs) then + -- old type 1 stuff ... seacs + local charset = data.dictionaries[1].charset + if charset then + local lookup = table.swapped(charset) + for index, v in next, seacs do + local bindex = lookup[standardnames[v.base]] + local aindex = lookup[standardnames[v.accent]] + local bglyph = bindex and glyphs[bindex] + local aglyph = aindex and glyphs[aindex] + if bglyph and aglyph then + -- this is a real ugly hack but we seldom enter this branch (e.g. old lbr) + local jp = justpass + justpass = false + local x, y = processshape(charstrings[bindex+1],bindex,true) + justpass = jp + -- + local base = bglyph.stream + local accent = aglyph.stream + local moveto = encode[-x-v.asb+v.adx] .. chars[22] + .. encode[-y +v.ady] .. chars[ 4] + -- prune an endchar + base = sub(base,1,#base-1) + -- combine them + glyphs[index].stream = base .. moveto .. accent + end + end + end end stopparsing(fontdata,data) else @@ -2127,9 +2248,10 @@ end vsindex = dictionary.vsindex or 0 glyphs = glphs or { } - justpass = streams == true + justpass = streams == true + seacs = { } - globalbias, localbias = setbias(globals,locals) + globalbias, localbias = setbias(globals,locals,nobias) nominalwidth, defaultwidth = setwidths(dictionary.private) processshape(tab,index-1) @@ -2428,8 +2550,8 @@ function readers.cff(f,fontdata,specification) if private then local data = private.data if type(data) == "table" then - cffinfo.defaultwidth = data.defaultwidth or cffinfo.defaultwidth - cffinfo.nominalwidth = data.nominalwidth or cffinfo.nominalwidth + cffinfo.defaultwidth = data.defaultwidthx or cffinfo.defaultwidth + cffinfo.nominalwidth = data.nominalwidthx or cffinfo.nominalwidth cffinfo.bluevalues = data.bluevalues cffinfo.otherblues = data.otherblues cffinfo.familyblues = data.familyblues |