diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkiv/font-onr.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/mkiv/font-onr.lua | 250 |
1 files changed, 175 insertions, 75 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-onr.lua b/Master/texmf-dist/tex/context/base/mkiv/font-onr.lua index 2699f25bbfd..85d3604b7c8 100644 --- a/Master/texmf-dist/tex/context/base/mkiv/font-onr.lua +++ b/Master/texmf-dist/tex/context/base/mkiv/font-onr.lua @@ -21,22 +21,21 @@ add features.</p> local fonts, logs, trackers, resolvers = fonts, logs, trackers, resolvers -local next, type, tonumber, rawget = next, type, tonumber, rawget +local next, type, tonumber, rawget, rawset = next, type, tonumber, rawget, rawset local match, lower, gsub, strip, find = string.match, string.lower, string.gsub, string.strip, string.find local char, byte, sub = string.char, string.byte, string.sub local abs = math.abs local bxor, rshift = bit32.bxor, bit32.rshift -local P, S, R, Cmt, C, Ct, Cs, Carg = lpeg.P, lpeg.S, lpeg.R, lpeg.Cmt, lpeg.C, lpeg.Ct, lpeg.Cs, lpeg.Carg +local P, S, R, Cmt, C, Ct, Cs, Carg, Cf, Cg = lpeg.P, lpeg.S, lpeg.R, lpeg.Cmt, lpeg.C, lpeg.Ct, lpeg.Cs, lpeg.Carg, lpeg.Cf, lpeg.Cg local lpegmatch, patterns = lpeg.match, lpeg.patterns local trace_indexing = false trackers.register("afm.indexing", function(v) trace_indexing = v end) local trace_loading = false trackers.register("afm.loading", function(v) trace_loading = v end) local report_afm = logs.reporter("fonts","afm loading") +local report_pfb = logs.reporter("fonts","pfb loading") -fonts = fonts or { } -local handlers = fonts.handlers or { } -fonts.handlers = handlers +local handlers = fonts.handlers local afm = handlers.afm or { } handlers.afm = afm local readers = afm.readers or { } @@ -51,42 +50,10 @@ and <l n='otf'/> reader.</p> and new vectors (we actually had one bad vector with the old loader).</p> --ldx]]-- -local get_indexes +local get_indexes, get_shapes do - local n, m - - local progress = function(str,position,name,size) - local forward = position + tonumber(size) + 3 + 2 - n = n + 1 - if n >= m then - return #str, name - elseif forward < #str then - return forward, name - else - return #str, name - end - end - - local initialize = function(str,position,size) - n = 0 - m = tonumber(size) - return position + 1 - end - - local charstrings = P("/CharStrings") - local name = P("/") * C((R("az")+R("AZ")+R("09")+S("-_."))^1) - local size = C(R("09")^1) - local spaces = P(" ")^1 - - local p_filternames = Ct ( - (1-charstrings)^0 * charstrings * spaces * Cmt(size,initialize) - * (Cmt(name * P(" ")^1 * C(R("09")^1), progress) + P(1))^1 - ) - - -- if one of first 4 not 0-9A-F then binary else hex - local decrypt do @@ -100,62 +67,165 @@ do return char(plain) end - decrypt = function(binary) - r, c1, c2, n = 55665, 52845, 22719, 4 + decrypt = function(binary,initial,seed) + r, c1, c2, n = initial, 52845, 22719, seed binary = gsub(binary,".",step) return sub(binary,n+1) end -- local pattern = Cs((P(1) / step)^1) -- - -- decrypt = function(binary) - -- r, c1, c2, n = 55665, 52845, 22719, 4 + -- decrypt = function(binary,initial,seed) + -- r, c1, c2, n = initial, 52845, 22719, seed -- binary = lpegmatch(pattern,binary) -- return sub(binary,n+1) -- end end - local function loadpfbvector(filename) + local charstrings = P("/CharStrings") + local subroutines = P("/Subrs") + local encoding = P("/Encoding") + local dup = P("dup") + local put = P("put") + local array = P("array") + local name = P("/") * C((R("az")+R("AZ")+R("09")+S("-_."))^1) + local digits = R("09")^1 + local cardinal = digits / tonumber + local spaces = P(" ")^1 + local spacing = patterns.whitespace^0 + + local routines, vector, chars, n, m + + local initialize = function(str,position,size) + n = 0 + m = size -- % tonumber(size) + return position + 1 + end + + local setroutine = function(str,position,index,size) + local forward = position + tonumber(size) + local stream = decrypt(sub(str,position+1,forward),4330,4) + routines[index] = { byte(stream,1,#stream) } + return forward + end + + local setvector = function(str,position,name,size) + local forward = position + tonumber(size) + if n >= m then + return #str + elseif forward < #str then + vector[n] = name + n = n + 1 -- we compensate for notdef at the cff loader end + return forward + else + return #str + end + end + + local setshapes = function(str,position,name,size) + local forward = position + tonumber(size) + local stream = sub(str,position+1,forward) + if n > m then + return #str + elseif forward < #str then + vector[n] = name + n = n + 1 + chars [n] = decrypt(stream,4330,4) + return forward + else + return #str + end + end + + local p_rd = spacing * (P("RD") + P("-|")) + local p_np = spacing * (P("NP") + P( "|")) + local p_nd = spacing * (P("ND") + P( "|")) + + local p_filterroutines = -- dup <i> <n> RD or -| <n encrypted bytes> NP or | + (1-subroutines)^0 * subroutines * spaces * Cmt(cardinal,initialize) + * (Cmt(cardinal * spaces * cardinal * p_rd, setroutine) * p_np + P(1))^1 + + local p_filtershapes = -- /foo <n> RD <n encrypted bytes> ND + (1-charstrings)^0 * charstrings * spaces * Cmt(cardinal,initialize) + * (Cmt(name * spaces * cardinal * p_rd, setshapes) * p_nd + P(1))^1 + + local p_filternames = Ct ( + (1-charstrings)^0 * charstrings * spaces * Cmt(cardinal,initialize) + * (Cmt(name * spaces * cardinal, setvector) + P(1))^1 + ) + + -- /Encoding 256 array + -- 0 1 255 {1 index exch /.notdef put} for + -- dup 0 /Foo put + + local p_filterencoding = + (1-encoding)^0 * encoding * spaces * digits * spaces * array * (1-dup)^0 + * Cf( + Ct("") * Cg(spacing * dup * spaces * cardinal * spaces * name * spaces * put)^1 + ,rawset) + + -- if one of first 4 not 0-9A-F then binary else hex + + local function loadpfbvector(filename,shapestoo) -- for the moment limited to encoding only local data = io.loaddata(resolvers.findfile(filename)) if not data then - print("no data",filename) + report_pfb("no data in %a",filename) return end - if not find(data,"!PS%-AdobeFont%-") then - print("no font",filename) + if not (find(data,"!PS%-AdobeFont%-") or find(data,"%%!FontType1")) then + report_pfb("no font in %a",filename) return end local ascii, binary = match(data,"(.*)eexec%s+......(.*)") if not binary then - print("no binary",filename) + report_pfb("no binary data in %a",filename) return end - binary = decrypt(binary,4) - - local vector = lpegmatch(p_filternames,binary) - - if vector[1] == ".notdef" then - -- tricky - vector[0] = table.remove(vector,1) + binary = decrypt(binary,55665,4) + + local names = { } + local encoding = lpegmatch(p_filterencoding,ascii) + local glyphs = { } + + routines, vector, chars = { }, { }, { } + + if shapestoo then + lpegmatch(p_filterroutines,binary) + lpegmatch(p_filtershapes,binary) + local data = { + dictionaries = { + { + charstrings = chars, + charset = vector, + subroutines = routines, + } + }, + } + fonts.handlers.otf.readers.parsecharstrings(false,data,glyphs,true,true) + else + lpegmatch(p_filternames,binary) end - if not vector then - print("no vector",filename) - return - end + names = vector + + routines, vector, chars = nil, nil, nil - return vector + return names, encoding, glyphs end + local pfb = handlers.pfb or { } + handlers.pfb = pfb + pfb.loadvector = loadpfbvector + get_indexes = function(data,pfbname) local vector = loadpfbvector(pfbname) if vector then @@ -176,6 +246,11 @@ do end end + get_shapes = function(pfbname) + local vector, encoding, glyphs = loadpfbvector(pfbname,true) + return glyphs + end + end --[[ldx-- @@ -184,16 +259,18 @@ and <l n='otf'/> reader. We only need data that is relevant for our use. We don' more complex arrangements like multiple master (obsolete), direction specific kerning, etc.</p> --ldx]]-- -local spacing = patterns.whitespace -local lineend = patterns.newline -local number = spacing * S("+-")^-1 * (R("09") + S("."))^1 / tonumber -local name = spacing * C((1-spacing)^1) -local words = spacing * (1 - lineend)^1 / strip -local rest = (1 - lineend)^0 -local fontdata = Carg(1) -local semicolon = spacing * P(";") -local plus = P("plus") * number -local minus = P("minus") * number +local spacer = patterns.spacer +local whitespace = patterns.whitespace +local lineend = patterns.newline +local spacing = spacer^0 +local number = spacing * S("+-")^-1 * (R("09") + S("."))^1 / tonumber +local name = spacing * C((1 - whitespace)^1) +local words = spacing * ((1 - lineend)^1 / strip) +local rest = (1 - lineend)^0 +local fontdata = Carg(1) +local semicolon = spacing * P(";") +local plus = spacing * P("plus") * number +local minus = spacing * P("minus") * number -- kern pairs @@ -333,6 +410,10 @@ local fullparser = ( P("StartFontMetrics") * fontdata * name / start ) * ( p_charmetrics + p_kernpairs + p_parameters + (1-P("EndFontMetrics")) )^0 * ( P("EndFontMetrics") / stop ) +local fullparser = ( P("StartFontMetrics") * fontdata * name / start ) + * ( p_charmetrics + p_kernpairs + p_parameters + (1-P("EndFontMetrics")) )^0 + * ( P("EndFontMetrics") / stop ) + local infoparser = ( P("StartFontMetrics") * fontdata * name / start ) * ( p_parameters + (1-P("EndFontMetrics")) )^0 * ( P("EndFontMetrics") / stop ) @@ -382,24 +463,43 @@ function readers.loadfont(afmname,pfbname) local data = read(resolvers.findfile(afmname),fullparser) if data then if not pfbname or pfbname == "" then - pfbname = file.replacesuffix(file.nameonly(afmname),"pfb") - pfbname = resolvers.findfile(pfbname) + pfbname = resolvers.findfile(file.replacesuffix(file.nameonly(afmname),"pfb")) end if pfbname and pfbname ~= "" then data.resources.filename = resolvers.unresolve(pfbname) get_indexes(data,pfbname) - elseif trace_loading then + return data + else -- if trace_loading then report_afm("no pfb file for %a",afmname) - -- data.resources.filename = "unset" -- better than loading the afm file + -- better than loading the afm file: data.resources.filename = rawname + -- but that will still crash the backend so we just return nothing now end - return data end end +-- for now, todo: n and check with otf (no afm needed here) + +function readers.loadshapes(filename) + local fullname = resolvers.findfile(filename) or "" + if fullname == "" then + return { + filename = "not found: " .. filename, + glyphs = { } + } + else + return { + filename = fullname, + format = "opentype", + glyphs = get_shapes(fullname) or { }, + units = 1000, + } + end +end + + function readers.getinfo(filename) local data = read(resolvers.findfile(filename),infoparser) if data then return data.metadata end end - |