diff options
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 |