diff options
| author | Context Git Mirror Bot <phg42.2a@gmail.com> | 2016-08-15 23:17:11 +0200 | 
|---|---|---|
| committer | Context Git Mirror Bot <phg42.2a@gmail.com> | 2016-08-15 23:17:11 +0200 | 
| commit | 30b3a925bfc1857a31e23d9b17b8da0be572d02a (patch) | |
| tree | 994685218d0ab6c1c65df36dcc5a5a08a231171e /tex | |
| parent | 01440ae8999ee20351f0538792e415ade8cd3d5c (diff) | |
| download | context-30b3a925bfc1857a31e23d9b17b8da0be572d02a.tar.gz | |
2016-08-15 22:45:00
Diffstat (limited to 'tex')
26 files changed, 1049 insertions, 613 deletions
diff --git a/tex/context/base/context-version.pdf b/tex/context/base/context-version.pdf Binary files differindex 56b86067d..c59466f1d 100644 --- a/tex/context/base/context-version.pdf +++ b/tex/context/base/context-version.pdf diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv index eab508e59..11508c4c1 100644 --- a/tex/context/base/mkiv/cont-new.mkiv +++ b/tex/context/base/mkiv/cont-new.mkiv @@ -11,7 +11,7 @@  %C therefore copyrighted by \PRAGMA. See mreadme.pdf for  %C details. -\newcontextversion{2016.08.11 13:56} +\newcontextversion{2016.08.15 22:40}  %D This file is loaded at runtime, thereby providing an excellent place for  %D hacks, patches, extensions and new features. diff --git a/tex/context/base/mkiv/context.mkiv b/tex/context/base/mkiv/context.mkiv index dd2143252..fc4b3427a 100644 --- a/tex/context/base/mkiv/context.mkiv +++ b/tex/context/base/mkiv/context.mkiv @@ -39,7 +39,7 @@  %D up and the dependencies are more consistent.  \edef\contextformat {\jobname} -\edef\contextversion{2016.08.11 13:56} +\edef\contextversion{2016.08.15 22:40}  \edef\contextkind   {beta}  %D For those who want to use this: diff --git a/tex/context/base/mkiv/font-cff.lua b/tex/context/base/mkiv/font-cff.lua index 8c57b473e..8f33c76c4 100644 --- a/tex/context/base/mkiv/font-cff.lua +++ b/tex/context/base/mkiv/font-cff.lua @@ -26,6 +26,7 @@ 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 formatters = string.formatters  local readers           = fonts.handlers.otf.readers  local streamreader      = readers.streamreader @@ -594,6 +595,7 @@ do      local ymax       = 0      local checked    = false      local keepcurve  = false +    local version    = 2      local function showstate(where)          report("%w%-10s : [%s] n=%i",depth*2,where,concat(stack," ",1,top),top) @@ -1052,13 +1054,114 @@ do          end      end -    local function unsupported() +    local function unsupported(t)          if trace_charstrings then -            showstate("unsupported") +            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("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 +      -- Bah, we cannot use a fast lpeg because a hint has an unknown size and a      -- runtime capture cannot handle that well. @@ -1076,7 +1179,7 @@ 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 @@ -1098,6 +1201,17 @@ 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, @@ -1107,23 +1221,29 @@ do      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 +        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 +                if type(tab) == "string" then +                    tab = lpegmatch(p_bytes,tab) +                    list[index] = tab +                end +                process(tab) +            else +                showstate(formatters["unknown %s call %i"](scope,index)) +                top = 0 +            end          end +        depth = depth - 1      end      local function process(tab) @@ -1131,7 +1251,7 @@ do          local n = #tab          while i <= n do              local t = tab[i] -            if t >= 32 and t<=246 then +            if t >= 32 and t <= 246 then                  -- -107 .. +107                  top = top + 1                  stack[top] = t - 139 @@ -1196,7 +1316,7 @@ do                  local t = tab[i]                  local a = subactions[t]                  if a then -                    a() +                    a(t)                  else                      if trace_charstrings then                          showvalue("<subaction>",t) @@ -1207,7 +1327,7 @@ do              else                  local a = actions[t]                  if a then -                    local s = a() +                    local s = a(t)                      if s then                          i = i + s                      end @@ -1260,27 +1380,44 @@ do   --     end   -- end -    parsecharstrings = function(data,glyphs,doshapes) +    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 +    end + +    parsecharstrings = function(data,glyphs,doshapes,tversion)          -- for all charstrings          local dictionary  = data.dictionaries[1]          local charstrings = dictionary.charstrings          local charset     = dictionary.charset +        local private     = dictionary.private or { data = { } } +          keepcurve  = doshapes +        version    = tversion          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 +        globals    = data.routines or { } +        locals     = dictionary.subroutines or { } + +        globalbias, localbias = setbias(globals,locals,version) + +        local nominalwidth = private.data.nominalwidthx or 0 +        local defaultwidth = private.data.defaultwidthx or 0          for i=1,#charstrings do -            local str   = charstrings[i] -            local tab   = lpegmatch(p_bytes,str) +            local tab = charstrings[i] +            if type(tab) == "string" then +                tab = lpegmatch(p_bytes,tab) +            end              local index = i - 1              x       = 0              y       = 0 @@ -1341,20 +1478,22 @@ do          return glyphs      end -    parsecharstring = function(data,dictionary,charstring,glyphs,index,doshapes) +    parsecharstring = function(data,dictionary,tab,glyphs,index,doshapes,version)          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 + +        globalbias = setbias(globals,locals) +          local nominalwidth = private and private.data.nominalwidthx or 0          local defaultwidth = private and private.data.defaultwidthx or 0          -- -        local tab = lpegmatch(p_bytes,charstring) +        if type(tab) == "string" then +            tab = lpegmatch(p_bytes,tab) +        end +        --          x         = 0          y         = 0          width     = false @@ -1384,7 +1523,8 @@ do              width = nominalwidth + width          end          -- -index = index - 1 +        index = index - 1 +        --          local glyph = glyphs[index] -- can be autodefined in otr          if not glyph then              glyphs[index] = { @@ -1410,8 +1550,6 @@ index = index - 1              report("width: %s",tostring(width))              report("boundingbox: % t",boundingbox)          end -        -- -        return charstring      end      resetcharstrings = function() @@ -1542,7 +1680,7 @@ local function readcidprivates(f,data)      parseprivates(data,dictionaries)  end -local function readnoselect(f,data,glyphs,doshapes) +local function readnoselect(f,data,glyphs,doshapes,version)      local dictionaries = data.dictionaries      local dictionary   = dictionaries[1]      readglobals(f,data) @@ -1552,11 +1690,13 @@ local function readnoselect(f,data,glyphs,doshapes)      readprivates(f,data)      parseprivates(data,data.dictionaries)      readlocals(f,data,dictionary) -    parsecharstrings(data,glyphs,doshapes) +    parsecharstrings(data,glyphs,doshapes,version)      resetcharstrings()  end -local function readfdselect(f,data,glyphs,doshapes) +readers.parsecharstrings = parsecharstrings + +local function readfdselect(f,data,glyphs,doshapes,version)      local header       = data.header      local dictionaries = data.dictionaries      local dictionary   = dictionaries[1] @@ -1615,7 +1755,7 @@ local function readfdselect(f,data,glyphs,doshapes)              readlocals(f,data,dictionaries[i])          end          for i=1,#charstrings do -            parsecharstring(data,dictionaries[fdindex[i]+1],charstrings[i],glyphs,i,doshapes) +            parsecharstring(data,dictionaries[fdindex[i]+1],charstrings[i],glyphs,i,doshapes,version)          end          resetcharstrings()      end diff --git a/tex/context/base/mkiv/font-lib.mkvi b/tex/context/base/mkiv/font-lib.mkvi index 6b891542c..ed7d896c5 100644 --- a/tex/context/base/mkiv/font-lib.mkvi +++ b/tex/context/base/mkiv/font-lib.mkvi @@ -61,6 +61,10 @@  %registerctxluafile{font-afm}{1.001}  \registerctxluafile{font-afk}{1.001} +% shapes + +\registerctxluafile{font-shp}{1.001} +  % tfm  \registerctxluafile{font-tfm}{1.001} diff --git a/tex/context/base/mkiv/font-onr.lua b/tex/context/base/mkiv/font-onr.lua index dcf7445e5..6c33b24c6 100644 --- a/tex/context/base/mkiv/font-onr.lua +++ b/tex/context/base/mkiv/font-onr.lua @@ -50,31 +50,41 @@ 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 decrypt -    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 +    do + +        local r, c1, c2, n = 0, 0, 0, 0 + +        local function step(c) +            local cipher = byte(c) +            local plain  = bxor(cipher,rshift(r,8)) +            r = ((cipher + r) * c1 + c2) % 65536 +            return char(plain)          end -    end -    local initialize = function(str,position,size) -        n = 0 -        m = size -- % tonumber(size) -        return position + 1 +        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,initial,seed) +     --     r, c1, c2, n = initial, 52845, 22719, seed +     --     binary = lpegmatch(pattern,binary) +     --     return sub(binary,n+1) +     -- end +      end      local charstrings   = P("/CharStrings") +    local subroutines   = P("/Subrs")      local encoding      = P("/Encoding")      local dup           = P("dup")      local put           = P("put") @@ -85,9 +95,64 @@ do      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  = sub(str,position+1,forward) +        routines[index] = decrypt(stream,4330,4) +        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, progress) + P(1))^1 +        * (Cmt(name * spaces * cardinal, setvector) + P(1))^1      )      -- /Encoding 256 array @@ -102,36 +167,7 @@ do      -- if one of first 4 not 0-9A-F then binary else hex -    local decrypt - -    do - -        local r, c1, c2, n = 0, 0, 0, 0 - -        local function step(c) -            local cipher = byte(c) -            local plain  = bxor(cipher,rshift(r,8)) -            r = ((cipher + r) * c1 + c2) % 65536 -            return char(plain) -        end - -        decrypt = function(binary) -            r, c1, c2, n = 55665, 52845, 22719, 4 -            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 -     --     binary = lpegmatch(pattern,binary) -     --     return sub(binary,n+1) -     -- end - -    end - -    local function loadpfbvector(filename) +    local function loadpfbvector(filename,shapestoo)          -- for the moment limited to encoding only          local data = io.loaddata(resolvers.findfile(filename)) @@ -153,28 +189,36 @@ do              return          end -        binary = decrypt(binary,4) +        binary = decrypt(binary,55665,4) -        local vector = lpegmatch(p_filternames,binary) - ---         if vector[1] == ".notdef" then ---             -- tricky ---             vector[0] = table.remove(vector,1) ---         end - -        for i=1,#vector do -            vector[i-1] = vector[i] +        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(data,glyphs,true,true) +        else +            lpegmatch(p_filternames,binary)          end -        vector[#vector] = nil -        if not vector then -            report_pfb("no vector in %a",filename) -            return -        end +        names = vector -        local encoding = lpegmatch(p_filterencoding,ascii) +        routines, vector, chars = nil, nil, nil -        return vector, encoding +        return names, encoding, glyphs      end @@ -202,6 +246,11 @@ do          end      end +    get_shapes = function(pfbname) +        local vector, encoding, glyphs = loadpfbvector(pfbname,true) +        return glyphs +    end +  end  --[[ldx-- @@ -428,6 +477,26 @@ function readers.loadfont(afmname,pfbname)      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 diff --git a/tex/context/base/mkiv/font-otr.lua b/tex/context/base/mkiv/font-otr.lua index 7c81285c1..9cdbc3df0 100644 --- a/tex/context/base/mkiv/font-otr.lua +++ b/tex/context/base/mkiv/font-otr.lua @@ -1747,118 +1747,6 @@ function readers.math(f,fontdata,specification)      end  end --- Goodie. A sequence instead of segments costs a bit more memory, some 300K on a --- dejavu serif and about the same on a pagella regular. - -local function packoutlines(data,makesequence) -    local subfonts = data.subfonts -    if subfonts then -        for i=1,#subfonts do -            packoutlines(subfonts[i],makesequence) -        end -        return -    end -    local common = data.segments -    if common then -        return -    end -    local glyphs = data.glyphs -    if not glyphs then -        return -    end -    if makesequence then -        for index=1,#glyphs do -            local glyph = glyphs[index] -            local segments = glyph.segments -            if segments then -                local sequence    = { } -                local nofsequence = 0 -                for i=1,#segments do -                    local segment    = segments[i] -                    local nofsegment = #segment -                    nofsequence = nofsequence + 1 -                    sequence[nofsequence] = segment[nofsegment] -                    for i=1,nofsegment-1 do -                        nofsequence = nofsequence + 1 -                        sequence[nofsequence] = segment[i] -                    end -                end -                glyph.sequence = sequence -                glyph.segments = nil -            end -        end -    else -        local hash    = { } -        local common  = { } -        local reverse = { } -        local last    = 0 -        for index=1,#glyphs do -            local segments = glyphs[index].segments -            if segments then -                for i=1,#segments do -                    local h = concat(segments[i]," ") -                    hash[h] = (hash[h] or 0) + 1 -                end -            end -        end -        for index=1,#glyphs do -            local segments = glyphs[index].segments -            if segments then -                for i=1,#segments do -                    local segment = segments[i] -                    local h = concat(segment," ") -                    if hash[h] > 1 then -- minimal one shared in order to hash -                        local idx = reverse[h] -                        if not idx then -                            last = last + 1 -                            reverse[h] = last -                            common[last] = segment -                            idx = last -                        end -                        segments[i] = idx -                    end -                end -            end -        end -        if last > 0 then -            data.segments = common -        end -    end -end - -local function unpackoutlines(data) -    local subfonts = data.subfonts -    if subfonts then -        for i=1,#subfonts do -            unpackoutlines(subfonts[i]) -        end -        return -    end -    local common = data.segments -    if not common then -        return -    end -    local glyphs = data.glyphs -    if not glyphs then -        return -    end -    for index=1,#glyphs do -        local segments = glyphs[index].segments -        if segments then -            for i=1,#segments do -                local c = common[segments[i]] -                if c then -                    segments[i] = c -                end -            end -        end -    end -    data.segments = nil -end - -otf.packoutlines   = packoutlines -otf.unpackoutlines = unpackoutlines -  -- Now comes the loader. The order of reading these matters as we need to know  -- some properties in order to read following tables. When details is true we also  -- initialize the glyphs data. @@ -2152,6 +2040,15 @@ function readers.loadshapes(filename,n)          shapes   = true,          subfont  = n,      } +    if fontdata then +        -- easier on luajit but still we can hit the 64 K stack constants issue +        for k, v in next, fontdata.glyphs do +            v.class = nil +            v.index = nil +            v.math  = nil +         -- v.name  = nil +        end +    end      return fontdata and {       -- version  = 0.123 -- todo          filename = filename, @@ -2302,63 +2199,3 @@ function readers.extend(fontdata)          end      end  end - --- for now .. this will move to a context specific file - -if fonts.hashes then - -    local identifiers = fonts.hashes.identifiers -    local loadshapes  = readers.loadshapes - -    readers.version  = 0.006 -    readers.cache    = containers.define("fonts", "shapes", readers.version, true) - -    -- todo: loaders per format - -    local function load(filename,sub) -        local base = file.basename(filename) -        local name = file.removesuffix(base) -        local kind = file.suffix(filename) -        local attr = lfs.attributes(filename) -        local size = attr and attr.size or 0 -        local time = attr and attr.modification or 0 -        local sub  = tonumber(sub) -        if size > 0 and (kind == "otf" or kind == "ttf" or kind == "tcc") then -            local hash = containers.cleanname(base) -- including suffix -            if sub then -                hash = hash .. "-" .. sub -            end -            data = containers.read(readers.cache,hash) -            if not data or data.time ~= time or data.size  ~= size then -                data = loadshapes(filename,sub) -                if data then -                    data.size   = size -                    data.format = data.format or (kind == "otf" and "opentype") or "truetype" -                    data.time   = time -                    packoutlines(data) -                    containers.write(readers.cache,hash,data) -                    data = containers.read(readers.cache,hash) -- frees old mem -                end -            end -            unpackoutlines(data) -        else -            data = { -                filename = filename, -                size     = 0, -                time     = time, -                format   = "unknown", -                units    = 1000, -                glyphs   = { } -            } -        end -        return data -    end - -    fonts.hashes.shapes = table.setmetatableindex(function(t,k) -        local d = identifiers[k] -        local v = load(d.properties.filename,d.subindex) -        t[k] = v -        return v -    end) - -end diff --git a/tex/context/base/mkiv/font-ots.lua b/tex/context/base/mkiv/font-ots.lua index d37115603..8443a383d 100644 --- a/tex/context/base/mkiv/font-ots.lua +++ b/tex/context/base/mkiv/font-ots.lua @@ -3665,7 +3665,7 @@ if fontfeatures then      function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr)          local features = fontfeatures[font] -        local enabled  = features.spacekern == true and features.kern == true +        local enabled  = features and features.spacekern and features.kern          if enabled then              setspacekerns(font,sequence)          end @@ -3677,7 +3677,7 @@ else -- generic (no hashes)      function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr)          local shared   = fontdata[font].shared          local features = shared and shared.features -        local enabled  = features and features.spacekern == true and features.kern == true +        local enabled  = features and features.spacekern and features.kern          if enabled then              setspacekerns(font,sequence)          end @@ -3739,7 +3739,7 @@ local function spaceinitializer(tfmdata,value) -- attr                      if kern then                          if feat then                              for script, languages in next, kern do -                                local f = feat[k] +                                local f = feat[script]                                  if f then                                      for l in next, languages do                                          f[l] = true @@ -3759,7 +3759,7 @@ local function spaceinitializer(tfmdata,value) -- attr                                  if kerns then                                      for k, v in next, kerns do                                          if type(v) == "table" then -                                            right[k] = v[3] -- needs checking +                                            right[k] = v[1][3]                                          else                                              right[k] = v                                          end @@ -3769,7 +3769,7 @@ local function spaceinitializer(tfmdata,value) -- attr                                      local kern = v[32]                                      if kern then                                          if type(kern) == "table" then -                                            left[k] = kern[3] -- needs checking +                                            left[k] = kern[1][3]                                          else                                              left[k] = kern                                          end diff --git a/tex/context/base/mkiv/font-shp.lua b/tex/context/base/mkiv/font-shp.lua new file mode 100644 index 000000000..92ff70127 --- /dev/null +++ b/tex/context/base/mkiv/font-shp.lua @@ -0,0 +1,193 @@ +if not modules then modules = { } end modules ['font-shp'] = { +    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" +} + +local concat = table.concat +local load, tonumber = load, tonumber + +local otf         = fonts.handlers.otf +local afm         = fonts.handlers.afm + +local hashes      = fonts.hashes +local identifiers = hashes.identifiers + +local version     = 0.006 +local cache       = containers.define("fonts", "shapes", version, true) + +-- shapes (can be come a separate file at some point) + +local function packoutlines(data,makesequence) +    local subfonts = data.subfonts +    if subfonts then +        for i=1,#subfonts do +            packoutlines(subfonts[i],makesequence) +        end +        return +    end +    local common = data.segments +    if common then +        return +    end +    local glyphs = data.glyphs +    if not glyphs then +        return +    end +    if makesequence then +        for index=1,#glyphs do +            local glyph = glyphs[index] +            local segments = glyph.segments +            if segments then +                local sequence    = { } +                local nofsequence = 0 +                for i=1,#segments do +                    local segment    = segments[i] +                    local nofsegment = #segment +                    nofsequence = nofsequence + 1 +                    sequence[nofsequence] = segment[nofsegment] +                    for i=1,nofsegment-1 do +                        nofsequence = nofsequence + 1 +                        sequence[nofsequence] = segment[i] +                    end +                end +                glyph.sequence = sequence +                glyph.segments = nil +            end +        end +    else +        local hash    = { } +        local common  = { } +        local reverse = { } +        local last    = 0 +        for index=1,#glyphs do +            local segments = glyphs[index].segments +            if segments then +                for i=1,#segments do +                    local h = concat(segments[i]," ") +                    hash[h] = (hash[h] or 0) + 1 +                end +            end +        end +        for index=1,#glyphs do +            local segments = glyphs[index].segments +            if segments then +                for i=1,#segments do +                    local segment = segments[i] +                    local h = concat(segment," ") +                    if hash[h] > 1 then -- minimal one shared in order to hash +                        local idx = reverse[h] +                        if not idx then +                            last = last + 1 +                            reverse[h] = last +                            common[last] = segment +                            idx = last +                        end +                        segments[i] = idx +                    end +                end +            end +        end +        if last > 0 then +            data.segments = common +        end +    end +end + +local function unpackoutlines(data) +    local subfonts = data.subfonts +    if subfonts then +        for i=1,#subfonts do +            unpackoutlines(subfonts[i]) +        end +        return +    end +    local common = data.segments +    if not common then +        return +    end +    local glyphs = data.glyphs +    if not glyphs then +        return +    end +    for index=1,#glyphs do +        local segments = glyphs[index].segments +        if segments then +            for i=1,#segments do +                local c = common[segments[i]] +                if c then +                    segments[i] = c +                end +            end +        end +    end +    data.segments = nil +end + +-- todo: loaders per format + +local function load(filename,sub) +    local base = file.basename(filename) +    local name = file.removesuffix(base) +    local kind = file.suffix(filename) +    local attr = lfs.attributes(filename) +    local size = attr and attr.size or 0 +    local time = attr and attr.modification or 0 +    local sub  = tonumber(sub) + +    -- fonts.formats + +    if size > 0 and (kind == "otf" or kind == "ttf" or kind == "tcc") then +        local hash = containers.cleanname(base) -- including suffix +        if sub then +            hash = hash .. "-" .. sub +        end +        data = containers.read(cache,hash) +        if not data or data.time ~= time or data.size  ~= size then +            data = otf.readers.loadshapes(filename,sub) +            if data then +                data.size   = size +                data.format = data.format or (kind == "otf" and "opentype") or "truetype" +                data.time   = time +                packoutlines(data) +                containers.write(cache,hash,data) +                data = containers.read(cache,hash) -- frees old mem +            end +        end +        unpackoutlines(data) +    elseif size > 0 and (kind == "pfb") then +        local hash = containers.cleanname(base) -- including suffix +        data = containers.read(cache,hash) +        if not data or data.time ~= time or data.size  ~= size then +            data = afm.readers.loadshapes(filename) +            if data then +                data.size   = size +                data.format = "type1" +                data.time   = time +                packoutlines(data) +                containers.write(cache,hash,data) +                data = containers.read(cache,hash) -- frees old mem +            end +        end +        unpackoutlines(data) +    else +        data = { +            filename = filename, +            size     = 0, +            time     = time, +            format   = "unknown", +            units    = 1000, +            glyphs   = { } +        } +    end +    return data +end + +hashes.shapes = table.setmetatableindex(function(t,k) +    local d = identifiers[k] +    local v = load(d.properties.filename,d.subindex) +    t[k] = v +    return v +end) diff --git a/tex/context/base/mkiv/luat-mac.lua b/tex/context/base/mkiv/luat-mac.lua index 4274fe9f9..3f1fe6751 100644 --- a/tex/context/base/mkiv/luat-mac.lua +++ b/tex/context/base/mkiv/luat-mac.lua @@ -145,9 +145,8 @@ local grammar = { "converter",                  * stopcode                  * poplocal,      texbody     = ( -leadingcomment -- new per 2015-03-03 (ugly) -+ -                      V("definition") +                      leadingcomment -- new per 2015-03-03 (ugly) +                    + V("definition")                      + identifier                      + V("braced")                      + (1 - stopcode) diff --git a/tex/context/base/mkiv/math-map.lua b/tex/context/base/mkiv/math-map.lua index 4eb76ac8c..cf9353e95 100644 --- a/tex/context/base/mkiv/math-map.lua +++ b/tex/context/base/mkiv/math-map.lua @@ -34,7 +34,7 @@ if not modules then modules = { } end modules ['math-map'] = {  local type, next = type, next  local floor, div = math.floor, math.div -local merged = table.merged +local merged, sortedhash = table.merged, table.sortedhash  local extract = bit32.extract  local allocate            = utilities.storage.allocate @@ -557,10 +557,10 @@ mathematics.mapremap  = mathremap  local boldmap         = allocate { }  mathematics.boldmap   = boldmap --- all math (a bit of redundancy here) +-- all math (a bit of redundancy here) (sorted for tracing) -for alphabet, styles in next, alphabets do -- per 9/6/2011 we also have attr for missing -    for style, data in next, styles do +for alphabet, styles in sortedhash(alphabets) do -- per 9/6/2011 we also have attr for missing +    for style, data in sortedhash(styles) do       -- let's keep the long names (for tracing)          local n = #mathremap + 1          local d = { diff --git a/tex/context/base/mkiv/meta-imp-outlines.mkiv b/tex/context/base/mkiv/meta-imp-outlines.mkiv index ab6fcdd3d..199dadb32 100644 --- a/tex/context/base/mkiv/meta-imp-outlines.mkiv +++ b/tex/context/base/mkiv/meta-imp-outlines.mkiv @@ -54,7 +54,7 @@ function metapost.showglyph(specification)      local fontid      = font.current()      local shapedata   = fonts.hashes.shapes[fontid] -- by index      local chardata    = fonts.hashes.characters[fontid] -- by unicode -    local shapeglyphs = shapedata.glyphs +    local shapeglyphs = shapedata.glyphs or { }      local character   = validstring(specification.character)      local index       = validstring(specification.index)      local alternative = validstring(specification.alternative) @@ -181,6 +181,8 @@ end  \usemodule[art-01] +% \definedfont[lt55476.afm] +  \startcombination[3*1]      {\ruledhbox{\startMPcode draw textext("\showshape[character=a]") ; \stopMPcode}} {}      {\ruledhbox{\startMPcode draw textext("\showshape[character=x]") ; \stopMPcode}} {} diff --git a/tex/context/base/mkiv/meta-tex.lua b/tex/context/base/mkiv/meta-tex.lua index 1008e45c0..9c5a2186d 100644 --- a/tex/context/base/mkiv/meta-tex.lua +++ b/tex/context/base/mkiv/meta-tex.lua @@ -187,9 +187,9 @@ function mp.format(fmt,str)      mpprint(f_textext(formatters[fmt](metapost.untagvariable(str,false))))  end -function mp.formatted(fmt,num) -- svformat +function mp.formatted(fmt,...) -- svformat      fmt = lpegmatch(cleaner,fmt) -    mpprint(f_textext(formatters[fmt](tonumber(num) or num))) +    mpprint(f_textext(formatters[fmt](...)))  end  function mp.graphformat(fmt,num) -- nvformat diff --git a/tex/context/base/mkiv/mlib-lua.lua b/tex/context/base/mkiv/mlib-lua.lua index 7b2c67220..93ae74244 100644 --- a/tex/context/base/mkiv/mlib-lua.lua +++ b/tex/context/base/mkiv/mlib-lua.lua @@ -412,7 +412,6 @@ function mp.tb_dimensions(category,name)      mptriplet(w/factor,h/factor,d/factor)  end -  function mp.report(a,b)      if b then          report_message("%s : %s",a,b) diff --git a/tex/context/base/mkiv/mlib-pps.lua b/tex/context/base/mkiv/mlib-pps.lua index f72061372..8d200ac63 100644 --- a/tex/context/base/mkiv/mlib-pps.lua +++ b/tex/context/base/mkiv/mlib-pps.lua @@ -1160,16 +1160,17 @@ local function sh_process(object,prescript,before,after)      local sh_type = prescript.sh_type      if sh_type then          nofshades = nofshades + 1 -        local domain   = lpegmatch(domainsplitter,prescript.sh_domain   or "0 1") -        local centera  = lpegmatch(centersplitter,prescript.sh_center_a or "0 0") -        local centerb  = lpegmatch(centersplitter,prescript.sh_center_b or "0 0") +        local domain    = lpegmatch(domainsplitter,prescript.sh_domain   or "0 1") +        local centera   = lpegmatch(centersplitter,prescript.sh_center_a or "0 0") +        local centerb   = lpegmatch(centersplitter,prescript.sh_center_b or "0 0") +        local transform = toboolean(prescript.sh_transform or "yes",true)          -- compensation for scaling          local sx = 1          local sy = 1          local sr = 1          local dx = 0          local dy = 0 -        if true then +        if transform then              local first = lpegmatch(coordinatesplitter,prescript.sh_first or "0 0")              local setx  = lpegmatch(coordinatesplitter,prescript.sh_set_x or "0 0")              local sety  = lpegmatch(coordinatesplitter,prescript.sh_set_y or "0 0") diff --git a/tex/context/base/mkiv/mtx-context-xml.tex b/tex/context/base/mkiv/mtx-context-xml.tex index 8e4d229f5..f8bfeef3a 100644 --- a/tex/context/base/mkiv/mtx-context-xml.tex +++ b/tex/context/base/mkiv/mtx-context-xml.tex @@ -18,12 +18,14 @@  % usage: context --extra=xml [options] list-of-files  %  % --analyze             : show elements and characters +% --template            : also export template  % --topspace=dimension  : distance above first line  % --backspace=dimension : distance before left margin  % --bodyfont=list       : additional bodyfont settings  % --paperformat=spec    : paper*print or paperxprint  %  % context --extra=xml --analyze path::i-context.xml +% context --extra=xml --analyze --template path::i-context.xml  % context --extra=xml --analyze selfautoparent:texmf-context/tex/context/interface/mkiv/i-*.xml  % end help @@ -52,8 +54,10 @@  \starttext  \startluacode -    local files   = document.files -    local pattern = document.arguments.pattern or (#files == 1 and files[1]) +    local files    = document.files +    local pattern  = document.arguments.pattern or (#files == 1 and files[1]) +    local analyze  = document.arguments.analyze +    local template = document.arguments.template      if pattern then          files = dir.glob(pattern) @@ -63,12 +67,15 @@      end      if #files > 0 then -        if document.arguments.analyze then -            moduledata.xml.analyzers.structure (files) +        if analyze then +            moduledata.xml.analyzers.structure(files)              context.page()              moduledata.xml.analyzers.characters(files)              context.page()              moduledata.xml.analyzers.entities(files) +            if template then +                moduledata.xml.analyzers.allsetups(files,type(template) == "string" and template or nil) +            end          else              context("no action given")          end diff --git a/tex/context/base/mkiv/mult-fun.lua b/tex/context/base/mkiv/mult-fun.lua index c6d321949..5996b9ac6 100644 --- a/tex/context/base/mkiv/mult-fun.lua +++ b/tex/context/base/mkiv/mult-fun.lua @@ -24,7 +24,7 @@ return {          "invsin", "invcos", "invtan", "acosh", "asinh", "sinh", "cosh",          "zmod",          "paired", "tripled", -        "unitcircle", "fulldiamond", "unitdiamond", "fullsquare", +        "unitcircle", "fulldiamond", "unitdiamond", "fullsquare", "unittriangle", "fulltriangle",       -- "halfcircle", "quartercircle",          "llcircle", "lrcircle", "urcircle", "ulcircle",          "tcircle", "bcircle", "lcircle", "rcircle", @@ -45,8 +45,10 @@ return {          "withshade", "withcircularshade", "withlinearshade", -- old but kept          "defineshade", "shaded",       -- "withshading", "withlinearshading", "withcircularshading", "withfromshadecolor", "withtoshadecolor", -        "shadedinto", "withshadecolors", "withshadedomain", "withshademethod", "withshadefactor", "withshadevector", -        "withshadecenter", "withshadedirection", "withshadestep", "withshadefraction", +        "shadedinto", "withshadecolors", +        "withshadedomain", "withshademethod", "withshadefactor", "withshadevector", +        "withshadecenter", "withshadedirection", "withshaderadius", "withshadetransform", +        "withshadestep", "withshadefraction",          "cmyk", "spotcolor", "multitonecolor", "namedcolor",          "drawfill", "undrawfill",          "inverted", "uncolored", "softened", "grayed", "greyed", diff --git a/tex/context/base/mkiv/node-ini.lua b/tex/context/base/mkiv/node-ini.lua index f8720f717..1a9d141f4 100644 --- a/tex/context/base/mkiv/node-ini.lua +++ b/tex/context/base/mkiv/node-ini.lua @@ -248,6 +248,7 @@ local accentcodes = mark(getsubtypes("accent"))  --     [1] = "left",  --     [2] = "middle",  --     [3] = "right", +--     [4] = "no",  -- }  local fencecodes = mark(getsubtypes("fence")) @@ -274,6 +275,18 @@ local usercodes = allocate {      [116] = "tokens"      -- t  } +local noadoptions = allocate { +    set      =        0x08, +    unused_1 = 0x00 + 0x08, +    unused_2 = 0x01 + 0x08, +    axis     = 0x02 + 0x08, +    no_axis  = 0x04 + 0x08, +    exact    = 0x10 + 0x08, +    left     = 0x11 + 0x08, +    middle   = 0x12 + 0x08, +    right    = 0x14 + 0x08, +} +  skipcodes     = allocate(swapped(skipcodes,skipcodes))  boundarycodes = allocate(swapped(boundarycodes,boundarycodes))  noadcodes     = allocate(swapped(noadcodes,noadcodes)) @@ -293,6 +306,7 @@ fencecodes    = allocate(swapped(fencecodes,fencecodes))  rulecodes     = allocate(swapped(rulecodes,rulecodes))  leadercodes   = allocate(swapped(leadercodes,leadercodes))  usercodes     = allocate(swapped(usercodes,usercodes)) +noadoptions   = allocate(swapped(noadoptions,noadoptions))  nodes.skipcodes     = skipcodes  nodes.boundarycodes = boundarycodes @@ -313,6 +327,7 @@ nodes.fencecodes    = fencecodes  nodes.rulecodes     = rulecodes  nodes.leadercodes   = leadercodes  nodes.usercodes     = usercodes +nodes.noadoptions   = noadoptions  nodes.gluecodes          = skipcodes -- more official  nodes.whatsitcodes       = whatcodes -- more official @@ -327,25 +342,38 @@ kerncodes.kerning          = kerncodes.fontkern  kerncodes.italiccorrection = kerncodes.italiccorrection or 1 -- new  nodes.codes = allocate { -- mostly for listing -    glue     = skipcodes, -    boundary = boundarycodes, -    noad     = noadcodes, -    node     = nodecodes, -    hlist    = listcodes, -    vlist    = listcodes, -    glyph    = glyphcodes, -    kern     = kerncodes, -    penalty  = penaltycodes, -    math     = mathnodes, -    fill     = fillcodes, -    margin   = margincodes, -    disc     = disccodes, -    whatsit  = whatcodes, -    accent   = accentcodes, -    fence    = fencecodes, -    rule     = rulecodes, -    leader   = leadercodes, -    user     = usercodes, +    glue        = skipcodes, +    boundary    = boundarycodes, +    noad        = noadcodes, +    node        = nodecodes, +    hlist       = listcodes, +    vlist       = listcodes, +    glyph       = glyphcodes, +    kern        = kerncodes, +    penalty     = penaltycodes, +    math        = mathnodes, +    fill        = fillcodes, +    margin      = margincodes, +    disc        = disccodes, +    whatsit     = whatcodes, +    accent      = accentcodes, +    fence       = fencecodes, +    rule        = rulecodes, +    leader      = leadercodes, +    user        = usercodes, +    noadoptions = noadoptions, +} + +nodes.noadoptions = { +    set      =        0x08, +    unused_1 = 0x00 + 0x08, +    unused_2 = 0x01 + 0x08, +    axis     = 0x02 + 0x08, +    no_axis  = 0x04 + 0x08, +    exact    = 0x10 + 0x08, +    left     = 0x11 + 0x08, +    middle   = 0x12 + 0x08, +    right    = 0x14 + 0x08,  }  local report_codes = logs.reporter("nodes","codes") diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf Binary files differindex 3192f32d8..10ad1bcfd 100644 --- a/tex/context/base/mkiv/status-files.pdf +++ b/tex/context/base/mkiv/status-files.pdf diff --git a/tex/context/base/mkiv/status-lua.pdf b/tex/context/base/mkiv/status-lua.pdf Binary files differindex 4dc611165..05f1666a9 100644 --- a/tex/context/base/mkiv/status-lua.pdf +++ b/tex/context/base/mkiv/status-lua.pdf diff --git a/tex/context/base/mkiv/trac-inf.lua b/tex/context/base/mkiv/trac-inf.lua index a1d7fb0a0..12a4f646f 100644 --- a/tex/context/base/mkiv/trac-inf.lua +++ b/tex/context/base/mkiv/trac-inf.lua @@ -61,12 +61,13 @@ local function stoptiming(instance)          timer.timing = it - 1      else          local starttime = timer.starttime -        if starttime then -            local stoptime = clock() -            local loadtime = stoptime - starttime -            timer.stoptime = stoptime -            timer.loadtime = timer.loadtime + loadtime -            timer.timing = 0 +        if starttime and starttime > 0 then +            local stoptime  = clock() +            local loadtime  = stoptime - starttime +            timer.stoptime  = stoptime +            timer.loadtime  = timer.loadtime + loadtime +            timer.timing    = 0 +            timer.starttime = 0              return loadtime          end      end @@ -183,7 +184,7 @@ end  function statistics.runtime()      stoptiming(statistics) -    stoptiming(statistics) -- somehow we can start the timer twice, but where + --  stoptiming(statistics) -- somehow we can start the timer twice, but where      return statistics.formatruntime(elapsedtime(statistics))  end diff --git a/tex/context/interface/mkiv/i-context.pdf b/tex/context/interface/mkiv/i-context.pdf Binary files differindex 7a04caa92..6f9fc8a56 100644 --- a/tex/context/interface/mkiv/i-context.pdf +++ b/tex/context/interface/mkiv/i-context.pdf diff --git a/tex/context/interface/mkiv/i-readme.pdf b/tex/context/interface/mkiv/i-readme.pdf Binary files differindex 21a81dd2a..621a2513b 100644 --- a/tex/context/interface/mkiv/i-readme.pdf +++ b/tex/context/interface/mkiv/i-readme.pdf diff --git a/tex/context/modules/mkiv/s-xml-analyzers.lua b/tex/context/modules/mkiv/s-xml-analyzers.lua index 99f6a1cdf..6e7f7f2ba 100644 --- a/tex/context/modules/mkiv/s-xml-analyzers.lua +++ b/tex/context/modules/mkiv/s-xml-analyzers.lua @@ -11,6 +11,8 @@ moduledata.xml.analyzers = moduledata.xml.analyzers or { }  local next, type = next, type  local utfvalues = string.utfvalues +local formatters = string.formatters +local setmetatableindex = table.setmetatableindex  local context = context  local NC, NR, HL, FL, LL, SL, TB = context.NC, context.NR, context.HL, context.TB, context.FL, context.LL, context.SL  local sortedhash, sortedkeys, concat, sequenced = table.sortedhash, table.sortedkeys, table.concat, table.sequenced @@ -43,28 +45,29 @@ local function analyze(filename)      attr = { }      ents = { } -    table.setmetatableindex(tags,function(t,k) +    local function att(t,k) +        local v = setmetatableindex("number") +        t[k] = v +        return v +    end + +    local function add(t,k)          local v = {              n          = 0, -            attributes = { }, -            children   = { }, +            attributes = setmetatableindex(att), +            children   = setmetatableindex(add),          }          t[k] = v          return v -    end) +    end -    table.setmetatableindex(char,function(t,k) -        t[k] = 0 -        return 0 -    end) +    setmetatableindex(tags,add) -    table.setmetatableindex(attr,function(t,k) -        char[k] = char[k] or 0 -        t[k] = 0 -        return 0 -    end) +    setmetatableindex(ents,"number") +    setmetatableindex(char,"number") -    table.setmetatableindex(ents,function(t,k) +    setmetatableindex(attr,function(t,k) +        char[k] = char[k] or 0          t[k] = 0          return 0      end) @@ -85,24 +88,25 @@ local function analyze(filename)              local tg = e.tg              local tag = tags[tg]              tag.n = tag.n + 1 +            local children = parent and tags[parent].children[tg] +            local childatt = children and children.attributes +            if children then +                children.n = children.n + 1 +            end              if at then                  local attributes = tag.attributes                  for k, v in next, at do                      local a = attributes[k] -                    if a then -                        a[v] = (a[v] or 0) + 1 -                    else -                        attributes[k] = { [v] = 1 } +                    a[v] = a[v] + 1 +                    if childatt then +                        local a = childatt[k] +                        a[v] = a[v] + 1                      end                      for s in utfvalues(v) do                          attr[s] = attr[s] + 1                      end                  end              end -            if parent then -                local children = tags[parent].children -                children[tg] = (children[tg] or 0) + 1 -            end              if dt then                  for i=1,#dt do                      local d = dt[i] @@ -132,10 +136,10 @@ local function analyze(filename)          end      end -    table.setmetatableindex(tags,nil) -    table.setmetatableindex(char,nil) -    table.setmetatableindex(attr,nil) -    table.setmetatableindex(ents,nil) +    setmetatableindex(tags,nil) +    setmetatableindex(char,nil) +    setmetatableindex(attr,nil) +    setmetatableindex(ents,nil)  end @@ -157,7 +161,11 @@ function moduledata.xml.analyzers.structure(filename)          NC() context.bold("element") NC() context.darkred(name) NC() NR()          NC() context.bold("frequency") NC() context(data.n) NC() NR()          if next(children) then -            NC() context.bold("children") NC() context.puretext(sequenced(children)) NC() NR() +            local t = { } +            for k, v in next, children do +                t[k] = v.n +            end +            NC() context.bold("children") NC() context.puretext(sequenced(t)) NC() NR()          end          if next(attributes) then              NC() context.bold("attributes") NC() context.puretext.darkgreen(concat(sortedkeys(attributes)," ")) NC() NR() @@ -198,3 +206,122 @@ function moduledata.xml.analyzers.entities(filename)      end      context.stoptabulate()  end + +local f_parent_s = formatters["xml:%s"] +local f_parent_n = formatters["\\startxmlsetups xml:%s\n  \\xmlflush{#1}\n\\stopxmlsetups"] +local f_parent_a = formatters["\\startxmlsetups xml:%s\n  %% @ % t\n  \\xmlflush{#1}\n\\stopxmlsetups"] +local f_child_s  = formatters["xml:%s:%s"] +local f_child_n  = formatters["\\startxmlsetups xml:%s:%s\n  \\xmlflush{#1}\n\\stopxmlsetups"] +local f_child_a  = formatters["\\startxmlsetups xml:%s:%s\n  %% @ % t\n  \\xmlflush{#1}\n\\stopxmlsetups"] + +local f_template = formatters [ [[ +%% file: %s + +%% Beware, these are all (first level) setups. If you have a complex document +%% it often makes sense to use \\xmlfilter or similar local filter options. + +%% presets + +\startxmlsetup xml:presets:all +  \xmlsetsetups {#1} { +    %s +  } +\stopxmlsetups + +%% setups + +%s +]] ] + +function moduledata.xml.analyzers.allsetups(filename,usedname) +    analyze(filename) +    local result = { } +    local setups = { } +    for name, data in table.sortedhash(tags) do +        local children   = data.children +        local attributes = data.attributes +        if next(attributes) then +            result[#result+1] = f_parent_a(name,sortedkeys(attributes)) +        else +            result[#result+1] = f_parent_n(name) +        end +        setups[#setups+1] = f_parent_s(name) +        if next(children) then +            for k, v in sortedhash(children) do +                local attributes = v.attributes +                if next(attributes) then +                    result[#result+1] = f_child_a(name,k,sortedkeys(attributes)) +                else +                    result[#result+1] = f_child_n(name,k) +                end +                setups[#setups+1] = f_child_s(name,k) +            end +        end +    end +    table.sort(setups) +    -- +    if type(filename) == "table" then +        filename = concat(filename," | ") +    end +    -- +    usedname = usedname or "xml-analyze-template.tex" +    -- +    io.savedata(usedname,f_template(filename,concat(setups,"|\n    "),concat(result,"\n\n"))) +    logs.report("xml analyze","presets saved in: %s",usedname) +end + +-- example: + +-- local t = { } +-- local x = xml.load("music-collection.xml") +-- for c in xml.collected(x,"//*") do +--     if not c.special and not t[c.tg] then +--         t[c.tg] = true +--     end +-- end +-- inspect(table.sortedkeys(t)) + +-- xml.finalizers.taglist = function(collected) +--     local t = { } +--     for i=1,#collected do +--         local c = collected[i] +--         if not c.special then +--             local tg = c.tg +--             if tg and not t[tg] then +--                 t[tg] = true +--             end +--         end +--     end +--     return t +-- end +-- local x = xml.load("music-collection.xml") +-- inspect(table.sortedkeys(xml.applylpath(x,"//*/taglist()"))) + +-- xml.finalizers.taglist = function(collected,parenttoo) +--     local t = { } +--     for i=1,#collected do +--         local c = collected[i] +--         if not c.special then +--             local tg = c.tg +--             if tg and not t[tg] then +--                 t[tg] = true +--             end +--             if parenttoo then +--                 local p = c.__p__ +--                 if p and not p.special then +--                     local tg = p.tg .. ":" .. tg +--                     if tg and not t[tg] then +--                         t[tg] = true +--                     end +--                 end +--             end +--         end +--     end +--     return t +-- end + +-- local x = xml.load("music-collection.xml") +-- inspect(table.sortedkeys(xml.applylpath(x,"//*/taglist()"))) + +-- local x = xml.load("music-collection.xml") +-- inspect(table.sortedkeys(xml.applylpath(x,"//*/taglist(true)"))) diff --git a/tex/context/modules/mkiv/s-xml-analyzers.mkiv b/tex/context/modules/mkiv/s-xml-analyzers.mkiv index af11fc984..4104f023a 100644 --- a/tex/context/modules/mkiv/s-xml-analyzers.mkiv +++ b/tex/context/modules/mkiv/s-xml-analyzers.mkiv @@ -18,6 +18,7 @@  \installmodulecommandluasingle \showxmlstructure  {moduledata.xml.analyzers.structure}  \installmodulecommandluasingle \showxmlcharacters {moduledata.xml.analyzers.characters}  \installmodulecommandluasingle \showxmlentities   {moduledata.xml.analyzers.entities} +\installmodulecommandluasingle \showxmlallsetups  {moduledata.xml.analyzers.allsetups}  \stopmodule @@ -33,6 +34,9 @@  \starttext -    \showxmlcharacters[\FileName] +    \showxmlstructure [\FileName] \page +    \showxmlentities  [\FileName] \page +    \showxmlcharacters[\FileName] \page +    \showxmlallsetups [\FileName] \page  \stoptext diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index 6ef9430b3..bbd2117a8 100644 --- a/tex/generic/context/luatex/luatex-fonts-merged.lua +++ b/tex/generic/context/luatex/luatex-fonts-merged.lua @@ -1,6 +1,6 @@  -- merged file : c:/data/develop/context/sources/luatex-fonts-merged.lua  -- parent file : c:/data/develop/context/sources/luatex-fonts.lua --- merge date  : 08/11/16 13:56:03 +-- merge date  : 08/15/16 22:40:19  do -- begin closure to overcome local limits and interference @@ -8845,112 +8845,6 @@ function readers.math(f,fontdata,specification)      reportskippedtable("math")    end  end -local function packoutlines(data,makesequence) -  local subfonts=data.subfonts -  if subfonts then -    for i=1,#subfonts do -      packoutlines(subfonts[i],makesequence) -    end -    return -  end -  local common=data.segments -  if common then -    return -  end -  local glyphs=data.glyphs -  if not glyphs then -    return -  end -  if makesequence then -    for index=1,#glyphs do -      local glyph=glyphs[index] -      local segments=glyph.segments -      if segments then -        local sequence={} -        local nofsequence=0 -        for i=1,#segments do -          local segment=segments[i] -          local nofsegment=#segment -          nofsequence=nofsequence+1 -          sequence[nofsequence]=segment[nofsegment] -          for i=1,nofsegment-1 do -            nofsequence=nofsequence+1 -            sequence[nofsequence]=segment[i] -          end -        end -        glyph.sequence=sequence -        glyph.segments=nil -      end -    end -  else -    local hash={} -    local common={} -    local reverse={} -    local last=0 -    for index=1,#glyphs do -      local segments=glyphs[index].segments -      if segments then -        for i=1,#segments do -          local h=concat(segments[i]," ") -          hash[h]=(hash[h] or 0)+1 -        end -      end -    end -    for index=1,#glyphs do -      local segments=glyphs[index].segments -      if segments then -        for i=1,#segments do -          local segment=segments[i] -          local h=concat(segment," ") -          if hash[h]>1 then  -            local idx=reverse[h] -            if not idx then -              last=last+1 -              reverse[h]=last -              common[last]=segment -              idx=last -            end -            segments[i]=idx -          end -        end -      end -    end -    if last>0 then -      data.segments=common -    end -  end -end -local function unpackoutlines(data) -  local subfonts=data.subfonts -  if subfonts then -    for i=1,#subfonts do -      unpackoutlines(subfonts[i]) -    end -    return -  end -  local common=data.segments -  if not common then -    return -  end -  local glyphs=data.glyphs -  if not glyphs then -    return -  end -  for index=1,#glyphs do -    local segments=glyphs[index].segments -    if segments then -      for i=1,#segments do -        local c=common[segments[i]] -        if c then -          segments[i]=c -        end -      end -    end -  end -  data.segments=nil -end -otf.packoutlines=packoutlines -otf.unpackoutlines=unpackoutlines  local function getinfo(maindata,sub,platformnames,rawfamilynames)    local fontdata=sub and maindata.subfonts and maindata.subfonts[sub] or maindata    local names=fontdata.names @@ -9218,6 +9112,13 @@ function readers.loadshapes(filename,n)      shapes=true,      subfont=n,    } +  if fontdata then +    for k,v in next,fontdata.glyphs do +      v.class=nil +      v.index=nil +      v.math=nil +    end +  end    return fontdata and {      filename=filename,      format=fontdata.format, @@ -9347,56 +9248,6 @@ function readers.extend(fontdata)      end    end  end -if fonts.hashes then -  local identifiers=fonts.hashes.identifiers -  local loadshapes=readers.loadshapes -  readers.version=0.006 -  readers.cache=containers.define("fonts","shapes",readers.version,true) -  local function load(filename,sub) -    local base=file.basename(filename) -    local name=file.removesuffix(base) -    local kind=file.suffix(filename) -    local attr=lfs.attributes(filename) -    local size=attr and attr.size or 0 -    local time=attr and attr.modification or 0 -    local sub=tonumber(sub) -    if size>0 and (kind=="otf" or kind=="ttf" or kind=="tcc") then -      local hash=containers.cleanname(base)  -      if sub then -        hash=hash.."-"..sub -      end -      data=containers.read(readers.cache,hash) -      if not data or data.time~=time or data.size~=size then -        data=loadshapes(filename,sub) -        if data then -          data.size=size -          data.format=data.format or (kind=="otf" and "opentype") or "truetype" -          data.time=time -          packoutlines(data) -          containers.write(readers.cache,hash,data) -          data=containers.read(readers.cache,hash)  -        end -      end -      unpackoutlines(data) -    else -      data={ -        filename=filename, -        size=0, -        time=time, -        format="unknown", -        units=1000, -        glyphs={} -      } -    end -    return data -  end -  fonts.hashes.shapes=table.setmetatableindex(function(t,k) -    local d=identifiers[k] -    local v=load(d.properties.filename,d.subindex) -    t[k]=v -    return v -  end) -end  end -- closure @@ -9415,6 +9266,7 @@ 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 formatters=string.formatters  local readers=fonts.handlers.otf.readers  local streamreader=readers.streamreader  local readbytes=streamreader.readbytes @@ -9815,6 +9667,7 @@ do    local ymax=0    local checked=false    local keepcurve=false +  local version=2    local function showstate(where)      report("%w%-10s : [%s] n=%i",depth*2,where,concat(stack," ",1,top),top)    end @@ -10237,9 +10090,91 @@ do        return floor((stems+7)/8)      end    end -  local function unsupported() +  local function unsupported(t)      if trace_charstrings then -      showstate("unsupported") +      showstate("unsupported "..t) +    end +    top=0 +  end +  local function unsupportedsub(t) +    if trace_charstrings then +      showstate("unsupported sub "..t) +    end +    top=0 +  end +  local function getstem3() +    if trace_charstrings then +      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 +  local function callothersubr() +    if version==1 then +      if trace_charstrings then +        showstate("callothersubr (unsupported)") +      end +    end +    top=0 +  end +  local function pop() +    if version==1 then +      if trace_charstrings then +        showstate("pop (unsupported)") +      end +      top=top+1 +      stack[top]=0  +    else +      top=0 +    end +  end +  local function setcurrentpoint() +    if version==1 then +      if trace_charstrings then +        showstate("pop (unsupported)") +      end +      x=x+stack[top-1] +      y=y+stack[top]      end      top=0    end @@ -10256,7 +10191,7 @@ do      unsupported,      unsupported,      unsupported, -    unsupported, +    hsbw,      unsupported,      unsupported,      unsupported, @@ -10277,6 +10212,15 @@ do      hvcurveto,    }    local subactions={ +    [000]=dotsection, +    [001]=getstem3, +    [002]=getstem3, +    [006]=seac, +    [007]=sbw, +    [012]=divide, +    [016]=callothersubr, +    [017]=pop, +    [033]=setcurrentpoint,      [034]=hflex,      [035]=flex,      [036]=hflex1, @@ -10284,23 +10228,29 @@ do    }    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 +    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 +        if type(tab)=="string" then +          tab=lpegmatch(p_bytes,tab) +          list[index]=tab +        end +        process(tab) +      else +        showstate(formatters["unknown %s call %i"](scope,index)) +        top=0 +      end      end +    depth=depth-1    end    local function process(tab)      local i=1 @@ -10367,7 +10317,7 @@ do          local t=tab[i]          local a=subactions[t]          if a then -          a() +          a(t)          else            if trace_charstrings then              showvalue("<subaction>",t) @@ -10378,7 +10328,7 @@ do        else          local a=actions[t]          if a then -          local s=a() +          local s=a(t)            if s then              i=i+s            end @@ -10392,25 +10342,38 @@ do        end      end    end -  parsecharstrings=function(data,glyphs,doshapes) +  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 +  end +  parsecharstrings=function(data,glyphs,doshapes,tversion)      local dictionary=data.dictionaries[1]      local charstrings=dictionary.charstrings      local charset=dictionary.charset +    local private=dictionary.private or { data={} }      keepcurve=doshapes +    version=tversion      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 +    globals=data.routines or {} +    locals=dictionary.subroutines or {} +    globalbias,localbias=setbias(globals,locals,version) +    local nominalwidth=private.data.nominalwidthx or 0 +    local defaultwidth=private.data.defaultwidthx or 0      for i=1,#charstrings do -      local str=charstrings[i] -      local tab=lpegmatch(p_bytes,str) +      local tab=charstrings[i] +      if type(tab)=="string" then +        tab=lpegmatch(p_bytes,tab) +      end        local index=i-1        x=0        y=0 @@ -10461,19 +10424,18 @@ do      end      return glyphs    end -  parsecharstring=function(data,dictionary,charstring,glyphs,index,doshapes) +  parsecharstring=function(data,dictionary,tab,glyphs,index,doshapes,version)      local private=dictionary.private      keepcurve=doshapes      strings=data.strings       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 +    globalbias=setbias(globals,locals)      local nominalwidth=private and private.data.nominalwidthx or 0      local defaultwidth=private and private.data.defaultwidthx or 0 -    local tab=lpegmatch(p_bytes,charstring) +    if type(tab)=="string" then +      tab=lpegmatch(p_bytes,tab) +    end      x=0      y=0      width=false @@ -10497,7 +10459,7 @@ do      else        width=nominalwidth+width      end -index=index-1 +    index=index-1      local glyph=glyphs[index]       if not glyph then        glyphs[index]={ @@ -10520,7 +10482,6 @@ index=index-1        report("width: %s",tostring(width))        report("boundingbox: % t",boundingbox)      end -    return charstring    end    resetcharstrings=function()      result={} @@ -10634,7 +10595,7 @@ local function readcidprivates(f,data)    end    parseprivates(data,dictionaries)  end -local function readnoselect(f,data,glyphs,doshapes) +local function readnoselect(f,data,glyphs,doshapes,version)    local dictionaries=data.dictionaries    local dictionary=dictionaries[1]    readglobals(f,data) @@ -10644,10 +10605,11 @@ local function readnoselect(f,data,glyphs,doshapes)    readprivates(f,data)    parseprivates(data,data.dictionaries)    readlocals(f,data,dictionary) -  parsecharstrings(data,glyphs,doshapes) +  parsecharstrings(data,glyphs,doshapes,version)    resetcharstrings()  end -local function readfdselect(f,data,glyphs,doshapes) +readers.parsecharstrings=parsecharstrings +local function readfdselect(f,data,glyphs,doshapes,version)    local header=data.header    local dictionaries=data.dictionaries    local dictionary=dictionaries[1] @@ -10705,7 +10667,7 @@ local function readfdselect(f,data,glyphs,doshapes)        readlocals(f,data,dictionaries[i])      end      for i=1,#charstrings do -      parsecharstring(data,dictionaries[fdindex[i]+1],charstrings[i],glyphs,i,doshapes) +      parsecharstring(data,dictionaries[fdindex[i]+1],charstrings[i],glyphs,i,doshapes,version)      end      resetcharstrings()    end @@ -21057,7 +21019,7 @@ local setspacekerns=nodes.injections.setspacekerns if not setspacekerns then os.  if fontfeatures then    function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr)      local features=fontfeatures[font] -    local enabled=features.spacekern==true and features.kern==true +    local enabled=features and features.spacekern and features.kern      if enabled then        setspacekerns(font,sequence)      end @@ -21067,7 +21029,7 @@ else    function otf.handlers.trigger_space_kerns(head,start,dataset,sequence,_,_,_,_,font,attr)      local shared=fontdata[font].shared      local features=shared and shared.features -    local enabled=features and features.spacekern==true and features.kern==true +    local enabled=features and features.spacekern and features.kern      if enabled then        setspacekerns(font,sequence)      end @@ -21122,7 +21084,7 @@ local function spaceinitializer(tfmdata,value)            if kern then              if feat then                for script,languages in next,kern do -                local f=feat[k] +                local f=feat[script]                  if f then                    for l in next,languages do                      f[l]=true @@ -21142,7 +21104,7 @@ local function spaceinitializer(tfmdata,value)                  if kerns then                    for k,v in next,kerns do                      if type(v)=="table" then -                      right[k]=v[3]  +                      right[k]=v[1][3]                      else                        right[k]=v                      end @@ -21152,7 +21114,7 @@ local function spaceinitializer(tfmdata,value)                    local kern=v[32]                    if kern then                      if type(kern)=="table" then -                      left[k]=kern[3]  +                      left[k]=kern[1][3]                      else                        left[k]=kern                      end @@ -24226,26 +24188,25 @@ handlers.afm=afm  local readers=afm.readers or {}  afm.readers=readers  afm.version=1.512 -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 +  local decrypt +  do +    local r,c1,c2,n=0,0,0,0 +    local function step(c) +      local cipher=byte(c) +      local plain=bxor(cipher,rshift(r,8)) +      r=((cipher+r)*c1+c2)%65536 +      return char(plain) +    end +    decrypt=function(binary,initial,seed) +      r,c1,c2,n=initial,52845,22719,seed +      binary=gsub(binary,".",step) +      return sub(binary,n+1)      end -  end -  local initialize=function(str,position,size) -    n=0 -    m=size  -    return position+1    end    local charstrings=P("/CharStrings") +  local subroutines=P("/Subrs")    local encoding=P("/Encoding")    local dup=P("dup")    local put=P("put") @@ -24255,28 +24216,58 @@ do    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  +    return position+1 +  end +  local setroutine=function(str,position,index,size) +    local forward=position+tonumber(size) +    local stream=sub(str,position+1,forward) +    routines[index]=decrypt(stream,4330,4) +    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  +      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= +    (1-subroutines)^0*subroutines*spaces*Cmt(cardinal,initialize)*(Cmt(cardinal*spaces*cardinal*p_rd,setroutine)*p_np+P(1))^1 +  local p_filtershapes= +    (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,progress)+P(1))^1 +    (1-charstrings)^0*charstrings*spaces*Cmt(cardinal,initialize)*(Cmt(name*spaces*cardinal,setvector)+P(1))^1    )    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) -  local decrypt -  do -    local r,c1,c2,n=0,0,0,0 -    local function step(c) -      local cipher=byte(c) -      local plain=bxor(cipher,rshift(r,8)) -      r=((cipher+r)*c1+c2)%65536 -      return char(plain) -    end -    decrypt=function(binary) -      r,c1,c2,n=55665,52845,22719,4 -      binary=gsub(binary,".",step) -      return sub(binary,n+1) -    end -  end -  local function loadpfbvector(filename) +  local function loadpfbvector(filename,shapestoo)      local data=io.loaddata(resolvers.findfile(filename))      if not data then        report_pfb("no data in %a",filename) @@ -24291,18 +24282,30 @@ do        report_pfb("no binary data in %a",filename)        return      end -    binary=decrypt(binary,4) -    local vector=lpegmatch(p_filternames,binary) -    for i=1,#vector do -      vector[i-1]=vector[i] -    end -    vector[#vector]=nil -    if not vector then -      report_pfb("no vector in %a",filename) -      return -    end +    binary=decrypt(binary,55665,4) +    local names={}      local encoding=lpegmatch(p_filterencoding,ascii) -    return vector,encoding +    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(data,glyphs,true,true) +    else +      lpegmatch(p_filternames,binary) +    end +    names=vector +    routines,vector,chars=nil,nil,nil +    return names,encoding,glyphs    end    local pfb=handlers.pfb or {}    handlers.pfb=pfb @@ -24326,6 +24329,10 @@ do        end      end    end +  get_shapes=function(pfbname) +    local vector,encoding,glyphs=loadpfbvector(pfbname,true) +    return glyphs +  end  end  local spacer=patterns.spacer  local whitespace=patterns.whitespace @@ -24474,6 +24481,22 @@ function readers.loadfont(afmname,pfbname)      return data    end  end +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  | 
