diff options
author | Karl Berry <karl@freefriends.org> | 2017-04-19 23:04:15 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2017-04-19 23:04:15 +0000 |
commit | f74161ca4e7eb3c5af9afcbe92522ae3b58987c1 (patch) | |
tree | 3c30a13df5ac7968195c85070a2b074578e669d2 /Master/texmf-dist/tex/context/base/mkiv/font-cff.lua | |
parent | 1d5a55ac8f5506a7ae9cfca52f4b588182e199d4 (diff) |
context beta/cont-tmf.zip (Apr 16 12:55)
git-svn-id: svn://tug.org/texlive/trunk@43931 c570f23f-e606-0410-a88d-b1316a301751
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 | 1387 |
1 files changed, 997 insertions, 390 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 8c57b473ef8..a799a67f52e 100644 --- a/Master/texmf-dist/tex/context/base/mkiv/font-cff.lua +++ b/Master/texmf-dist/tex/context/base/mkiv/font-cff.lua @@ -13,31 +13,39 @@ if not modules then modules = { } end modules ['font-cff'] = { -- 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. +-- #5177. In case of doubt I looked in the fontforge code that comes with LuaTeX but +-- it's not the easiest source to read (and doesn't cover cff2). -- 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. +-- +-- In retrospect I could have looked into the backend code of LuaTeX but it never +-- occurred to me that parsing charstrings was needed there (which has to to +-- with merging subroutines and flattening, not so much with calculations.) On +-- the other hand, we can now feed back cff2 stuff. local next, type, tonumber = next, type, tonumber -local byte = string.byte +local byte, char, gmatch = string.byte, string.char, string.gmatch local concat, remove = table.concat, table.remove -local floor, abs, round, ceil = math.floor, math.abs, math.round, math.ceil +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 local lpegmatch = lpeg.match +local formatters = string.formatters +local bytetable = string.bytetable 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 readulong = streamreader.readcardinal4 -- 32-bit unsigned integer local setposition = streamreader.setposition local getposition = streamreader.getposition +local readbytetable = streamreader.readbytetable local setmetatableindex = table.setmetatableindex @@ -49,6 +57,8 @@ local parsecharstring local parsecharstrings local resetcharstrings local parseprivates +local startparsing +local stopparsing local defaultstrings = { [0] = -- taken from ff ".notdef", "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", @@ -129,13 +139,21 @@ local cffreaders = { local function readheader(f) local offset = getposition(f) + local major = readbyte(f) local header = { offset = offset, - major = readbyte(f), + major = major, minor = readbyte(f), size = readbyte(f), -- headersize - osize = readbyte(f), -- for offsets to start } + if major == 1 then + header.dsize = readbyte(f) -- list of dict offsets + elseif major == 2 then + header.dsize = readushort(f) -- topdict size + else + -- I'm probably no longer around by then and we use AI's to + -- handle this kind of stuff, if we typeset documents at all. + end setposition(f,offset+header.size) return header end @@ -143,8 +161,8 @@ 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) +local function readlengths(f,longcount) + local count = longcount and readulong(f) or readushort(f) if count == 0 then return { } end @@ -158,7 +176,12 @@ local function readlengths(f) local previous = read(f) for i=1,count do local offset = read(f) - lengths[i] = offset - previous + local length = offset - previous + if length < 0 then + report("bad offset: %i",length) + length = 0 + end + lengths[i] = length previous = offset end return lengths @@ -216,7 +239,8 @@ end do - -- We use a closure so that we don't need to pass too much around. + -- We use a closure so that we don't need to pass too much around. For cff2 we can + -- at some point use a simple version as there is less. local stack = { } local top = 0 @@ -270,7 +294,7 @@ do result.encoding = stack[top] top = 0 end - + P("\17") / function() + + P("\17") / function() -- valid cff2 result.charstrings = stack[top] top = 0 end @@ -283,19 +307,32 @@ do end + P("\19") / function() result.subroutines = stack[top] + top = 0 -- new, forgotten ? end + P("\20") / function() result.defaultwidthx = stack[top] + top = 0 -- new, forgotten ? end + P("\21") / function() result.nominalwidthx = stack[top] + top = 0 -- new, forgotten ? + end + -- + P("\22") / function() -- reserved + -- end + -- + P("\23") / function() -- reserved + -- end + + P("\24") / function() -- new in cff2 + result.vstore = stack[top] + top = 0 + end + + P("\25") / function() -- new in cff2 + result.maxstack = stack[top] + top = 0 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 + -- + P("\26") / function() -- reserved + -- end + -- + P("\27") / function() -- reserved + -- end local p_double = P("\12") * ( P("\00") / function() @@ -326,7 +363,7 @@ do result.charstringtype = stack[top] top = 0 end - + P("\07") / function() + + P("\07") / function() -- valid cff2 result.fontmatrix = { unpack(stack,1,6) } top = 0 end @@ -376,11 +413,11 @@ do result.cid.uidbase = stack[top] top = 0 end - + P("\36") / function() + + P("\36") / function() -- valid cff2 result.cid.fdarray = stack[top] top = 0 end - + P("\37") / function() + + P("\37") / function() -- valid cff2 result.cid.fdselect = stack[top] top = 0 end @@ -501,12 +538,12 @@ do + p_unsupported )^1 - parsedictionaries = function(data,dictionaries) + parsedictionaries = function(data,dictionaries,what) stack = { } strings = data.strings for i=1,#dictionaries do top = 0 - result = { + result = what == "cff" and { monospaced = false, italicangle = 0, underlineposition = -100, @@ -524,6 +561,13 @@ do fonttype = 0, count = 8720, } + } or { + charstringtype = 2, + charset = 0, + vstore = 0, + cid = { + -- nothing yet + }, } lpegmatch(p_dictionary,dictionaries[i]) dictionaries[i] = result @@ -578,22 +622,32 @@ do -- 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 x = 0 + local y = 0 + local width = false + local r = 0 + local stems = 0 + local globalbias = 0 + local localbias = 0 + local nominalwidth = 0 + local defaultwidth = 0 + local charset = false + 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 version = 2 + local regions = false + local nofregions = 0 + local region = false + local factors = false + local axis = false + local vsindex = 0 local function showstate(where) report("%w%-10s : [%s] n=%i",depth*2,where,concat(stack," ",1,top),top) @@ -609,16 +663,17 @@ do -- 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. + -- some back. I inlined some of then and a bit speed can be gained by more + -- inlining but not that much. - local function moveto(x,y) + local function xymoveto() 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 + if x > xmax then xmax = x elseif x < xmin then xmin = x end + if y > ymax then ymax = y elseif y < ymin then ymin = y end else xmin = x ymin = y @@ -628,14 +683,58 @@ do end end - local function lineto(x,y) + local function xmoveto() -- slight speedup + if keepcurve then + r = r + 1 + result[r] = { x, y, "m" } + end + if not checked then + xmin = x + ymin = y + xmax = x + ymax = y + checked = true + elseif x > xmax then + xmax = x + elseif x < xmin then + xmin = x + end + end + + local function ymoveto() -- slight speedup + if keepcurve then + r = r + 1 + result[r] = { x, y, "m" } + end + if not checked then + xmin = x + ymin = y + xmax = x + ymax = y + checked = true + elseif y > ymax then + ymax = y + elseif y < ymin then + ymin = y + end + end + + local function moveto() + if trace_charstrings then + showstate("moveto") + end + top = 0 -- forgotten + xymoveto() + end + + local function xylineto() -- we could inline, no blend 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 + if x > xmax then xmax = x elseif x < xmin then xmin = x end + if y > ymax then ymax = y elseif y < ymin then ymin = y end else xmin = x ymin = y @@ -645,14 +744,53 @@ do end end - local function curveto(x1,y1,x2,y2,x3,y3) + local function xlineto() -- slight speedup + if keepcurve then + r = r + 1 + result[r] = { x, y, "l" } + end + if not checked then + xmin = x + ymin = y + xmax = x + ymax = y + checked = true + elseif x > xmax then + xmax = x + elseif x < xmin then + xmin = x + end + end + + local function ylineto() -- slight speedup + if keepcurve then + r = r + 1 + result[r] = { x, y, "l" } + end + if not checked then + xmin = x + ymin = y + xmax = x + ymax = y + checked = true + elseif y > ymax then + ymax = y + elseif y < ymin then + ymin = y + end + end + + local function xycurveto(x1,y1,x2,y2,x3,y3) -- called local so no blend here + if trace_charstrings then + showstate("curveto") + end 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 + if x1 > xmax then xmax = x1 elseif x1 < xmin then xmin = x1 end + if y1 > ymax then ymax = y1 elseif y1 < ymin then ymin = y1 end else xmin = x1 ymin = y1 @@ -660,22 +798,22 @@ do 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 + if x2 > xmax then xmax = x2 elseif x2 < xmin then xmin = x2 end + if y2 > ymax then ymax = y2 elseif y2 < ymin then ymin = y2 end + if x3 > xmax then xmax = x3 elseif x3 < xmin then xmin = x3 end + if y3 > ymax then ymax = y3 elseif y3 < ymin then ymin = y3 end end local function rmoveto() - if top > 2 then - if not width then + if not width then + if top > 2 then width = stack[1] if trace_charstrings then - showvalue("width",width) + showvalue("backtrack width",width) end + else + width = true end - elseif not width then - width = true end if trace_charstrings then showstate("rmoveto") @@ -683,45 +821,45 @@ do x = x + stack[top-1] -- dx1 y = y + stack[top] -- dy1 top = 0 - moveto(x,y) + xymoveto() end local function hmoveto() - if top > 1 then - if not width then + if not width then + if top > 1 then width = stack[1] if trace_charstrings then - showvalue("width",width) + showvalue("backtrack width",width) end + else + width = true 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) + xmoveto() end local function vmoveto() - if top > 1 then - if not width then + if not width then + if top > 1 then width = stack[1] if trace_charstrings then - showvalue("width",width) + showvalue("backtrack width",width) end + else + width = true 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) + ymoveto() end local function rlineto() @@ -731,21 +869,7 @@ do 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) + xylineto() end top = 0 end @@ -754,14 +878,48 @@ do if trace_charstrings then showstate("hlineto") end - xlineto(true) + if top == 1 then + x = x + stack[1] + xlineto() + else + local swap = true + for i=1,top do + if swap then + x = x + stack[i] + xlineto() + swap = false + else + y = y + stack[i] + ylineto() + swap = true + end + end + end + top = 0 end local function vlineto() -- y (x,y)+ | (y,x)+ if trace_charstrings then showstate("vlineto") end - xlineto(false) + if top == 1 then + y = y + stack[1] + ylineto() + else + local swap = false + for i=1,top do + if swap then + x = x + stack[i] + xlineto() + swap = false + else + y = y + stack[i] + ylineto() + swap = true + end + end + end + top = 0 end local function rrcurveto() @@ -773,9 +931,9 @@ do 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) + x = bx + stack[i+4] -- dxc + y = by + stack[i+5] -- dyc + xycurveto(ax,ay,bx,by,x,y) end top = 0 end @@ -786,17 +944,17 @@ do end local s = 1 if top % 2 ~= 0 then - y = y + stack[1] -- dy1 + y = y + stack[1] -- dy1 s = 2 end for i=s,top,4 do - local ax = x + stack[i] -- dxa + 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 + x = bx + stack[i+3] -- dxc y = by - curveto(ax,ay,bx,by,x,y) + xycurveto(ax,ay,bx,by,x,y) end top = 0 end @@ -808,28 +966,64 @@ do local s = 1 local d = 0 if top % 2 ~= 0 then - d = stack[1] -- dx1 + d = stack[1] -- dx1 s = 2 end for i=s,top,4 do local ax = x + d - local ay = y + stack[i] -- dya + 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) + y = by + stack[i+3] -- dyc + xycurveto(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 +-- 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 top = top - 1 end - local sw = swap for i=1,top,4 do local ax, ay, bx, by if swap then @@ -857,11 +1051,12 @@ do end swap = true end - curveto(ax,ay,bx,by,x,y) + xycurveto(ax,ay,bx,by,x,y) end top = 0 end + local function hvcurveto() if trace_charstrings then showstate("hvcurveto") @@ -887,11 +1082,11 @@ do 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) + xycurveto(ax,ay,bx,by,x,y) end x = x + stack[top-1] -- dxc y = y + stack[top] -- dyc - lineto(x,y) + xylineto() top = 0 end @@ -903,7 +1098,7 @@ do for i=1,top-6,2 do x = x + stack[i] y = y + stack[i+1] - lineto(x,y) + xylineto() end end local ax = x + stack[top-5] @@ -912,7 +1107,7 @@ do local by = ay + stack[top-2] x = bx + stack[top-1] y = by + stack[top] - curveto(ax,ay,bx,by,x,y) + xycurveto(ax,ay,bx,by,x,y) top = 0 end @@ -928,14 +1123,14 @@ do 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) + xycurveto(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) + xycurveto(dx,dy,ex,ey,x,y) top = 0 end @@ -943,19 +1138,19 @@ do if trace_charstrings then showstate("hflex") end - local ax = x + stack[1] -- dx1 + 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) + xycurveto(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) + x = ex + stack[7] -- dx6 + xycurveto(dx,dy,ex,ey,x,y) top = 0 end @@ -969,13 +1164,13 @@ do local by = ay + stack[4] -- dy2 local cx = bx + stack[5] -- dx3 local cy = by - curveto(ax,ay,bx,by,cx,cy) + xycurveto(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) + x = ex + stack[9] -- dx6 + xycurveto(dx,dy,ex,ey,x,y) top = 0 end @@ -989,7 +1184,7 @@ do 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) + xycurveto(ax,ay,bx,by,cx,cy) local dx = cx + stack[7] --dx4 local dy = cy + stack[8] --dy4 local ex = dx + stack[9] --dx5 @@ -999,7 +1194,7 @@ do else y = ey + stack[11] end - curveto(dx,dy,ex,ey,x,y) + xycurveto(dx,dy,ex,ey,x,y) top = 0 end @@ -1052,13 +1247,216 @@ do end end - local function unsupported() + local function unsupported(t) + if trace_charstrings then + showstate("unsupported " .. t) + end + top = 0 + end + + local function unsupportedsub(t) + if trace_charstrings then + showstate("unsupported sub " .. t) + end + top = 0 + end + + -- type 1 (not used in type 2) + + local function getstem3() if trace_charstrings then - showstate("unsupported") + showstate("stem3") + end + top = 0 + end + + local function divide() + if version == 1 then + local d = stack[top] + top = top - 1 + stack[top] = stack[top] / d + end + end + + local function closepath() + if version == 1 then + if trace_charstrings then + showstate("closepath") + end + end + top = 0 + end + + local function hsbw() + if version == 1 then + if trace_charstrings then + showstate("dotsection") + end + width = stack[top] + end + top = 0 + end + + local function seac() + if version == 1 then + if trace_charstrings then + showstate("seac") + end + end + top = 0 + end + + local function sbw() + if version == 1 then + if trace_charstrings then + showstate("sbw") + end + width = stack[top-1] + end + top = 0 + end + + -- these are probably used for special cases i.e. call out to postscript + + local function callothersubr() + if version == 1 then + -- we don't support this (ok, we could mimick these othersubs) + if trace_charstrings then + showstate("callothersubr (unsupported)") + end + end + top = 0 + end + + local function pop() + if version == 1 then + -- we don't support this + if trace_charstrings then + showstate("pop (unsupported)") + end + top = top + 1 + stack[top] = 0 -- a dummy + else + top = 0 + end + end + + local function setcurrentpoint() + if version == 1 then + -- we don't support this + if trace_charstrings then + showstate("pop (unsupported)") + end + x = x + stack[top-1] + y = y + stack[top] end top = 0 end + -- So far for unsupported postscript. Now some cff2 magic. As I still need + -- to wrap my head around the rather complex variable font specification + -- with regions and axis, the following approach kind of works but is more + -- some trial and error trick. It's still not clear how much of the complex + -- truetype description applies to cff. + + local reginit = false + + local function updateregions(n) -- n + 1 + if regions then + local current = regions[n] or regions[1] + nofregions = #current + if axis and n ~= reginit then + factors = { } + for i=1,nofregions do + local region = current[i] + local s = 1 + for j=1,#axis do + local f = axis[j] + local r = region[j] + local start = r.start + local peak = r.peak + local stop = r.stop + if start > peak or peak > stop then + -- * 1 + elseif start < 0 and stop > 0 and peak ~= 0 then + -- * 1 + elseif peak == 0 then + -- * 1 + elseif f < start or f > stop then + -- * 0 + s = 0 + break + elseif f < peak then + s = s * (f - start) / (peak - start) + elseif f > peak then + s = s * (stop - f) / (stop - peak) + else + -- * 1 + end + end + factors[i] = s + end + end + end + reginit = n + end + + local function setvsindex() + local vsindex = stack[top] + if trace_charstrings then + showstate(formatters["vsindex %i"](vsindex)) + end + updateregions(vsindex) + top = top - 1 + end + + local function blend() + local n = stack[top] + top = top - 1 + if axis then + -- x (r1x,r2x,r3x) + -- (x,y) (r1x,r2x,r3x) (r1y,r2y,r3y) + if trace_charstrings then + local t = top - nofregions * n + local m = t - n + for i=1,n do + local k = m + i + local d = m + n + (i-1)*nofregions + local old = stack[k] + local new = old + for r=1,nofregions do + new = new + stack[d+r] * factors[r] + end + stack[k] = new + showstate(formatters["blend %i of %i: %s -> %s"](i,n,old,new)) + end + top = t + elseif n == 1 then + top = top - nofregions + local v = stack[top] + for r=1,nofregions do + v = v + stack[top+r] * factors[r] + end + stack[top] = v + else + top = top - nofregions * n + local d = top + local k = top - n + for i=1,n do + k = k + 1 + local v = stack[k] + for r=1,nofregions do + v = v + stack[d+r] * factors[r] + end + stack[k] = v + d = d + nofregions + end + end + else + -- error + end + end + -- Bah, we cannot use a fast lpeg because a hint has an unknown size and a -- runtime capture cannot handle that well. @@ -1076,10 +1474,10 @@ do unsupported, -- 10 -- calllocal, unsupported, -- 11 -- callreturn, unsupported, -- 12 -- elsewhere - unsupported, -- 13 -- hsbw + hsbw, -- 13 -- hsbw (type 1 cff) unsupported, -- 14 -- endchar, - unsupported, -- 15 - unsupported, -- 16 + setvsindex, -- 15 -- cff2 + blend, -- 16 -- cff2 unsupported, -- 17 getstem, -- 18 -- hstemhm getmask, -- 19 -- hintmask @@ -1098,82 +1496,190 @@ do } local subactions = { + -- cff 1 + [000] = dotsection, + [001] = getstem3, + [002] = getstem3, + [006] = seac, + [007] = sbw, + [012] = divide, + [016] = callothersubr, + [017] = pop, + [033] = setcurrentpoint, + -- cff 2 [034] = hflex, [035] = flex, [036] = hflex1, [037] = flex1, } - local p_bytes = Ct((P(1)/byte)^0) + local c_endchar = char(14) - local function call(scope,list,bias,process) - local index = stack[top] + bias - top = top - 1 - if trace_charstrings then - showvalue(scope,index,true) + local passon do + + -- todo: round in blend + -- todo: delay this hash + + local rshift = bit32.rshift + local band = bit32.band + local round = math.round + + local encode = table.setmetatableindex(function(t,i) + for i=-2048,-1130 do + t[i] = char(28,band(rshift(i,8),0xFF),band(i,0xFF)) + end + for i=-1131,-108 do + local v = 0xFB00 - i - 108 + t[i] = char(band(rshift(v,8),0xFF),band(v,0xFF)) + end + for i=-107,107 do + t[i] = char(i + 139) + end + for i=108,1131 do + local v = 0xF700 + i - 108 + t[i] = char(band(rshift(v,8),0xFF),band(v,0xFF)) + end + for i=1132,2048 do + t[i] = char(28,band(rshift(i,8),0xFF),band(i,0xFF)) + end + return t[i] + end) + + local function setvsindex() + local vsindex = stack[top] + updateregions(vsindex) + top = top - 1 + end + + local function blend() + local n = stack[top] + top = top - 1 + if not axis then + -- fatal error + elseif n == 1 then + top = top - nofregions + local v = stack[top] + for r=1,nofregions do + v = v + stack[top+r] * factors[r] + end + stack[top] = round(v) + else + top = top - nofregions * n + local d = top + local k = top - n + for i=1,n do + k = k + 1 + local v = stack[k] + for r=1,nofregions do + v = v + stack[d+r] * factors[r] + end + stack[k] = round(v) + d = d + nofregions + end + end end - local str = list[index] - if str then - if type(str) == "string" then - str = lpegmatch(p_bytes,str) - list[index] = str + + passon = function(operation) + if operation == 15 then + setvsindex() + elseif operation == 16 then + blend() + else + for i=1,top do + r = r + 1 + result[r] = encode[stack[i]] + end + r = r + 1 + result[r] = char(operation) -- maybe use a hash + top = 0 end - depth = depth + 1 - process(str) - depth = depth - 1 + end + + end + + -- end of experiment + + local process + + local function call(scope,list,bias) -- ,process) + depth = depth + 1 + if top == 0 then + showstate(formatters["unknown %s call"](scope)) + top = 0 else - report("unknown %s %i",scope,index) + local index = stack[top] + bias + top = top - 1 + if trace_charstrings then + showvalue(scope,index,true) + end + local tab = list[index] + if tab then + process(tab) + else + showstate(formatters["unknown %s call %i"](scope,index)) + top = 0 + end end + depth = depth - 1 end - local function process(tab) + -- precompiling and reuse is much slower than redoing the calls + + local justpass = false + + process = function(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 + if t >= 32 then top = top + 1 - stack[top] = -(t-251)*256 - tab[i+1] - 108 - i = i + 2 + if t <= 246 then + -- -107 .. +107 + stack[top] = t - 139 + i = i + 1 + elseif t <= 250 then + -- +108 .. +1131 + -- stack[top] = (t-247)*256 + tab[i+1] + 108 + -- stack[top] = t*256 - 247*256 + tab[i+1] + 108 + stack[top] = t*256 - 63124 + tab[i+1] + i = i + 2 + elseif t <= 254 then + -- -1131 .. -108 + -- stack[top] = -(t-251)*256 - tab[i+1] - 108 + -- stack[top] = -t*256 + 251*256 - tab[i+1] - 108 + stack[top] = -t*256 + 64148 - tab[i+1] + i = i + 2 + else + local n = 0x100 * tab[i+1] + tab[i+2] + if n >= 0x8000 then + -- stack[top] = n - 0xFFFF - 1 + (0x100 * tab[i+3] + tab[i+4])/0xFFFF + stack[top] = n - 0x10000 + (0x100 * tab[i+3] + tab[i+4])/0xFFFF + else + stack[top] = n + (0x100 * tab[i+3] + tab[i+4])/0xFFFF + end + i = i + 5 + end 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 + -- stack[top] = n - 0xFFFF - 1 + stack[top] = n - 0x10000 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 + elseif t == 11 then -- not in cff2 if trace_charstrings then showstate("return") end return elseif t == 10 then - call("local",locals,localbias,process) + call("local",locals,localbias) -- ,process) i = i + 1 - elseif t == 14 then -- endchar + elseif t == 14 then -- not in cff2 if width then -- okay elseif top > 0 then @@ -1189,14 +1695,14 @@ do end return elseif t == 29 then - call("global",globals,globalbias,process) + 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() + a(t) else if trace_charstrings then showvalue("<subaction>",t) @@ -1204,20 +1710,25 @@ do top = 0 end i = i + 1 + elseif justpass then + passon(t) + i = i + 1 else local a = actions[t] if a then - local s = a() + local s = a(t) if s then - i = i + s + i = i + s + 1 + else + i = i + 1 end else if trace_charstrings then showvalue("<action>",t) end top = 0 + i = i + 1 end - i = i + 1 end end end @@ -1236,7 +1747,7 @@ do -- 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 + -- -- simplify the next checks -- for i=1,nofsegments do -- local s = segments[i] -- local x = s[1] @@ -1260,142 +1771,73 @@ do -- 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 + local function setbias(globals,locals) + if version == 1 then + return + false, + false + else + local g, l = #globals, #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 - 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 - -- + local function processshape(tab,index) + + tab = bytetable(tab) + + x = 0 + y = 0 + width = false + r = 0 + top = 0 + stems = 0 + result = { } -- we could reuse it when only boundingbox calculations are needed + + xmin = 0 + xmax = 0 + ymin = 0 + ymax = 0 + checked = false + if trace_charstrings then report("glyph: %i",index) - report("data: % t",tab) + report("data : % t",tab) end - -- + + if regions then + updateregions(vsindex) + end + process(tab) - -- - local boundingbox = { xmin, ymin, xmax, ymax } - -- + + local boundingbox = { + round(xmin), + round(ymin), + round(xmax), + round(ymax), + } + if width == true or width == false then width = defaultwidth else width = nominalwidth + width end - -- -index = index - 1 + 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 + if justpass then + r = r + 1 + result[r] = c_endchar + local stream = concat(result) + if glyph then + glyph.stream = stream + else + glyphs[index] = { stream = stream } + end + elseif glyph then + glyph.segments = keepcurve ~= false and result or nil glyph.boundingbox = boundingbox if not glyph.width then glyph.width = width @@ -1404,20 +1846,107 @@ index = index - 1 glyph.name = charset[index] end -- glyph.sidebearing = 0 -- todo + elseif keepcurve then + glyphs[index] = { + segments = result, + boundingbox = boundingbox, + width = width, + name = charset and charset[index] or nil, + -- sidebearing = 0, + } + else + glyphs[index] = { + boundingbox = boundingbox, + width = width, + name = charset and charset[index] or nil, + } end - -- + if trace_charstrings then - report("width: %s",tostring(width)) + report("width : %s",tostring(width)) report("boundingbox: % t",boundingbox) end - -- - return charstring + end - resetcharstrings = function() - result = { } - top = 0 - stack = { } + startparsing = function(fontdata,data,streams) + reginit = false + axis = false + regions = data.regions + justpass = streams == true + if regions then + regions = { regions } -- needs checking + axis = data.factors or false + end + end + + stopparsing = function(fontdata,data) + stack = { } + glyphs = false + result = { } + top = 0 + locals = false + globals = false + strings = false + end + + local function setwidths(private) + if not private then + return 0, 0 + end + local privatedata = private.data + if not privatedata then + return 0, 0 + end + return privatedata.nominalwidthx or 0, privatedata.defaultwidthx or 0 + end + + parsecharstrings = function(fontdata,data,glphs,doshapes,tversion,streams) + + local dictionary = data.dictionaries[1] + local charstrings = dictionary.charstrings + + keepcurve = doshapes + version = tversion + strings = data.strings + globals = data.routines or { } + locals = dictionary.subroutines or { } + charset = dictionary.charset + vsindex = dictionary.vsindex or 0 + glyphs = glphs or { } + + globalbias, localbias = setbias(globals,locals) + nominalwidth, defaultwidth = setwidths(dictionary.private) + + 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 + + stopparsing(fontdata,data) + + return glyphs + end + + parsecharstring = function(fontdata,data,dictionary,tab,glphs,index,doshapes,tversion) + + keepcurve = doshapes + version = tversion + strings = data.strings + globals = data.routines or { } + locals = dictionary.subroutines or { } + charset = false + vsindex = dictionary.vsindex or 0 + glyphs = glphs or { } + + globalbias, localbias = setbias(globals,locals) + nominalwidth, defaultwidth = setwidths(dictionary.private) + + processshape(tab,index-1) + + -- return glyphs[index] end end @@ -1425,7 +1954,7 @@ end local function readglobals(f,data) local routines = readlengths(f) for i=1,#routines do - routines[i] = readstring(f,routines[i]) + routines[i] = readbytetable(f,routines[i]) end data.routines = routines end @@ -1439,8 +1968,7 @@ local function readcharsets(f,data,dictionary) local strings = data.strings local nofglyphs = data.nofglyphs local charsetoffset = dictionary.charset - - if charsetoffset ~= 0 then + if charsetoffset and charsetoffset ~= 0 then setposition(f,header.offset+charsetoffset) local format = readbyte(f) local charset = { [0] = ".notdef" } @@ -1466,6 +1994,9 @@ local function readcharsets(f,data,dictionary) else report("cff parser: unsupported charset format %a",format) end + else + dictionary.nocharset = true + dictionary.charset = nil end end @@ -1488,7 +2019,7 @@ local function readlocals(f,data,dictionary) setposition(f,header.offset+private.offset+subroutineoffset) local subroutines = readlengths(f) for i=1,#subroutines do - subroutines[i] = readstring(f,subroutines[i]) + subroutines[i] = readbytetable(f,subroutines[i]) end dictionary.subroutines = subroutines private.data.subroutines = nil @@ -1503,16 +2034,18 @@ 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 function readcharstrings(f,data,what) local header = data.header local dictionaries = data.dictionaries local dictionary = dictionaries[1] - local type = dictionary.charstringtype + local stringtype = dictionary.charstringtype local offset = dictionary.charstrings - if type == 2 then + if type(offset) ~= "number" then + -- weird + elseif stringtype == 2 then setposition(f,header.offset+offset) -- could be a metatable .. delayed loading - local charstrings = readlengths(f) + local charstrings = readlengths(f,what=="cff2") local nofglyphs = #charstrings for i=1,nofglyphs do charstrings[i] = readstring(f,charstrings[i]) @@ -1520,7 +2053,7 @@ local function readcharstrings(f,data) data.nofglyphs = nofglyphs dictionary.charstrings = charstrings else - report("unsupported charstr type %i",type) + report("unsupported charstr type %i",stringtype) data.nofglyphs = 0 dictionary.charstrings = { } end @@ -1542,29 +2075,36 @@ local function readcidprivates(f,data) parseprivates(data,dictionaries) end -local function readnoselect(f,data,glyphs,doshapes) +readers.parsecharstrings = parsecharstrings -- used in font-onr.lua (type 1) + +local function readnoselect(f,fontdata,data,glyphs,doshapes,version,streams) local dictionaries = data.dictionaries local dictionary = dictionaries[1] readglobals(f,data) - readcharstrings(f,data) - readencodings(f,data) - readcharsets(f,data,dictionary) + readcharstrings(f,data,version) + if version ~= "cff2" then + readencodings(f,data) + readcharsets(f,data,dictionary) + end readprivates(f,data) parseprivates(data,data.dictionaries) readlocals(f,data,dictionary) - parsecharstrings(data,glyphs,doshapes) - resetcharstrings() + startparsing(fontdata,data,streams) + parsecharstrings(fontdata,data,glyphs,doshapes,version,streams) + stopparsing(fontdata,data) end -local function readfdselect(f,data,glyphs,doshapes) +local function readfdselect(f,fontdata,data,glyphs,doshapes,version,streams) 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) + readcharstrings(f,data,version) + if version ~= "cff2" then + readencodings(f,data) + end local charstrings = dictionary.charstrings local fdindex = { } local nofglyphs = data.nofglyphs @@ -1601,6 +2141,7 @@ local function readfdselect(f,data,glyphs,doshapes) else -- unsupported format end + -- hm, always if maxindex >= 0 then local cidarray = cid.fdarray setposition(f,header.offset+cidarray) @@ -1614,85 +2155,151 @@ local function readfdselect(f,data,glyphs,doshapes) for i=1,#dictionaries do readlocals(f,data,dictionaries[i]) end + startparsing(fontdata,data,streams) for i=1,#charstrings do - parsecharstring(data,dictionaries[fdindex[i]+1],charstrings[i],glyphs,i,doshapes) + parsecharstring(fontdata,data,dictionaries[fdindex[i]+1],charstrings[i],glyphs,i,doshapes,version) + charstrings[i] = nil end - resetcharstrings() + stopparsing(fontdata,data) end end +local gotodatatable = readers.helpers.gotodatatable + +local function cleanup(data,dictionaries) + -- 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 + 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 + local tableoffset = gotodatatable(f,fontdata,"cff",specification.details) + if tableoffset then + local header = readheader(f) + if header.major ~= 1 then + report("only version %s is supported for table %a",1,"cff") + return + end + local glyphs = fontdata.glyphs + 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,dictionaries,"cff") + -- + local dic = dictionaries[1] + local cid = dic.cid + fontdata.cffinfo = { + familynamename = dic.familyname, + fullname = dic.fullname, + boundingbox = dic.boundingbox, + weight = dic.weight, + italicangle = dic.italicangle, + underlineposition = dic.underlineposition, + underlinethickness = dic.underlinethickness, + monospaced = dic.monospaced, + } + fontdata.cidinfo = cid and { + registry = cid.registry, + ordering = cid.ordering, + supplement = cid.supplement, + } + -- + if specification.glyphs then + local all = specification.shapes or false + if cid and cid.fdselect then + readfdselect(f,fontdata,data,glyphs,all,"cff") 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 + readnoselect(f,fontdata,data,glyphs,all,"cff") 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 + cleanup(data,dictionaries) + end +end + +function readers.cff2(f,fontdata,specification) + local tableoffset = gotodatatable(f,fontdata,"cff2",specification.glyphs) + if tableoffset then + local header = readheader(f) + if header.major ~= 2 then + report("only version %s is supported for table %a",2,"cff2") + return + end + local glyphs = fontdata.glyphs + local dictionaries = { readstring(f,header.dsize) } + local data = { + header = header, + dictionaries = dictionaries, + nofglyphs = fontdata.nofglyphs, + } + -- + parsedictionaries(data,dictionaries,"cff2") + -- + local storeoffset = dictionaries[1].vstore + data.header.offset + 2 -- cff has a preceding size field + local regions, deltas = readers.helpers.readvariationdata(f,storeoffset,factors) + -- + data.regions = regions + data.deltas = deltas + data.factors = specification.factors + -- + local cid = data.dictionaries[1].cid + local all = specification.shapes or false + if cid and cid.fdselect then + readfdselect(f,fontdata,data,glyphs,all,"cff2",specification.streams) + else + readnoselect(f,fontdata,data,glyphs,all,"cff2",specification.streams) + end + cleanup(data,dictionaries) + end +end + +-- temporary helper needed for checking backend patches + +function readers.cffcheck(filename) + local f = io.open(filename,"rb") + if f then + local fontdata = { + glyphs = { }, + } + local header = readheader(f) + if header.major ~= 1 then + report("only version %s is supported for table %a",1,"cff") + return + end + local names = readfontnames(f) + local dictionaries = readtopdictionaries(f) + local strings = readstrings(f) + local glyphs = { } + local data = { + header = header, + names = names, + dictionaries = dictionaries, + strings = strings, + glyphs = glyphs, + nofglyphs = 4, + } + -- + parsedictionaries(data,dictionaries,"cff") + -- + local cid = data.dictionaries[1].cid + if cid and cid.fdselect then + readfdselect(f,fontdata,data,glyphs,false) + else + readnoselect(f,fontdata,data,glyphs,false) + end + return data end end |