diff options
Diffstat (limited to 'tex')
209 files changed, 13841 insertions, 1888 deletions
diff --git a/tex/context/base/mkii/cont-new.mkii b/tex/context/base/mkii/cont-new.mkii index afb671bbd..0dda26e80 100644 --- a/tex/context/base/mkii/cont-new.mkii +++ b/tex/context/base/mkii/cont-new.mkii @@ -11,7 +11,7 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\newcontextversion{2019.02.14 16:57} +\newcontextversion{2019.04.04 13:31} %D This file is loaded at runtime, thereby providing an %D excellent place for hacks, patches, extensions and new diff --git a/tex/context/base/mkii/context.mkii b/tex/context/base/mkii/context.mkii index f50ab529e..91d282601 100644 --- a/tex/context/base/mkii/context.mkii +++ b/tex/context/base/mkii/context.mkii @@ -20,7 +20,7 @@ %D your styles an modules. \edef\contextformat {\jobname} -\edef\contextversion{2019.02.14 16:57} +\edef\contextversion{2019.04.04 13:31} %D For those who want to use this: diff --git a/tex/context/base/mkii/mult-de.mkii b/tex/context/base/mkii/mult-de.mkii index 0a15a4f30..46a239304 100644 --- a/tex/context/base/mkii/mult-de.mkii +++ b/tex/context/base/mkii/mult-de.mkii @@ -587,6 +587,7 @@ \setinterfacevariable{understrike}{understrike} \setinterfacevariable{understrikes}{understrikes} \setinterfacevariable{unframed}{unframed} +\setinterfacevariable{unicode}{unicode} \setinterfacevariable{unit}{einheit} \setinterfacevariable{units}{einheiten} \setinterfacevariable{unknown}{unbekannt} diff --git a/tex/context/base/mkii/mult-en.mkii b/tex/context/base/mkii/mult-en.mkii index faf268576..0f9cc15e1 100644 --- a/tex/context/base/mkii/mult-en.mkii +++ b/tex/context/base/mkii/mult-en.mkii @@ -587,6 +587,7 @@ \setinterfacevariable{understrike}{understrike} \setinterfacevariable{understrikes}{understrikes} \setinterfacevariable{unframed}{unframed} +\setinterfacevariable{unicode}{unicode} \setinterfacevariable{unit}{unit} \setinterfacevariable{units}{units} \setinterfacevariable{unknown}{unknown} diff --git a/tex/context/base/mkii/mult-nl.mkii b/tex/context/base/mkii/mult-nl.mkii index 884503363..6376b158a 100644 --- a/tex/context/base/mkii/mult-nl.mkii +++ b/tex/context/base/mkii/mult-nl.mkii @@ -587,6 +587,7 @@ \setinterfacevariable{understrike}{understrike} \setinterfacevariable{understrikes}{understrikes} \setinterfacevariable{unframed}{unframed} +\setinterfacevariable{unicode}{unicode} \setinterfacevariable{unit}{eenheid} \setinterfacevariable{units}{eenheden} \setinterfacevariable{unknown}{onbekend} diff --git a/tex/context/base/mkiv/anch-pgr.lua b/tex/context/base/mkiv/anch-pgr.lua index 32b7c2960..14afa3967 100644 --- a/tex/context/base/mkiv/anch-pgr.lua +++ b/tex/context/base/mkiv/anch-pgr.lua @@ -94,7 +94,14 @@ local enabled = false -- Freeing the data is somewhat tricky as we can have backgrounds spanning -- many pages but for an arbitrary background shape that is not so common. -local function check(a,index,depth,d,where,ht,dp) +local function check(specification) + local a = specification.attribute + local index = specification.index + local depth = specification.depth + local d = specification.data + local where = specification.where + local ht = specification.ht + local dp = specification.dp -- this is not yet r2l ready local w = d.shapes[realpage] local x, y = getpos() @@ -107,7 +114,7 @@ local function check(a,index,depth,d,where,ht,dp) n = n + 1 d.index = index d.depth = depth --- w[n] = { x, x, y, ht, dp } + -- w[n] = { x, x, y, ht, dp } w[n] = { y, ht, dp, x, x } else local wn = w[n] @@ -148,8 +155,8 @@ local function flush(head,f,l,a,parent,depth) local ix = index local ht = getheight(parent) local dp = getdepth(parent) - local ln = new_latelua(function() check(a,ix,depth,d,"l",ht,dp) end) - local rn = new_latelua(function() check(a,ix,depth,d,"r",ht,dp) end) + local ln = new_latelua { action = check, attribute = a, index = ix, depth = depth, data = d, where = "l", ht = ht, dp = dp } + local rn = new_latelua { action = check, attribute = a, index = ix, depth = depth, data = d, where = "r", ht = ht, dp = dp } if trace_ranges then ln = new_hlist(setlink(new_rule(65536,65536*4,0),new_kern(-65536),ln)) rn = new_hlist(setlink(new_rule(65536,0,65536*4),new_kern(-65536),rn)) @@ -507,7 +514,8 @@ local function shape(kind,b,p,realpage,xmin,xmax,ymin,ymax,fh,ld) -- use height of b and depth of e, maybe check for weird border -- cases here if fh then - local lsf, rsf = ls[1], rs[1] + local lsf = ls[1] + local rsf = rs[1] if lsf[2] < fh then lsf[2] = fh end @@ -516,7 +524,8 @@ local function shape(kind,b,p,realpage,xmin,xmax,ymin,ymax,fh,ld) end end if fd then - local lsl, rsl = ls[n], rs[n] + local lsl = ls[n] + local rsl = rs[n] if lsl[2] > fd then lsl[2] = fd end @@ -533,12 +542,18 @@ local function shape(kind,b,p,realpage,xmin,xmax,ymin,ymax,fh,ld) end local function singlepart(b,e,p,realpage,r,left,right) - local bx, by = b.x, b.y - local ex, ey = e.x, e.y - local rx, ry = r.x, r.y - local bh, bd = by + b.h, by - b.d - local eh, ed = ey + e.h, ey - e.d - local rh, rd = ry + r.h, ry - r.d + local bx = b.x + local by = b.y + local ex = e.x + local ey = e.y + local rx = r.x + local ry = r.y + local bh = by + b.h + local bd = by - b.d + local eh = ey + e.h + local ed = ey - e.d + local rh = ry + r.h + local rd = ry - r.d local rw = rx + r.w if left then rx = rx + left @@ -591,10 +606,14 @@ local function singlepart(b,e,p,realpage,r,left,right) end local function firstpart(b,e,p,realpage,r,left,right) - local bx, by = b.x, b.y - local rx, ry = r.x, r.y - local bh, bd = by + b.h, by - b.d - local rh, rd = ry + r.h, ry - r.d + local bx = b.x + local by = b.y + local rx = r.x + local ry = r.y + local bh = by + b.h + local bd = by - b.d + local rh = ry + r.h + local rd = ry - r.d local rw = rx + r.w if left then rx = rx + left @@ -628,8 +647,10 @@ local function firstpart(b,e,p,realpage,r,left,right) end local function middlepart(b,e,p,realpage,r,left,right) - local rx, ry = r.x, r.y - local rh, rd = ry + r.h, ry - r.d + local rx = r.x + local ry = r.y + local rh = ry + r.h + local rd = ry - r.d local rw = rx + r.w if left then rx = rx + left @@ -652,10 +673,14 @@ local function middlepart(b,e,p,realpage,r,left,right) end local function lastpart(b,e,p,realpage,r,left,right) - local ex, ey = e.x, e.y - local rx, ry = r.x, r.y - local eh, ed = ey + e.h, ey - e.d - local rh, rd = ry + r.h, ry - r.d + local ex = e.x + local ey = e.y + local rx = r.x + local ry = r.y + local eh = ey + e.h + local ed = ey - e.d + local rh = ry + r.h + local rd = ry - r.d local rw = rx + r.w if left then rx = rx + left @@ -842,8 +867,10 @@ local function freemultipar(pagedata,frees) -- ,k local areas = { } data.areas = areas - local f_1, n_1 = { }, 0 - local f_2, n_2 = { }, 0 + local f_1 = { } + local n_1 = 0 + local f_2 = { } + local n_2 = 0 for i=1,#frees do local f = frees[i] local k = f.k @@ -906,14 +933,18 @@ local function freemultipar(pagedata,frees) -- ,k -- we can collect the coordinates first local function check_two(area,frees) - local ul = area[1] - local ur = area[2] - local lr = area[3] - local ll = area[4] - local ulx, uly = ul[1], ul[2] - local urx, ury = ur[1], ur[2] - local lrx, lry = lr[1], lr[2] - local llx, lly = ll[1], ll[2] + local ul = area[1] + local ur = area[2] + local lr = area[3] + local ll = area[4] + local ulx = ul[1] + local uly = ul[2] + local urx = ur[1] + local ury = ur[2] + local lrx = lr[1] + local lry = lr[2] + local llx = ll[1] + local lly = ll[2] local temp = { } local n = 0 @@ -1106,12 +1137,16 @@ local function fetchmultipar(n,anchor,page) report_graphics("fetching %a at page %s using anchor %a containing %s multipars", n,page,anchor,nofmultipars) end - local x, y = a.x, a.y - local w, h, d = a.w, a.h, a.d - local bpos = data.bpos - local bh, bd = bpos.h, bpos.d - local result = { false } -- slot 1 will be set later - local n = 0 + local x = a.x + local y = a.y + local w = a.w + local h = a.h + local d = a.d + local bpos = data.bpos + local bh = bpos.h + local bd = bpos.d + local result = { false } -- slot 1 will be set later + local n = 0 for i=1,nofmultipars do local data = pagedata[i] local location = data.location @@ -1176,7 +1211,8 @@ implement { if type(tags) == "string" then tags = utilities.parsers.settings_to_array(tags) end - local list, nofboxes = { }, 0 + local list = { } + local nofboxes = 0 for i=1,#tags do local tag= tags[i] local c = collected[tag] @@ -1185,7 +1221,11 @@ implement { if r then r = collected[r] if r then - local rx, ry, rw, rh, rd = r.x, r.y, r.w, r.h, r.d + local rx = r.x + local ry = r.y + local rw = r.w + local rh = r.h + local rd = r.d local cx = c.x - rx local cy = c.y local cw = cx + c.w diff --git a/tex/context/base/mkiv/anch-pos.lua b/tex/context/base/mkiv/anch-pos.lua index 9438fa2a7..56250e16d 100644 --- a/tex/context/base/mkiv/anch-pos.lua +++ b/tex/context/base/mkiv/anch-pos.lua @@ -44,7 +44,6 @@ local scanners = interfaces.scanners local commands = commands local context = context -local ctxnode = context.nodes.flush local ctx_latelua = context.latelua @@ -75,7 +74,6 @@ local find_tail = nuts.tail local hpack = nuts.hpack local new_latelua = nuts.pool.latelua -local new_latelua_node = nodes.pool.latelua local variables = interfaces.variables local v_text = variables.text @@ -243,7 +241,6 @@ end -- t[#t+1] = data -- end -- --- -- -- local pages = structures.pages.collected -- if pages then -- local last = nil @@ -403,9 +400,29 @@ end -- analyze some files (with lots if margindata) and then when one key optionally -- use that one instead of a table (so, a 3rd / 4th argument: key, e.g. "x") -local function set(name,index,val) -- ,key - local data = enhance(val or index) - if val then +local function set(name,index,value) -- ,key + -- officially there should have been a settobesaved + local data = enhance(value or {}) + if value then + container = tobesaved[name] + if not container then + tobesaved[name] = { + [index] = data + } + else + container[index] = data + end + else + tobesaved[name] = data + end +end + +local function setspec(specification) + local name = specification.name + local index = specification.index + local value = specification.value + local data = enhance(value or {}) + if value then container = tobesaved[name] if not container then tobesaved[name] = { @@ -428,16 +445,11 @@ local function get(id,index) end end -------------.setdim = setdim -jobpositions.setall = setall -jobpositions.set = set -jobpositions.get = get - --- scanners.setpos = setall - --- trackers.enable("tokens.compi*") - --- something weird: the compiler fails us here +------------.setdim = setdim +jobpositions.setall = setall +jobpositions.set = set +jobpositions.setspec = setspec +jobpositions.get = get scanners.dosaveposition = compilescanner { actions = setall, -- name p x y @@ -459,7 +471,8 @@ scanners.dosavepositionplus = compilescanner { -- not much gain in keeping stack (inc/dec instead of insert/remove) -local function b_column(tag) +local function b_column(specification) + local tag = specification.tag local x = gethpos() tobesaved[tag] = { r = true, @@ -470,7 +483,7 @@ local function b_column(tag) column = tag end -local function e_column(tag) +local function e_column() local t = tobesaved[column] if not t then -- something's wrong @@ -496,8 +509,7 @@ scanners.bposcolumnregistered = function() -- tag local tag = scanstring() insert(columns,tag) column = tag --- ctxnode(new_latelua_node(function() b_column(tag) end)) - ctx_latelua(function() b_column(tag) end) + ctx_latelua { action = b_column, tag = tag } end scanners.eposcolumn = function() @@ -506,15 +518,15 @@ scanners.eposcolumn = function() end scanners.eposcolumnregistered = function() --- ctxnode(new_latelua_node(e_column)) - ctx_latelua(e_column) + ctx_latelua { action = e_column } remove(columns) column = columns[#columns] end -- regions -local function b_region(tag) +local function b_region(specification) + local tag = specification.tag or specification local last = tobesaved[tag] local x, y = getpos() last.x = x ~= 0 and x or nil @@ -524,11 +536,11 @@ local function b_region(tag) region = tag end -local function e_region(correct) +local function e_region(specification) local last = tobesaved[region] local y = getvpos() local x, y = getpos() - if correct then + if specification.correct then local h = (last.y or 0) - y last.h = h ~= 0 and h or nil end @@ -569,8 +581,8 @@ end local function markregionbox(n,tag,correct,...) -- correct needs checking local tag, box = setregionbox(n,tag,...) -- todo: check if tostring is needed with formatter - local push = new_latelua(function() b_region(tag) end) - local pop = new_latelua(function() e_region(correct) end) + local push = new_latelua { action = b_region, tag = tag } + local pop = new_latelua { action = e_region, correct = correct } -- maybe we should construct a hbox first (needs experimenting) so that we can avoid some at the tex end local head = getlist(box) -- no, this fails with \framed[region=...] .. needs thinking @@ -604,6 +616,13 @@ function jobpositions.gettobesaved(name,tag) end end +function jobpositions.settobesaved(name,tag,data) + local t = tobesaved[name] + if t and tag and data then + t[tag] = data + end +end + local nofparagraphs = 0 scanners.parpos = function() @@ -645,15 +664,14 @@ scanners.parpos = function() if parshape and #parshape > 0 then t.ps = parshape end - local tag = f_p_tag(nofparagraphs) - tobesaved[tag] = t --- ctxnode(new_latelua_node(function() enhance(tobesaved[tag]) end)) - ctx_latelua(function() enhance(tobesaved[tag]) end) + local name = f_p_tag(nofparagraphs) + tobesaved[name] = t + ctx_latelua { action = enhance, specification = t } end scanners.dosetposition = function() -- name local name = scanstring() - tobesaved[name] = { + local spec = { p = true, c = column, r = true, @@ -662,16 +680,16 @@ scanners.dosetposition = function() -- name n = nofparagraphs > 0 and nofparagraphs or nil, r2l = texgetcount("inlinelefttoright") == 1 or nil, } --- ctxnode(new_latelua_node(function() enhance(tobesaved[name]) end)) - ctx_latelua(function() enhance(tobesaved[name]) end) + tobesaved[name] = spec + ctx_latelua { action = enhance, specification = spec } end scanners.dosetpositionwhd = function() -- name w h d extra local name = scanstring() - local w = scandimen() - local h = scandimen() - local d = scandimen() - tobesaved[name] = { + local w = scandimen() + local h = scandimen() + local d = scandimen() + local spec = { p = true, c = column, r = true, @@ -683,15 +701,15 @@ scanners.dosetpositionwhd = function() -- name w h d extra n = nofparagraphs > 0 and nofparagraphs or nil, r2l = texgetcount("inlinelefttoright") == 1 or nil, } --- ctxnode(new_latelua_node(function() enhance(tobesaved[name]) end)) - ctx_latelua(function() enhance(tobesaved[name]) end) + tobesaved[name] = spec + ctx_latelua { action = enhance, specification = spec } end scanners.dosetpositionbox = function() -- name box local name = scanstring() local box = getbox(scaninteger()) local w, h, d = getwhd(box) - tobesaved[name] = { + local spec = { p = true, c = column, r = true, @@ -703,16 +721,16 @@ scanners.dosetpositionbox = function() -- name box n = nofparagraphs > 0 and nofparagraphs or nil, r2l = texgetcount("inlinelefttoright") == 1 or nil, } --- ctxnode(new_latelua_node(function() enhance(tobesaved[name]) end)) - ctx_latelua(function() enhance(tobesaved[name]) end) + tobesaved[name] = spec + ctx_latelua { action = enhance, specification = spec } end scanners.dosetpositionplus = function() -- name w h d extra local name = scanstring() - local w = scandimen() - local h = scandimen() - local d = scandimen() - tobesaved[name] = { + local w = scandimen() + local h = scandimen() + local d = scandimen() + local spec = { p = true, c = column, r = true, @@ -725,15 +743,15 @@ scanners.dosetpositionplus = function() -- name w h d extra e = scanstring(), r2l = texgetcount("inlinelefttoright") == 1 or nil, } --- ctxnode(new_latelua_node(function() enhance(tobesaved[name]) end)) - ctx_latelua(function() enhance(tobesaved[name]) end) + tobesaved[name] = spec + ctx_latelua { action = enhance, specification = spec } end scanners.dosetpositionstrut = function() -- name local name = scanstring() local box = getbox("strutbox") local w, h, d = getwhd(box) - tobesaved[name] = { + local spec = { p = true, c = column, r = true, @@ -744,8 +762,8 @@ scanners.dosetpositionstrut = function() -- name n = nofparagraphs > 0 and nofparagraphs or nil, r2l = texgetcount("inlinelefttoright") == 1 or nil, } --- ctxnode(new_latelua_node(function() enhance(tobesaved[name]) end)) - ctx_latelua(function() enhance(tobesaved[name]) end) + tobesaved[name] = spec + ctx_latelua { action = enhance, specification = spec } end scanners.dosetpositionstrutkind = function() -- name @@ -753,7 +771,7 @@ scanners.dosetpositionstrutkind = function() -- name local kind = scaninteger() local box = getbox("strutbox") local w, h, d = getwhd(box) - tobesaved[name] = { + local spec = { k = kind, p = true, c = column, @@ -765,8 +783,8 @@ scanners.dosetpositionstrutkind = function() -- name n = nofparagraphs > 0 and nofparagraphs or nil, r2l = texgetcount("inlinelefttoright") == 1 or nil, } --- ctxnode(new_latelua_node(function() enhance(tobesaved[name]) end)) - ctx_latelua(function() enhance(tobesaved[name]) end) + tobesaved[name] = spec + ctx_latelua { action = enhance, specification = spec } end function jobpositions.getreserved(tag,n) diff --git a/tex/context/base/mkiv/attr-col.lua b/tex/context/base/mkiv/attr-col.lua index 2d4b65181..5ea72c7e3 100644 --- a/tex/context/base/mkiv/attr-col.lua +++ b/tex/context/base/mkiv/attr-col.lua @@ -368,10 +368,14 @@ local function reviver(data,n) local gray = graycolor(v[2]) d = { gray, gray, gray, gray } elseif model == 3 then - local gray, rgb, cmyk = graycolor(v[2]), rgbcolor(v[3],v[4],v[5]), cmykcolor(v[6],v[7],v[8],v[9]) + local gray = graycolor(v[2]) + local rgb = rgbcolor(v[3],v[4],v[5]) + local cmyk = cmykcolor(v[6],v[7],v[8],v[9]) d = { rgb, gray, rgb, cmyk } elseif model == 4 then - local gray, rgb, cmyk = graycolor(v[2]), rgbcolor(v[3],v[4],v[5]), cmykcolor(v[6],v[7],v[8],v[9]) + local gray = graycolor(v[2]) + local rgb = rgbcolor(v[3],v[4],v[5]) + local cmyk = cmykcolor(v[6],v[7],v[8],v[9]) d = { cmyk, gray, rgb, cmyk } elseif model == 5 then local spot = spotcolor(v[10],v[11],v[12],v[13]) diff --git a/tex/context/base/mkiv/attr-ini.lua b/tex/context/base/mkiv/attr-ini.lua index 63015d205..dd971afc1 100644 --- a/tex/context/base/mkiv/attr-ini.lua +++ b/tex/context/base/mkiv/attr-ini.lua @@ -114,7 +114,8 @@ local function showlist(what,list) local a = list.next local i = 0 while a do - local number, value = a.number, a.value + local number = a.number + local value = a.value i = i + 1 report_attribute("%S %2i: attribute %3i, value %4i, name %a",what,i,number,value,names[number]) a = a.next diff --git a/tex/context/base/mkiv/back-ini.lua b/tex/context/base/mkiv/back-ini.lua index 94cdcd29f..b7af1529b 100644 --- a/tex/context/base/mkiv/back-ini.lua +++ b/tex/context/base/mkiv/back-ini.lua @@ -76,7 +76,7 @@ local lmtx_mode = nil local function lmtxmode() if lmtx_mode == nil then - lmtx_mode = environment.lmtxmode and drivers and drivers.lmtxversion + lmtx_mode = ((tonumber(CONTEXTLMTXMODE) or 0) > 0) and drivers and drivers.lmtxversion end return lmtx_mode end @@ -208,11 +208,11 @@ local savenode = nodepool.save local restorenode = nodepool.restore local setmatrixnode = nodepool.setmatrix --- updaters.register("backend.update",function() --- savenode = nodepool.save --- restorenode = nodepool.restore --- setmatrixnode = nodepool.setmatrix --- end) +updaters.register("backend.update",function() + savenode = nodepool.save + restorenode = nodepool.restore + setmatrixnode = nodepool.setmatrix +end) local function stopsomething() local top = remove(stack) diff --git a/tex/context/base/mkiv/back-lpd.lua b/tex/context/base/mkiv/back-lpd.lua new file mode 100644 index 000000000..44ffbc43a --- /dev/null +++ b/tex/context/base/mkiv/back-lpd.lua @@ -0,0 +1,2468 @@ +if not modules then modules = { } end modules ['back-lpd'] = { + version = 1.001, + comment = "companion to lpdf-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- If you consider this complex, watch: +-- +-- https://www.youtube.com/watch?v=6H-cAzfB2qo +-- +-- or in distactionmode: +-- +-- https://www.youtube.com/watch?v=TYuTE_1jvvE +-- https://www.youtube.com/watch?v=nnicGKX3lvM +-- +-- For the moment we have to support the built in backend as well as the alternative. So the +-- next interface is suboptimal and will change at some time. + +local type, next, unpack, tonumber = type, next, unpack, tonumber +local char, rep, find = string.char, string.rep, string.find +local formatters, splitstring = string.formatters, string.split +local band, extract = bit32.band, bit32.extract +local concat, keys, sortedhash = table.concat, table.keys, table.sortedhash +local setmetatableindex = table.setmetatableindex + +local bpfactor = number.dimenfactors.bp + +local md5HEX = md5.HEX +local osuuid = os.uuid +local zlibcompress = flate.zip_compress or zlib.compress + +local starttiming = statistics.starttiming +local stoptiming = statistics.stoptiming + +local nuts = nodes.nuts +local tonut = nodes.tonut + +local getdata = nuts.getdata +local getsubtype = nuts.getsubtype +local getfield = nuts.getfield +local getwhd = nuts.getwhd +local flushlist = nuts.flush_list + +local pdfincludeimage = lpdf.includeimage +local pdfgetfontname = lpdf.getfontname +local pdfgetfontobjnumber = lpdf.getfontobjnumber + +local pdfreserveobject = lpdf.reserveobject +local pdfpagereference = lpdf.pagereference +local pdfflushobject = lpdf.flushobject +local pdfreference = lpdf.reference +local pdfdictionary = lpdf.dictionary +local pdfarray = lpdf.array +local pdfconstant = lpdf.constant +local pdfflushstreamobject = lpdf.flushstreamobject +local pdfliteral = lpdf.literal -- not to be confused with a whatsit! + +local pdf_pages = pdfconstant("Pages") +local pdf_page = pdfconstant("Page") +local pdf_xobject = pdfconstant("XObject") +local pdf_form = pdfconstant("Form") + +local fonthashes = fonts.hashes +local characters = fonthashes.characters +local parameters = fonthashes.parameters +local properties = fonthashes.properties + +local report = logs.reporter("backend") + +do + + local dummy = function() end + + local function unavailable(t,k) + report("calling unavailable pdf.%s function",k) + t[k] = dummy + return dummy + end + + updaters.register("backend.update.pdf",function() + setmetatableindex(pdf,unavailable) + end) + + updaters.register("backend.update",function() + pdf = setmetatableindex(unavailable) + end) + +end + +-- used variables + +local pdf_h, pdf_v +local need_tm, need_tf, cur_tmrx, cur_factor, cur_f, cur_e +local need_width, need_mode, done_width, done_mode +local mode +local f_pdf_cur, f_pdf, fs_cur, fs, f_cur +local tj_delta, cw +local usedfonts, usedxforms, usedximages +local getxformname, getximagename +local boundingbox, shippingmode, objectnumber +local tmrx, tmry, tmsx, tmsy, tmtx, tmty +local cmrx, cmry, cmsx, cmsy, cmtx, cmty + +local function usefont(t,k) -- a bit redundant hash + local v = pdfgetfontname(k) + t[k] = v + return v +end + +local function reset_variables(specification) + pdf_h, pdf_v = 0, 0 + cmrx, cmry = 1, 1 + cmsx, cmsy = 0, 0 + cmtx, cmty = 0, 0 + tmrx, tmry = 1, 1 + tmsx, tmsy = 0, 0 + tmtx, tmty = 0, 0 + need_tm = false + need_tf = false + need_width = 0 + need_mode = 0 + done_width = false + done_mode = false + mode = "page" + shippingmode = specification.shippingmode + objectnumber = specification.objectnumber + cur_tmrx = 0 + f_cur = 0 + f_pdf_cur = 0 -- nullfont + f_pdf = 0 -- nullfont + fs_cur = 0 + fs = 0 + tj_delta = 0 + cur_factor = 0 + cur_f = false + cur_e = false + cw = 0 + usedfonts = setmetatableindex(usefont) + usedxforms = { } + usedximages = { } + boundingbox = specification.boundingbox + -- +-- if overload then +-- overload() +-- end +end + +-- buffer + +local buffer = { } +local b = 0 + +local function reset_buffer() + -- buffer = { } + b = 0 +end + +local function flush_buffer() + b = 0 +end + +local function show_buffer() + print(concat(buffer,"\n",1,b)) +end + +-- fonts + +local fontcharacters +local fontparameters +local fontproperties +local usedcharacters = setmetatableindex("table") +local pdfcharacters +local horizontalmode = true +----- widefontmode = true +local scalefactor = 1 +local minthreshold = -65536 * 5 +local maxthreshold = 65536 * 5 +local tjfactor = 100 / 65536 + +lpdf.usedcharacters = usedcharacters + +local function updatefontstate(font) + fontcharacters = characters[font] + fontparameters = parameters[font] + fontproperties = properties[font] + local size = fontparameters.size -- or bad news + local designsize = fontparameters.designsize or size + pdfcharacters = usedcharacters[font] + horizontalmode = fontparameters.writingmode ~= "vertical" + -- widefontmode = fontproperties.encodingbytes == 2 + scalefactor = (designsize/size) * tjfactor + maxthreshold = designsize + minthreshold = - maxthreshold +end + +-- helpers + +local f_cm = formatters["%.6F %.6F %.6F %.6F %.6F %.6F cm"] +local f_tm = formatters["%.6F %.6F %.6F %.6F %.6F %.6F Tm"] + +directives.register("pdf.stripzeros",function() + f_cm = formatters["%.6N %.6N %.6N %.6N %.6N %.6N cm"] + f_tm = formatters["%.6N %.6N %.6N %.6N %.6N %.6N Tm"] +end) + +local saved_text_pos_v = 0 +local saved_text_pos_h = 0 + +local function begin_text() + saved_text_pos_h = pdf_h + saved_text_pos_v = pdf_v + b = b + 1 ; buffer[b] = "BT" + need_tf = true + need_width = 0 + need_mode = 0 + mode = "text" +end + +local function end_text() + if done_width then + b = b + 1 ; buffer[b] = "0 w" + done_width = false + end + if done_mode then + b = b + 1 ; buffer[b] = "0 Tr" + done_mode = false + end + b = b + 1 ; buffer[b] = "ET" + pdf_h = saved_text_pos_h + pdf_v = saved_text_pos_v + mode = "page" +end + +local saved_chararray_pos_h +local saved_chararray_pos_v + +local saved_b = 0 + +local function begin_chararray() + saved_chararray_pos_h = pdf_h + saved_chararray_pos_v = pdf_v + cw = horizontalmode and saved_chararray_pos_h or - saved_chararray_pos_v + tj_delta = 0 + saved_b = b + b = b + 1 ; buffer[b] = " [" + mode = "chararray" +end + +local function end_chararray() + b = b + 1 ; buffer[b] = "] TJ" + buffer[saved_b] = concat(buffer,"",saved_b,b) + b = saved_b + pdf_h = saved_chararray_pos_h + pdf_v = saved_chararray_pos_v + mode = "text" +end + +local function begin_charmode() + -- b = b + 1 ; buffer[b] = widefontmode and "<" or "(" + b = b + 1 ; buffer[b] = "<" + mode = "char" +end + +local function end_charmode() + -- b = b + 1 ; buffer[b] = widefontmode and ">" or ")" + b = b + 1 ; buffer[b] = ">" + mode = "chararray" +end + +local function calc_pdfpos(h,v) + if mode == "page" then + cmtx = h - pdf_h + cmty = v - pdf_v + if h ~= pdf_h or v ~= pdf_v then + return true + end + elseif mode == "text" then + tmtx = h - saved_text_pos_h + tmty = v - saved_text_pos_v + if h ~= pdf_h or v ~= pdf_v then + return true + end + elseif horizontalmode then + tmty = v - saved_text_pos_v + tj_delta = cw - h -- + saved_chararray_pos_h + if tj_delta ~= 0 or v ~= pdf_v then + return true + end + else + tmtx = h - saved_text_pos_h + tj_delta = cw + v -- - saved_chararray_pos_v + if tj_delta ~= 0 or h ~= pdf_h then + return true + end + end + return false +end + +local function pdf_set_pos(h,v) + local move = calc_pdfpos(h,v) + if move then + b = b + 1 ; buffer[b] = f_cm(cmrx, cmsx, cmsy, cmry, cmtx*bpfactor, cmty*bpfactor) + pdf_h = pdf_h + cmtx + pdf_v = pdf_v + cmty + end +end + +local function pdf_reset_pos() -- pdf_set_pos(0,0) + if mode == "page" then + cmtx = - pdf_h + cmty = - pdf_v + if pdf_h == 0 and pdf_v == 0 then + return + end + elseif mode == "text" then + tmtx = - saved_text_pos_h + tmty = - saved_text_pos_v + if pdf_h == 0 and pdf_v == 0 then + return + end + elseif horizontalmode then + tmty = - saved_text_pos_v + tj_delta = cw + if tj_delta == 0 and pdf_v == 0 then + return + end + else + tmtx = - saved_text_pos_h + tj_delta = cw + if tj_delta == 0 and pdf_h == 0 then + return + end + end + b = b + 1 ; buffer[b] = f_cm(cmrx, cmsx, cmsy, cmry, cmtx*bpfactor, cmty*bpfactor) + pdf_h = pdf_h + cmtx + pdf_v = pdf_v + cmty +end + +local function pdf_set_pos_temp(h,v) + local move = calc_pdfpos(h,v) + if move then + b = b + 1 ; buffer[b] = f_cm(cmrx, cmsx, cmsy, cmry, cmtx*bpfactor, cmty*bpfactor) + end +end + +local function pdf_end_string_nl() + if mode == "char" then + end_charmode() + end_chararray() + elseif mode == "chararray" then + end_chararray() + end +end + +local function pdf_goto_textmode() + if mode == "page" then + -- pdf_set_pos(0,0) + pdf_reset_pos() + begin_text() + elseif mode ~= "text" then + if mode == "char" then + end_charmode() + end_chararray() + else -- if mode == "chararray" then + end_chararray() + end + end +end + +local function pdf_goto_pagemode() + if mode ~= "page" then + if mode == "char" then + end_charmode() + end_chararray() + end_text() + elseif mode == "chararray" then + end_chararray() + end_text() + elseif mode == "text" then + end_text() + end + end +end + +local function pdf_goto_fontmode() + if mode == "char" then + end_charmode() + end_chararray() + end_text() + elseif mode == "chararray" then + end_chararray() + end_text() + elseif mode == "text" then + end_text() + end + -- pdf_set_pos(0,0) + pdf_reset_pos() + mode = "page" +end + +-- characters + +local flushcharacter do + + local round = math.round + + local function setup_fontparameters(font,factor,f,e) + local slant = (fontparameters.slantfactor or 0) / 1000 + local extend = (fontparameters.extendfactor or 1000) / 1000 + local squeeze = (fontparameters.squeezefactor or 1000) / 1000 + local expand = 1 + factor / 1000000 + local format = fontproperties.format + if e then + extend = extend * e + end + tmrx = expand * extend + tmsy = slant + tmry = squeeze + need_width = fontparameters.width + need_mode = fontparameters.mode + f_cur = font + f_pdf = usedfonts[font] -- cache + cur_factor = factor + cur_f = f + cur_e = e + tj_delta = 0 + fs = fontparameters.size * bpfactor + if f then + fs = fs * f + end + -- kind of special: + if format == "opentype" or format == "type1" then + fs = fs * 1000 / fontparameters.units -- can we avoid this ? + end + end + + local f_width = formatters["%.6F w"] + local f_mode = formatters["%i Tr"] + local f_font = formatters["/F%i %.6F Tf"] + local s_width = "0 w" + local s_mode = "0 Tr" + + directives.register("pdf.stripzeros",function() + f_width = formatters["%.6N w"] + f_font = formatters["/F%i %.6N Tf"] + end) + + local function set_font() + if need_width and need_width ~= 0 then + b = b + 1 ; buffer[b] = f_width(bpfactor * need_width / 1000) + done_width = true + elseif done_width then + b = b + 1 ; buffer[b] = s_width + done_width = false + end + if need_mode and need_mode ~= 0 then + b = b + 1 ; buffer[b] = f_mode(need_mode) + done_mode = true + elseif done_mode then + b = b + 1 ; buffer[b] = s_mode + done_mode = false + end + b = b + 1 ; buffer[b] = f_font(f_pdf,fs) + f_pdf_cur = f_pdf + fs_cur = fs + need_tf = false + need_tm = true + end + + local function set_textmatrix(h,v) + local move = calc_pdfpos(h,v) -- duplicate + if need_tm or move then + b = b + 1 ; buffer[b] = f_tm(tmrx, tmsx, tmsy, tmry, tmtx*bpfactor, tmty*bpfactor) + pdf_h = saved_text_pos_h + tmtx + pdf_v = saved_text_pos_v + tmty + need_tm = false + end + cur_tmrx = tmrx + end + + -- local f_skip = formatters["%i"] + -- local f_octal = formatters["\\%o"] + -- local f_char = formatters["%c"] + local f_hex = formatters["%04X"] + + local h_hex = setmetatableindex(function(t,k) + local v = f_hex(k) + t[k] = v + return v + end) + + flushcharacter = function(current,pos_h,pos_v,pos_r,font,char,data,factor,width,f,e) + if need_tf or font ~= f_cur or f_pdf ~= f_pdf_cur or fs ~= fs_cur or mode == "page" then + pdf_goto_textmode() + setup_fontparameters(font,factor,f,e) + set_font() + elseif cur_tmrx ~= tmrx or cur_factor ~= factor or cur_f ~= f or cur_e ~= e then + setup_fontparameters(font,factor,f,e) + need_tm = true + end + local move = calc_pdfpos(pos_h,pos_v) + if move or need_tm then + if not need_tm then + if horizontalmode then + if (saved_text_pos_v + tmty) ~= pdf_v then + need_tm = true + elseif tj_delta >= maxthreshold or tj_delta <= minthreshold then + need_tm = true + end + else + if (saved_text_pos_h + tmtx) ~= pdf_h then + need_tm = true + elseif tj_delta >= maxthreshold or tj_delta <= minthreshold then + need_tm = true + end + end + end + if need_tm then + pdf_goto_textmode() + set_textmatrix(pos_h,pos_v) + begin_chararray() + move = calc_pdfpos(pos_h,pos_v) + end + if move then + -- local d = round(tj_delta * scalefactor) + -- if d ~= 0 then + local d = tj_delta * scalefactor + if d <= -0.5 or d >= 0.5 then + if mode == "char" then + end_charmode() + end + -- b = b + 1 ; buffer[b] = f_skip(d) + -- b = b + 1 ; buffer[b] = d + b = b + 1 ; buffer[b] = round(d) + end + cw = cw - tj_delta + end + end + if mode == "chararray" then + begin_charmode(font) + end + + local index = data.index or char + + b = b + 1 + -- if widefontmode then + -- buffer[b] = h_hex[data.index or 0] + buffer[b] = h_hex[index] + -- elseif char > 255 then + -- buffer[b] = f_octal(32) + -- elseif char <= 32 or char == 92 or char == 40 or char == 41 or char > 127 then -- \ ( ) + -- buffer[b] = f_octal(char) + -- else + -- buffer[b] = f_char(char) + -- end + + cw = cw + width + + -- pdfcharacters[fontcharacters[char].index or char] = true + pdfcharacters[index] = true + + end + +end + +-- literals + +local flushpdfliteral do + + local literalvalues = nodes.literalvalues + + local originliteral_code = literalvalues.origin + local pageliteral_code = literalvalues.page + local alwaysliteral_code = literalvalues.always + local rawliteral_code = literalvalues.raw + local textliteral_code = literalvalues.text + local fontliteral_code = literalvalues.font + + local nodeproperties = nodes.properties.data + + flushpdfliteral = function(current,pos_h,pos_v,mode,str) + if mode then + if not str then + mode, str = originliteral_code, mode + elseif mode == "mode" then + mode = literalvalues[str] + if mode == originliteral_code then + pdf_goto_pagemode() + pdf_set_pos(pos_h,pos_v) + elseif mode == pageliteral_code then + pdf_goto_pagemode() + elseif mode == textliteral_code then + pdf_goto_textmode() + elseif mode == fontliteral_code then + pdf_goto_fontmode() + elseif mode == alwaysliteral_code then + pdf_end_string_nl() + need_tm = true + elseif mode == rawliteral_code then + pdf_end_string_nl() + end + return + else + mode = literalvalues[mode] + end + else + -- str, mode = getdata(current) + local p = nodeproperties[current] +if p then + str = p.data + mode = p.mode +else + str, mode = getdata(current) +end + end + if str and str ~= "" then + if mode == originliteral_code then + pdf_goto_pagemode() + pdf_set_pos(pos_h,pos_v) + elseif mode == pageliteral_code then + pdf_goto_pagemode() + elseif mode == textliteral_code then + pdf_goto_textmode() + elseif mode == fontliteral_code then + pdf_goto_fontmode() + elseif mode == alwaysliteral_code then + pdf_end_string_nl() + need_tm = true + elseif mode == rawliteral_code then + pdf_end_string_nl() + else + print("check literal") + pdf_goto_pagemode() + pdf_set_pos(pos_h,pos_v) + end + b = b + 1 ; buffer[b] = str + end + end + + updaters.register("backend.update.pdf",function() + function pdf.print(mode,str) + if str then + mode = literalvalues[mode] + else + mode, str = originliteral_code, mode + end + if str and str ~= "" then + if mode == originliteral_code then + pdf_goto_pagemode() + -- pdf_set_pos(pdf_h,pdf_v) + elseif mode == pageliteral_code then + pdf_goto_pagemode() + elseif mode == textliteral_code then + pdf_goto_textmode() + elseif mode == fontliteral_code then + pdf_goto_fontmode() + elseif mode == alwaysliteral_code then + pdf_end_string_nl() + need_tm = true + elseif mode == rawliteral_code then + pdf_end_string_nl() + else + pdf_goto_pagemode() + -- pdf_set_pos(pdf_h,pdf_v) + end + b = b + 1 ; buffer[b] = str + end + end + end) + +end + +-- grouping & orientation + +local flushpdfsave, flushpdfrestore, flushpdfsetmatrix do + + local matrices = { } + local positions = { } + local nofpositions = 0 + local nofmatrices = 0 + + local f_matrix = formatters["%s 0 0 cm"] + + flushpdfsave = function(current,pos_h,pos_v) + nofpositions = nofpositions + 1 + positions[nofpositions] = { pos_h, pos_v, nofmatrices } + pdf_goto_pagemode() + pdf_set_pos(pos_h,pos_v) + b = b + 1 ; buffer[b] = "q" + end + + flushpdfrestore = function(current,pos_h,pos_v) + if nofpositions < 1 then + return + end + local t = positions[nofpositions] + -- local h = pos_h - t[1] + -- local v = pos_v - t[2] + if shippingmode == "page" then + nofmatrices = t[3] + end + pdf_goto_pagemode() + pdf_set_pos(pos_h,pos_v) + b = b + 1 ; buffer[b] = "Q" + nofpositions = nofpositions - 1 + end + + local function pdf_set_matrix(str,pos_h,pos_v) + if shippingmode == "page" then + local rx, sx, sy, ry = splitstring(str," ") + if rx and ry and sx and ry then + rx, sx, sy, ry = tonumber(rx), tonumber(ry), tonumber(sx), tonumber(sy) + local tx = pos_h * (1 - rx) - pos_v * sy + local ty = pos_v * (1 - ry) - pos_h * sx + if nofmatrices > 1 then + local t = matrices[nofmatrices] + local r_x, s_x, s_y, r_y, te, tf = t[1], t[2], t[3], t[4], t[5], t[6] + rx, sx = rx * r_x + sx * s_y, rx * s_x + sx * r_y + sy, ry = sy * r_x + ry * s_y, sy * s_x + ry * r_y + tx, ty = tx * r_x + ty * s_y + t_x, tx * s_x + ty * r_y + t_y + end + nofmatrices = nofmatrices + 1 + matrices[nofmatrices] = { rx, sx, sy, ry, tx, ty } + end + end + end + + local nodeproperties = nodes.properties.data + + flushpdfsetmatrix = function(current,pos_h,pos_v) + local str + if type(current) == "string" then + str = current + else + local p = nodeproperties[current] + if p then + str = p.matrix + else + str = getdata(current) -- for the moment + end + end + if str and str ~= "" then + pdf_set_matrix(str,pos_h,pos_v) + pdf_goto_pagemode() + pdf_set_pos(pos_h,pos_v) + b = b + 1 ; buffer[b] = f_matrix(str) + end + end + + do + + local function hasmatrix() + return nofmatrices > 0 + end + + local function getmatrix() + if nofmatrices > 0 then + return unpack(matrices[nofmatrices]) + else + return 0, 0, 0, 0, 0, 0 -- or 1 0 0 1 0 0 + end + end + + updaters.register("backend.update.pdf",function() + pdf.hasmatrix = hasmatrix + pdf.getmatrix = getmatrix + end) + + end + + pushorientation = function(orientation,pos_h,pos_v,pos_r) + pdf_goto_pagemode() + pdf_set_pos(pos_h,pos_v) + b = b + 1 ; buffer[b] = "q" + if orientation == 1 then + b = b + 1 ; buffer[b] = "0 -1 1 0 0 0 cm" -- 90 + elseif orientation == 2 then + b = b + 1 ; buffer[b] = "-1 0 0 -1 0 0 cm" -- 180 + elseif orientation == 3 then + b = b + 1 ; buffer[b] = "0 1 -1 0 0 0 cm" -- 270 + end + end + + poporientation = function(orientation,pos_h,pos_v,pos_r) + pdf_goto_pagemode() + pdf_set_pos(pos_h,pos_v) + b = b + 1 ; buffer[b] = "Q" + end + +-- pushorientation = function(orientation,pos_h,pos_v,pos_r) +-- flushpdfsave(false,pos_h,pos_v) +-- if orientation == 1 then +-- flushpdfsetmatrix("0 -1 1 0",pos_h,pos_v) +-- elseif orientation == 2 then +-- flushpdfsetmatrix("-1 0 0 -1",pos_h,pos_v) +-- elseif orientation == 3 then +-- flushpdfsetmatrix("0 1 -1 0",pos_h,pos_v) +-- end +-- end + +-- poporientation = function(orientation,pos_h,pos_v,pos_r) +-- flushpdfrestore(false,pos_h,pos_v) +-- end + +end + +-- rules + +local flushedxforms = { } -- actually box resources but can also be direct + +local flushrule, flushsimplerule do + + local rulecodes = nodes.rulecodes + local newrule = nodes.pool.rule + + local setprop = nuts.setprop + local getprop = nuts.getprop + + local normalrule_code = rulecodes.normal + local boxrule_code = rulecodes.box + local imagerule_code = rulecodes.image + local emptyrule_code = rulecodes.empty + local userrule_code = rulecodes.user + local overrule_code = rulecodes.over + local underrule_code = rulecodes.under + local fractionrule_code = rulecodes.fraction + local radicalrule_code = rulecodes.radical + local outlinerule_code = rulecodes.outline + + local rule_callback = callbacks.functions.process_rule + + local f_fm = formatters["/Fm%d Do"] + local f_im = formatters["/Im%d Do"] + + local s_b = "q" + local s_e = "Q" + + local f_v = formatters["[] 0 d 0 J %.6F w 0 0 m %.6F 0 l S"] + local f_h = formatters["[] 0 d 0 J %.6F w 0 0 m 0 %.6F l S"] + + local f_f = formatters["0 0 %.6F %.6F re f"] + local f_o = formatters["[] 0 d 0 J 0 0 %.6F %.6F re S"] + local f_w = formatters["[] 0 d 0 J %.6F w 0 0 %.6F %.6F re S"] + + directives.register("pdf.stripzeros",function() + f_v = formatters["[] 0 d 0 J %.6N w 0 0 m %.6N 0 l S"] + f_h = formatters["[] 0 d 0 J %.6N w 0 0 m 0 %.6N l S"] + f_f = formatters["0 0 %.6N %.6N re f"] + f_o = formatters["[] 0 d 0 J 0 0 %.6N %.6N re S"] + f_w = formatters["[] 0 d 0 J %.6N w 0 0 %.6N %.6N re S"] + end) + + -- Historically the index is an object which is kind of bad. + + local boxresources, n = { }, 0 + + getxformname = function(index) + local l = boxresources[index] + if l then + return l.name + else + print("no box resource",index) + end + end + + updaters.register("backend.update.pdf",function() + pdf.getxformname = getxformname + end) + + local function saveboxresource(box,attributes,resources,immediate,kind,margin) + n = n + 1 + local immediate = true + local margin = margin or 0 -- or dimension + local objnum = pdfreserveobject() + local list = tonut(type(box) == "number" and tex.takebox(box) or box) + -- + local width, height, depth = getwhd(list) + -- + local l = { + width = width, + height = height, + depth = depth, + margin = margin, + attributes = attributes, + resources = resources, + list = nil, + type = kind, + name = n, + index = objnum, + objnum = objnum, + } + boxresources[objnum] = l + if immediate then + lpdf.convert(list,"xform",objnum,l) + flushedxforms[objnum] = { true , objnum } + flushlist(list) + else + l.list = list + end + return objnum + end + + local function useboxresource(index,wd,ht,dp) + local l = boxresources[index] + if l then + if wd or ht or dp then + wd, ht, dp = wd or 0, ht or 0, dp or 0 + else + wd, ht, dp = l.width, l.height, l.depth + end + local rule = newrule(wd,ht,dp) -- newboxrule + rule.subtype = boxrule_code + setprop(tonut(rule),"index",index) + return rule, wd, ht, dp + else + print("no box resource",index) + end + end + + local function getboxresourcedimensions(index) + local l = boxresources[index] + if l then + return l.width, l.height, l.depth, l.margin + else + print("no box resource",index) + end + end + + local function getboxresourcebox(index) + local l = boxresources[index] + if l then + return l.list + end + end + + updaters.register("backend.update.tex",function() + tex.saveboxresource = saveboxresource + tex.useboxresource = useboxresource + tex.getboxresourcedimensions = getboxresourcedimensions + tex.getboxresourcebox = getboxresourcebox + end) + + -- a bit of a mess: index is now objnum but that has to change to a proper index + -- ... an engine inheritance + + local function flushpdfxform(current,pos_h,pos_v,pos_r,size_h,size_v) + -- object properties + local objnum = getprop(current,"index") + local name = getxformname(objnum) + local info = flushedxforms[objnum] + local r = boxresources[objnum] + if not info then + info = { false , objnum } + flushedxforms[objnum] = info + end + local wd, ht, dp = getboxresourcedimensions(objnum) + -- or: wd, ht, dp = r.width, r.height, r.depth + -- sanity check + local htdp = ht + dp + if wd == 0 or size_h == 0 or htdp == 0 or size_v == 0 then + return + end + -- calculate scale + local rx, ry = 1, 1 + if wd ~= size_h or htdp ~= size_v then + rx = size_h / wd + ry = size_v / htdp + end + -- flush the reference + usedxforms[objnum] = true + pdf_goto_pagemode() + calc_pdfpos(pos_h,pos_v) + tx = cmtx * bpfactor + ty = cmty * bpfactor + b = b + 1 ; buffer[b] = s_b + b = b + 1 ; buffer[b] = f_cm(rx,0,0,ry,tx,ty) + b = b + 1 ; buffer[b] = f_fm(name) + b = b + 1 ; buffer[b] = s_e + end + + -- place image also used in vf but we can use a different one if + -- we need it + + local imagetypes = images.types -- pdf png jpg jp2 jbig2 stream memstream + local img_none = imagetypes.none + local img_pdf = imagetypes.pdf + local img_stream = imagetypes.stream + local img_memstream = imagetypes.memstream + + local one_bp = 65536 * bpfactor + + local imageresources, n = { }, 0 + + getximagename = function(index) + local l = imageresources[index] + if l then + return l.name + else + print("no image resource",index) + end + end + + updaters.register("backend.update.pdf",function() + pdf.getximagename = getximagename + end) + + local function flushpdfximage(current,pos_h,pos_v,pos_r,size_h,size_v) + + local width, + height, + depth = getwhd(current) + local total = height + depth + local transform = getprop(current,"transform") or 0 -- we never set it ... so just use rotation then + local index = getprop(current,"index") or 0 + local kind, + xorigin, + yorigin, + xsize, + ysize, + rotation, + objnum, + groupref = pdfincludeimage(index) -- needs to be sorted out, bad name (no longer mixed anyway) + + if not kind then + print("invalid image",index) + return + end + + local rx, sx, sy, ry, tx, ty = 1, 0, 0, 1, 0, 0 + + if kind == img_pdf or kind == img_stream or kind == img_memstream then + rx, ry, tx, ty = 1/xsize, 1/ysize, xorigin/xsize, yorigin/ysize + else + -- if kind == img_png then + -- -- if groupref > 0 and img_page_group_val == 0 then + -- -- img_page_group_val = groupref + -- -- end + -- end + rx, ry = bpfactor, bpfactor + end + + if band(transform,7) > 3 then + -- mirror + rx, tx = -rx, -tx + end + local t = band(transform + rotation,3) + if t == 0 then + -- nothing + elseif t == 1 then + -- rotation over 90 degrees (counterclockwise) + rx, sx, sy, ry, tx, ty = 0, rx, -ry, 0, -ty, tx + elseif t == 2 then + -- rotation over 180 degrees (counterclockwise) + rx, ry, tx, ty = -rx, -ry, -tx, -ty + elseif t == 3 then + -- rotation over 270 degrees (counterclockwise) + rx, sx, sy, ry, tx, ty = 0, -rx, ry, 0, ty, -tx + end + + rx = rx * width + sx = sx * total + sy = sy * width + ry = ry * total + tx = pos_h - tx * width + ty = pos_v - ty * total + + local t = transform + rotation + + if band(transform,7) > 3 then + t = t + 1 + end + + t = band(t,3) + + if t == 0 then + -- no transform + elseif t == 1 then + -- rotation over 90 degrees (counterclockwise) + tx = tx + width + elseif t == 2 then + -- rotation over 180 degrees (counterclockwise) + tx = tx + width + ty = ty + total + elseif t == 3 then + -- rotation over 270 degrees (counterclockwise) + ty = ty + total + end + + -- a flaw in original, can go: + -- + -- if img_page_group_val == 0 then + -- img_page_group_val = group_ref + -- end + + usedximages[index] = objnum -- hm + + pdf_goto_pagemode() + + calc_pdfpos(tx,ty) + + tx = cmtx * bpfactor + ty = cmty * bpfactor + + b = b + 1 ; buffer[b] = s_b + b = b + 1 ; buffer[b] = f_cm(rx,sx,sy,ry,tx,ty) + b = b + 1 ; buffer[b] = f_im(index) + b = b + 1 ; buffer[b] = s_e + end + + flushpdfimage = function(index,width,height,depth,pos_h,pos_v) + + -- used in vf characters + + local total = height + depth + local kind, + xorigin, yorigin, + xsize, ysize, + rotation, + objnum, + groupref = pdfincludeimage(index) + + local rx = width / xsize + local sx = 0 + local sy = 0 + local ry = total / ysize + local tx = pos_h + local ty = pos_v - 2 * depth -- to be sorted out + + usedximages[index] = objnum + + pdf_goto_pagemode() + + calc_pdfpos(tx,ty) + + tx = cmtx * bpfactor + ty = cmty * bpfactor + + b = b + 1 ; buffer[b] = s_b + b = b + 1 ; buffer[b] = f_cm(rx,sx,sy,ry,tx,ty) + b = b + 1 ; buffer[b] = f_im(index) + b = b + 1 ; buffer[b] = s_e + end + + -- For the moment we need this hack because the engine checks the 'image' + -- command in virtual fonts (so we use lua instead). + + pdf.flushpdfimage = flushpdfimage + + flushrule = function(current,pos_h,pos_v,pos_r,size_h,size_v) + + local subtype = getsubtype(current) + if subtype == emptyrule_code then + return + elseif subtype == boxrule_code then + return flushpdfxform(current,pos_h,pos_v,pos_r,size_h,size_v) + elseif subtype == imagerule_code then + return flushpdfximage(current,pos_h,pos_v,pos_r,size_h,size_v) + end + if subtype == userrule_code or subtype >= overrule_code and subtype <= radicalrule_code then + pdf_goto_pagemode() + b = b + 1 ; buffer[b] = s_b + pdf_set_pos_temp(pos_h,pos_v) + rule_callback(current,size_h,size_v,pos_r) -- so we pass direction + b = b + 1 ; buffer[b] = s_e + return + end + + pdf_goto_pagemode() + + -- local saved_b = b + + b = b + 1 ; buffer[b] = s_b + + local dim_h = size_h * bpfactor + local dim_v = size_v * bpfactor + local rule + + if dim_v <= one_bp then + pdf_set_pos_temp(pos_h,pos_v + 0.5 * size_v) + rule = f_v(dim_v,dim_h) + elseif dim_h <= one_bp then + pdf_set_pos_temp(pos_h + 0.5 * size_h,pos_v) + rule = f_h(dim_h,dim_v) + else + pdf_set_pos_temp(pos_h,pos_v) + if subtype == outlinerule_code then + local linewidth = getdata(current) + if linewidth > 0 then + rule = f_w(linewidth * bpfactor,dim_h,dim_v) + else + rule = f_o(dim_h,dim_v) + end + else + rule = f_f(dim_h,dim_v) + end + end + + b = b + 1 ; buffer[b] = rule + b = b + 1 ; buffer[b] = s_e + + -- buffer[saved_b] = concat(buffer," ",saved_b,b) + -- b = saved_b + + end + + flushsimplerule = function(pos_h,pos_v,pos_r,size_h,size_v) + pdf_goto_pagemode() + + b = b + 1 ; buffer[b] = s_b + + local dim_h = size_h * bpfactor + local dim_v = size_v * bpfactor + local rule + + if dim_v <= one_bp then + pdf_set_pos_temp(pos_h,pos_v + 0.5 * size_v) + rule = f_v(dim_v,dim_h) + elseif dim_h <= one_bp then + pdf_set_pos_temp(pos_h + 0.5 * size_h,pos_v) + rule = f_h(dim_h,dim_v) + else + pdf_set_pos_temp(pos_h,pos_v) + rule = f_f(dim_h,dim_v) + end + + b = b + 1 ; buffer[b] = rule + b = b + 1 ; buffer[b] = s_e + end + +end + +--- basics + +local wrapup, registerpage do + + local pages = { } + local maxkids = 10 + local nofpages = 0 + + registerpage = function(object) + nofpages = nofpages + 1 + local objnum = pdfpagereference(nofpages) + pages[nofpages] = { + objnum = objnum, + object = object, + } + end + + wrapup = function() + + -- local includechar = lpdf.includecharlist + -- + -- for font, list in next, usedcharacters do + -- includechar(font,keys(list)) + -- end + + -- hook (to reshuffle pages) + local pagetree = { } + local parent = nil + local minimum = 0 + local maximum = 0 + local current = 0 + if #pages > 1.5 * maxkids then + repeat + local plist, pnode + if current == 0 then + plist, minimum = pages, 1 + elseif current == 1 then + plist, minimum = pagetree, 1 + else + plist, minimum = pagetree, maximum + 1 + end + maximum = #plist + if maximum > minimum then + local kids + for i=minimum,maximum do + local p = plist[i] + if not pnode or #kids == maxkids then + kids = pdfarray() + parent = pdfreserveobject() + pnode = pdfdictionary { + objnum = parent, + Type = pdf_pages, + Kids = kids, + Count = 0, + } + pagetree[#pagetree+1] = pnode + end + kids[#kids+1] = pdfreference(p.objnum) + pnode.Count = pnode.Count + (p.Count or 1) + p.Parent = pdfreference(parent) + end + end + current = current + 1 + until maximum == minimum + -- flush page tree + for i=1,#pagetree do + local entry = pagetree[i] + local objnum = entry.objnum + entry.objnum = nil + pdfflushobject(objnum,entry) + end + else + -- ugly + local kids = pdfarray() + local list = pdfdictionary { + Type = pdf_pages, + Kids = kids, + Count = nofpages, + } + parent = pdfreserveobject() + for i=1,nofpages do + local page = pages[i] + kids[#kids+1] = pdfreference(page.objnum) + page.Parent = pdfreference(parent) + end + pdfflushobject(parent,list) + end + for i=1,nofpages do + local page = pages[i] + local object = page.object + object.Parent = page.Parent + pdfflushobject(page.objnum,object) + end + lpdf.addtocatalog("Pages",pdfreference(parent)) + + end + +end + +pdf_h, pdf_v = 0, 0 + +local function initialize(specification) + reset_variables(specification) + reset_buffer() +end + +local f_font = formatters["F%d"] +local f_form = formatters["Fm%d"] +local f_image = formatters["Im%d"] + +-- This will all move and be merged and become less messy. + +-- todo: more clever resource management: a bit tricky as we can inject +-- stuff in the page stream + +local pushmode, popmode + +local function finalize(objnum,specification) + + pushmode() + + pdf_goto_pagemode() -- for now + + local content = concat(buffer,"\n",1,b) + + local fonts = nil + local xforms = nil + + if next(usedfonts) then + fonts = pdfdictionary { } + for k, v in next, usedfonts do + fonts[f_font(v)] = pdfreference(pdfgetfontobjnumber(k)) -- we can overload for testing + end + end + + -- messy: use real indexes for both ... so we need to change some in the + -- full luatex part + + if next(usedxforms) or next(usedximages) then + xforms = pdfdictionary { } + for k in sortedhash(usedxforms) do + -- xforms[f_form(k)] = pdfreference(k) + xforms[f_form(getxformname(k))] = pdfreference(k) + end + for k, v in sortedhash(usedximages) do + xforms[f_image(k)] = pdfreference(v) + end + end + + reset_buffer() + + -- finish_pdfpage_callback(shippingmode == "page") + + if shippingmode == "page" then + + local pageproperties = lpdf.getpageproperties() + + local pageresources = pageproperties.pageresources + local pageattributes = pageproperties.pageattributes + local pagesattributes = pageproperties.pagesattributes + + pageresources.Font = fonts + pageresources.XObject = xforms + pageresources.ProcSet = lpdf.procset() + + local contentsobj = pdfflushstreamobject(content,false,false) + + pageattributes.Type = pdf_page + pageattributes.Contents = pdfreference(contentsobj) + pageattributes.Resources = pageresources + -- pageattributes.Resources = pdfreference(pdfflushobject(pageresources)) + pageattributes.MediaBox = pdfarray { + boundingbox[1] * bpfactor, + boundingbox[2] * bpfactor, + boundingbox[3] * bpfactor, + boundingbox[4] * bpfactor, + } + pageattributes.Parent = nil -- precalculate + pageattributes.Group = nil -- todo + + -- resources can be indirect + + registerpage(pageattributes) + + lpdf.finalizepage(true) + + else + + local xformtype = specification.type or 0 + local margin = specification.margin or 0 + local attributes = specification.attributes or "" + local resources = specification.resources or "" + local wrapper = nil + if xformtype == 0 then + wrapper = pdfdictionary { + Type = pdf_xobject, + Subtype = pdf_form, + FormType = 1, + BBox = nil, + Matrix = nil, + Resources = nil, + } + else + wrapper = pdfdictionary { + BBox = nil, + Matrix = nil, + Resources = nil, + } + end + if xformtype == 0 or xformtype == 1 or xformtype == 3 then + wrapper.BBox = pdfarray { + -margin * bpfactor, + -margin * bpfactor, + (boundingbox[3] + margin) * bpfactor, + (boundingbox[4] + margin) * bpfactor, + } + end + if xformtype == 0 or xformtype == 2 or xformtype == 3 then + wrapper.Matrix = pdfarray { 1, 0, 0, 1, 0, 0 } + end + + -- todo: additional = resources + + local boxresources = lpdf.collectedresources { serialize = false } + boxresources.Font = fonts + boxresources.XObject = xforms + + -- todo: maybe share them + -- wrapper.Resources = pdfreference(pdfflushobject(boxresources)) + + if resources ~= "" then + boxresources = boxresources + resources + end + if attributes ~= "" then + wrapper = wrapper + attributes + end + + wrapper.Resources = next(boxresources) and boxresources or nil + wrapper.ProcSet = lpdf.procset() + + -- pdfflushstreamobject(content,wrapper,false,objectnumber) + pdfflushstreamobject(content,wrapper,false,specification.objnum) + + end + + for objnum in sortedhash(usedxforms) do + local f = flushedxforms[objnum] + if f[1] == false then + f[1] = true + local objnum = f[2] -- specification.objnum + local specification = boxresources[objnum] + local list = specification.list + lpdf.convert(list,"xform",f[2],specification) + end + end + + pdf_h, pdf_v = 0, 0 + + popmode() + +end + +updaters.register("backend.update.pdf",function() + job.positions.registerhandlers { + getpos = drivers.getpos, + gethpos = drivers.gethpos, + getvpos = drivers.getvpos, + } +end) + +updaters.register("backend.update",function() + local saveboxresource = tex.boxresources.save + -- + -- also in lpdf-res .. brrr .. needs fixing + -- + backends.codeinjections.registerboxresource = function(n,offset) + local r = saveboxresource(n,nil,nil,false,0,offset or 0) + return r + end +end) + +-- now comes the pdf file handling + +local objects = { } +local streams = { } -- maybe just parallel to objects (no holes) +local nofobjects = 0 +local offset = 0 +local f = false +local flush = false +local threshold = 40 -- also #("/Filter /FlateDecode") +local objectstream = true +local compress = true +local cache = false +local info = "" +local catalog = "" +local level = 0 +local lastdeferred = false +local enginepdf = pdf +local majorversion = 1 +local minorversion = 7 +local trailerid = true + +local f_object = formatters["%i 0 obj\010%s\010endobj\010"] +local f_stream_n_u = formatters["%i 0 obj\010<< /Length %i >>\010stream\010%s\010endstream\010endobj\010"] +local f_stream_n_c = formatters["%i 0 obj\010<< /Filter /FlateDecode /Length %i >>\010stream\010%s\010endstream\010endobj\010"] +local f_stream_d_u = formatters["%i 0 obj\010<< %s /Length %i >>\010stream\010%s\010endstream\010endobj\010"] +local f_stream_d_c = formatters["%i 0 obj\010<< %s /Filter /FlateDecode /Length %i >>\010stream\010%s\010endstream\010endobj\010"] +local f_stream_d_r = formatters["%i 0 obj\010<< %s >>\010stream\010%s\010endstream\010endobj\010"] + +local f_object_b = formatters["%i 0 obj\010"] +local f_stream_b_n_u = formatters["%i 0 obj\010<< /Length %i >>\010stream\010"] +local f_stream_b_n_c = formatters["%i 0 obj\010<< /Filter /FlateDecode /Length %i >>\010stream\010"] +local f_stream_b_d_u = formatters["%i 0 obj\010<< %s /Length %i >>\010stream\010"] +local f_stream_b_d_c = formatters["%i 0 obj\010<< %s /Filter /FlateDecode /Length %i >>\010stream\010"] +local f_stream_b_d_r = formatters["%i 0 obj\010<< %s >>\010stream\010"] + +local s_object_e = "\010endobj\010" +local s_stream_e = "\010endstream\010endobj\010" + +do + + local function setinfo() end -- we get it + local function setcatalog() end -- we get it + + local function settrailerid(v) + trailerid = v or false + end + + local function setmajorversion(v) majorversion = tonumber(v) or majorversion end + local function setminorversion(v) minorversion = tonumber(v) or minorversion end + + local function getmajorversion(v) return majorversion end + local function getminorversion(v) return minorversion end + + local function setcompresslevel (v) compress = v and v ~= 0 and true or false end + local function setobjcompresslevel(v) objectstream = v and v ~= 0 and true or false end + + local function getcompresslevel (v) return compress and 3 or 0 end + local function getobjcompresslevel(v) return objectstream and 1 or 0 end + + local function setpageresources () end -- needs to be sorted out + local function setpageattributes () end + local function setpagesattributes() end + + updaters.register("backend.update.pdf",function() + pdf.setinfo = setinfo + pdf.setcatalog = setcatalog + pdf.settrailerid = settrailerid + pdf.setmajorversion = setmajorversion + pdf.setminorversion = setminorversion + pdf.getmajorversion = getmajorversion + pdf.getminorversion = getminorversion + pdf.setcompresslevel = setcompresslevel + pdf.setobjcompresslevel = setobjcompresslevel + pdf.getcompresslevel = getcompresslevel + pdf.getobjcompresslevel = getobjcompresslevel + pdf.setpageresources = setpageresources + pdf.setpageattributes = setpageattributes + pdf.setpagesattributes = setpagesattributes + end) + +end + +local function pdfreserveobj() + nofobjects = nofobjects + 1 + objects[nofobjects] = false + return nofobjects +end + +local addtocache, flushcache, cache do + + local data, d = { }, 0 + local list, l = { }, 0 + local coffset = 0 + local maxsize = 32 * 1024 -- uncompressed + local maxcount = 0xFF + local indices = { } + + addtocache = function(n,str) + local size = #str + if size == 0 then + -- todo: message + return + end + if coffset + size > maxsize or d == maxcount then + flushcache() + end + if d == 0 then + nofobjects = nofobjects + 1 + objects[nofobjects] = false + streams[nofobjects] = indices + cache = nofobjects + end + objects[n] = - cache + indices[n] = d + d = d + 1 + -- can have a comment n 0 obj as in luatex + data[d] = str + l = l + 1 ; list[l] = n + l = l + 1 ; list[l] = coffset + coffset = coffset + size + 1 + end + + local p_ObjStm = pdfconstant("ObjStm") + + flushcache = function() -- references cannot be stored + if l > 0 then + list = concat(list," ") + data[0] = list + data = concat(data,"\010",0,d) + local strobj = pdfdictionary { + Type = p_ObjStm, + N = d, + First = #list + 1, + } + objects[cache] = offset + local b = nil + local e = s_stream_e + if compress then + local comp = zlibcompress(data,3) + if comp and #comp < #data then + data = comp + b = f_stream_b_d_c(cache,strobj(),#data) + else + b = f_stream_b_d_u(cache,strobj(),#data) + end + else + b = f_stream_b_d_u(cache,strobj(),#data) + end + flush(f,b) + flush(f,data) + flush(f,e) + offset = offset + #b + #data + #e + data, d = { }, 0 + list, l = { }, 0 + coffset = 0 + indices = { } + end + end + +end + +local pages = table.setmetatableindex(function(t,k) + local v = pdfreserveobj() + t[k] = v + return v +end) + +local function getpageref(n) + return pages[n] +end + +local function refobj() + -- not needed, as we have auto-delay +end + +local function flushnormalobj(data,n) + if not n then + nofobjects = nofobjects + 1 + n = nofobjects + end + data = f_object(n,data) + if level == 0 then + objects[n] = offset + offset = offset + #data + flush(f,data) + else + if not lastdeferred then + lastdeferred = n + elseif n < lastdeferred then + lastdeferred = n + end + objects[n] = data + end + return n +end + +local function flushstreamobj(data,n,dict,comp,nolength) + if not data then + print("no data for",dict) + return + end + if not n then + nofobjects = nofobjects + 1 + n = nofobjects + end + local size = #data + if level == 0 then + local b = nil + local e = s_stream_e + if nolength then + b = f_stream_b_d_r(n,dict) + elseif comp ~= false and compress and size > threshold then + local compdata = zlibcompress(data,3) + if compdata then + local compsize = #compdata + if compsize > size - threshold then + b = dict and f_stream_b_d_u(n,dict,size) or f_stream_b_n_u(n,size) + else + data = compdata + b = dict and f_stream_b_d_c(n,dict,compsize) or f_stream_b_n_c(n,compsize) + end + else + b = dict and f_stream_b_d_u(n,dict,size) or f_stream_b_n_u(n,size) + end + else + b = dict and f_stream_b_d_u(n,dict,size) or f_stream_b_n_u(n,size) + end + flush(f,b) + flush(f,data) + flush(f,e) + objects[n] = offset + offset = offset + #b + #data + #e + else + if nolength then + data = f_stream_d_r(n,dict,data) + elseif comp ~= false and compress and size > threshold then + local compdata = zlibcompress(data,3) + if compdata then + local compsize = #compdata + if compsize > size - threshold then + data = dict and f_stream_d_u(n,dict,size,data) or f_stream_n_u(n,size,data) + else + data = dict and f_stream_d_c(n,dict,compsize,compdata) or f_stream_n_c(n,compsize,compdata) + end + else + data = dict and f_stream_d_u(n,dict,size,data) or f_stream_n_u(n,size,data) + end + else + data = dict and f_stream_d_u(n,dict,size,data) or f_stream_n_u(n,size,data) + end + if not lastdeferred then + lastdeferred = n + elseif n < lastdeferred then + lastdeferred = n + end + objects[n] = data + end + return n +end + +local function flushdeferred() + if lastdeferred then + for n=lastdeferred,nofobjects do + local o = objects[n] + if type(o) == "string" then + objects[n] = offset + offset = offset + #o + flush(f,o) + end + end + lastdeferred = false + end +end + +-- These are already used above, so we define them now: + +pushmode = function() + level = level + 1 +end + +popmode = function() + if level == 1 then + flushdeferred() + end + level = level - 1 +end + +-- n = pdf.obj([n,] objtext) +-- n = pdf.obj([n,] "file", filename) +-- n = pdf.obj([n,] "stream", streamtext [, attrtext]) +-- n = pdf.obj([n,] "streamfile", filename [, attrtext]) +-- +-- n = pdf.obj { +-- type = <string>, -- raw|stream +-- immediate = <boolean>, +-- objnum = <number>, +-- attr = <string>, +-- compresslevel = <number>, +-- objcompression = <boolean>, +-- file = <string>, +-- string = <string>, +-- nolength = <boolean>, +-- } + +local function obj(a,b,c,d) + local kind --, immediate + local objnum, data, attr, filename + local compresslevel, objcompression, nolength + local argtype = type(a) + if argtype == "table" then + kind = a.type -- raw | stream + -- immediate = a.immediate + objnum = a.objnum + attr = a.attr + compresslevel = a.compresslevel + objcompression = a.objcompression + filename = a.file + data = a.string or a.stream or "" + nolength = a.nolength + if kind == "stream" then + if filename then + data = io.loaddata(filename) or "" + end + elseif kind == "raw"then + if filename then + data = io.loaddata(filename) or "" + end + elseif kind == "file"then + kind = "raw" + data = filename and io.loaddata(filename) or "" + elseif kind == "streamfile" then + kind = "stream" + data = filename and io.loaddata(filename) or "" + end + else + if argtype == "number" then + objnum = a + a, b, c = b, c, d + else + nofobjects = nofobjects + 1 + objnum = nofobjects + end + if b then + if a == "stream" then + kind = "stream" + data = b + elseif a == "file" then + -- kind = "raw" + data = io.loaddata(b) + elseif a == "streamfile" then + kind = "stream" + data = io.loaddata(b) + else + data = "" -- invalid object + end + attr = c + else + -- kind = "raw" + data = a + end + end + if not objnum then + nofobjects = nofobjects + 1 + objnum = nofobjects + end + -- todo: immediate + if kind == "stream" then + flushstreamobj(data,objnum,attr,compresslevel and compresslevel > 0 or nil,nolength) + elseif objectstream and objcompression ~= false then + addtocache(objnum,data) + else + flushnormalobj(data,objnum) + end + return objnum +end + +updaters.register("backend.update.pdf",function() + pdf.reserveobj = pdfreserveobj + pdf.getpageref = getpageref + pdf.refobj = refobj + pdf.flushstreamobj = flushstreamobj + pdf.flushnormalobj = flushnormalobj + pdf.obj = obj + pdf.immediateobj = obj +end) + +local openfile, closefile do + + local f_used = formatters["%010i 00000 n \010"] + local f_link = formatters["%010i 00000 f \010"] + local f_first = formatters["%010i 65535 f \010"] + local f_pdf = formatters["%%PDF-%i.%i\010"] + local f_xref = formatters["xref\0100 %i\010"] + local f_trailer_id = formatters["trailer\010<< %s /ID [ <%s> <%s> ] >>\010startxref\010%i\010%%%%EOF"] + local f_trailer_no = formatters["trailer\010<< %s >>\010startxref\010%i\010%%%%EOF"] + local f_startxref = formatters["startxref\010%i\010%%%%EOF"] + + local inmemory = false + -- local inmemory = environment.arguments.inmemory + local close = nil + + openfile = function(filename) + if inmemory then + f = { } + local n = 0 + flush = function(f,s) + n = n + 1 f[n] = s + end + close = function(f) + f = concat(f) + io.savedata(filename,f) + f = false + end + else + f = io.open(filename,"wb") + if not f then + -- message + os.exit() + end + flush = getmetatable(f).write + close = getmetatable(f).close + end + local v = f_pdf(majorversion,minorversion) + -- local b = "%\xCC\xD5\xC1\xD4\xC5\xD8\xD0\xC4\xC6\010" -- LUATEXPDF (+128) + local b = "%\xC3\xCF\xCE\xD4\xC5\xD8\xD4\xD0\xC4\xC6\010" -- CONTEXTPDF (+128) + flush(f,v) + flush(f,b) + offset = #v + #b + end + + closefile = function(abort) + if not abort then + local xrefoffset = offset + local lastfree = 0 + local noffree = 0 + local catalog = lpdf.getcatalog() + local info = lpdf.getinfo() + if trailerid == true then + trailerid = md5HEX(osuuid()) + elseif trailerid and #trailerid > 32 then + trailerid = md5HEX(trailerid) + else + trailerid = false + end + if objectstream then + flushdeferred() + flushcache() + -- + xrefoffset = offset + -- + nofobjects = nofobjects + 1 + objects[nofobjects] = offset -- + 1 + -- + -- combine these three in one doesn't really give less code so + -- we go for the efficient ones + -- + local nofbytes = 4 + local c1, c2, c3, c4 + if offset <= 0xFFFF then + nofbytes = 2 + for i=1,nofobjects do + local o = objects[i] + if not o then + noffree = noffree + 1 + else + local strm = o < 0 + if strm then + o = -o + end + c1 = extract(o,8,8) + c2 = extract(o,0,8) + if strm then + objects[i] = char(2,c1,c2,streams[o][i]) + else + objects[i] = char(1,c1,c2,0) + end + end + end + if noffree > 0 then + for i=nofobjects,1,-1 do + local o = objects[i] + if not o then + local f1 = extract(lastfree,8,8) + local f2 = extract(lastfree,0,8) + objects[i] = char(0,f1,f2,0) + lastfree = i + end + end + end + elseif offset <= 0xFFFFFF then + nofbytes = 3 + for i=1,nofobjects do + local o = objects[i] + if not o then + noffree = noffree + 1 + else + local strm = o < 0 + if strm then + o = -o + end + c1 = extract(o,16,8) + c2 = extract(o, 8,8) + c3 = extract(o, 0,8) + if strm then + objects[i] = char(2,c1,c2,c3,streams[o][i]) + else + objects[i] = char(1,c1,c2,c3,0) + end + end + end + if noffree > 0 then + for i=nofobjects,1,-1 do + local o = objects[i] + if not o then + local f1 = extract(lastfree,16,8) + local f2 = extract(lastfree, 8,8) + local f3 = extract(lastfree, 0,8) + objects[i] = char(0,f1,f2,f3,0) + lastfree = i + end + end + end + else + nofbytes = 4 + for i=1,nofobjects do + local o = objects[i] + if not o then + noffree = noffree + 1 + else + local strm = o < 0 + if strm then + o = -o + end + c1 = extract(o,24,8) + c2 = extract(o,16,8) + c3 = extract(o, 8,8) + c4 = extract(o, 0,8) + if strm then + objects[i] = char(2,c1,c2,c3,c4,streams[o][i]) + else + objects[i] = char(1,c1,c2,c3,c4,0) + end + end + end + if noffree > 0 then + for i=nofobjects,1,-1 do + local o = objects[i] + if not o then + local f1 = extract(lastfree,24,8) + local f2 = extract(lastfree,16,8) + local f3 = extract(lastfree, 8,8) + local f4 = extract(lastfree, 0,8) + objects[i] = char(0,f1,f2,f3,f4,0) + lastfree = i + end + end + end + end + objects[0] = rep("\0",1+nofbytes+1) + local data = concat(objects,"",0,nofobjects) + local xref = pdfdictionary { + Type = pdfconstant("XRef"), + Size = nofobjects + 1, + W = pdfarray { 1, nofbytes, 1 }, + Root = catalog, + Info = info, + ID = trailerid and pdfarray { pdfliteral(trailerid,true), pdfliteral(trailerid,true) } or nil, + } + if compress then + local comp = zlibcompress(data,3) + if comp then + data = comp + flush(f,f_stream_b_d_c(nofobjects,xref(),#data)) + else + flush(f,f_stream_b_d_u(nofobjects,xref(),#data)) + end + else + flush(f,f_stream_b_d_u(nofobjects,xref(),#data)) + end + flush(f,data) + flush(f,s_stream_e) + flush(f,f_startxref(xrefoffset)) + else + flushdeferred() + xrefoffset = offset + flush(f,f_xref(nofobjects+1)) + local trailer = pdfdictionary { + Size = nofobjects+1, + Root = catalog, + Info = info, + } + for i=1,nofobjects do + local o = objects[i] + if o then + objects[i] = f_used(o) + end + end + for i=nofobjects,1,-1 do + local o = objects[i] + if not o then + objects[i] = f_link(lastfree) + lastfree = i + end + end + objects[0] = f_first(lastfree) + flush(f,concat(objects,"",0,nofobjects)) + trailer.Size = nofobjects + 1 + if trailerid then + flush(f,f_trailer_id(trailer(),trailerid,trailerid,xrefoffset)) + else + flush(f,f_trailer_no(trailer(),xrefoffset)) + end + end + end + close(f) + io.flush() + end + +end + +-- For the moment we overload it here, although back-fil.lua eventually will +-- be merged with back-pdf as it's pdf specific, or maybe back-imp-pdf or so. + +updaters.register("backend.update.pdf",function() + + -- We overload img but at some point it will even go away, so we just + -- reimplement what we need in context. This will change completely i.e. + -- we will drop the low level interface! + + local imagetypes = images.types -- pdf png jpg jp2 jbig2 stream memstream + local img_none = imagetypes.none + + local rulecodes = nodes.rulecodes + local imagerule_code = rulecodes.image + + local setprop = nodes.nuts.setprop + + local report_images = logs.reporter("backend","images") + + local lastindex = 0 + local indices = { } + + local bpfactor = number.dimenfactors.bp + + local function new_img(specification) + return specification + end + + local function copy_img(original) + return setmetatableindex(original) + end + + local function scan_img(specification) + return specification + end + + local function embed_img(specification) + lastindex = lastindex + 1 + index = lastindex + specification.index = index + local xobject = pdfdictionary { } + if not specification.notype then + xobject.Type = pdfconstant("XObject") + xobject.Subtype = pdfconstant("Form") + xobject.FormType = 1 + end + local bbox = specification.bbox + if bbox and not specification.nobbox then + xobject.BBox = pdfarray { + bbox[1] * bpfactor, + bbox[2] * bpfactor, + bbox[3] * bpfactor, + bbox[4] * bpfactor, + } + end + xobject = xobject + specification.attr + if bbox and not specification.width then + specification.width = bbox[3] + end + if bbox and not specification.height then + specification.height = bbox[4] + end + local dict = xobject() + -- + nofobjects = nofobjects + 1 + local objnum = nofobjects + local nolength = specification.nolength + local stream = specification.stream or specification.string + -- + -- We cannot set type in native img so we need this hack or + -- otherwise we need to patch too much. Better that i write + -- a wrapper then. Anyway, it has to be done better: a key that + -- tells either or not to scale by xsize/ysize when flushing. + -- + if not specification.type then + local kind = specification.kind + if kind then + -- take that one + elseif attr and find(attr,"BBox") then + kind = img_stream + else + -- hack: a bitmap + kind = img_none + end + specification.type = kind + specification.kind = kind + end + local compress = compresslevel and compresslevel > 0 or nil + flushstreamobj(stream,objnum,dict,compress,nolength) + specification.objnum = objnum + specification.rotation = specification.rotation or 0 + specification.orientation = specification.orientation or 0 + specification.transform = specification.transform or 0 + specification.stream = nil + specification.attr = nil + specification.type = specification.kind or specification.type or img_none + indices[index] = specification -- better create a real specification + return specification + end + + local function wrap_img(specification) + -- + local index = specification.index + if not index then + embed_img(specification) + end + -- + local width = specification.width or 0 + local height = specification.height or 0 + local depth = specification.depth or 0 + -- newimagerule + local n = nodes.pool.rule(width,height,depth) + n.subtype = imagerule_code + setprop(tonut(n),"index",specification.index) + return n + end + + -- plugged into the old stuff + + local img = images.__img__ + img.new = new_img + img.copy = copy_img + img.scan = scan_img + img.embed = embed_img + img.wrap = wrap_img + + function pdf.includeimage(index) + local specification = indices[index] + if specification then + local bbox = specification.bbox + local xorigin = bbox[1] + local yorigin = bbox[2] + local xsize = specification.width -- should equal to: bbox[3] - xorigin + local ysize = specification.height -- should equal to: bbox[4] - yorigin + local transform = specification.transform or 0 + local objnum = specification.objnum or pdfreserveobj() + local groupref = nil + local kind = specification.kind or specification.type or img_none -- determines scaling type + return + kind, + xorigin, yorigin, + xsize, ysize, + transform, + objnum, + groupref + end + end + +end) + +updaters.register("backend.update.lpdf",function() + + -- for the moment here, todo: an md5 or sha2 hash can save space + + local pdfimage = lpdf.epdf.image + local newpdf = pdfimage.new + local closepdf = pdfimage.close + local copypage = pdfimage.copy + + local embedimage = images.embed + + local nofstreams = 0 + local topdf = { } + local toidx = { } + + local function storedata(pdf) + local idx = toidx[pdf] + if not idx then + nofstreams = nofstreams + 1 + idx = nofstreams + toidx[pdf] = nofstreams + topdf[idx] = pdf + end + return idx + end + + -- todo: make a type 3 font instead + + -- move to lpdf namespace + + local function vfimage(id,wd,ht,dp,pos_h,pos_v) + local index = topdf[id] + if type(index) == "string" then + local pdfdoc = newpdf(index,#index) + local image = copypage(pdfdoc) + local bbox = image.bbox + image.width = bbox[3] - bbox[1] + image.height = bbox[4] - bbox[2] + embedimage(image) + index = image.index + topdf[id] = index + end + -- pdf.print or pdf.literal + pdf.flushpdfimage(index,wd,ht,dp,pos_h,pos_v) + end + + local function pdfvfimage(wd,ht,dp,data,name) + return { "lua", function(font,char,pos_h,pos_v) + local id = storedata(data) + vfimage(id,wd,ht,dp,pos_h,pos_v) + end } + end + + lpdf.vfimage = pdfvfimage + +end) + +-- The driver. + +do + + local isfile = lfs.isfile + local removefile = os.remove + local renamefile = os.rename +-- local addsuffix = file.addsuffix + + local pdfname = nil + local tmpname = nil + + local function outputfilename() + return pdfname + end + + local function prepare() + if not environment.initex then + -- install new functions in pdf namespace + updaters.apply("backend.update.pdf") + -- install new functions in lpdf namespace + updaters.apply("backend.update.lpdf") + -- adapt existing shortcuts to lpdf namespace + updaters.apply("backend.update.tex") + -- adapt existing shortcuts to tex namespace + updaters.apply("backend.update") + -- + updaters.apply("backend.update.img") + -- + directives.enable("graphics.uselua") + -- + -- if rawget(pdf,"setforcefile") then + -- pdf.setforcefile(false) -- default anyway + -- end + -- + pdfname = file.addsuffix(tex.jobname,"pdf") + tmpname = "l_m_t_x_" .. pdfname + removefile(tmpname) + if isfile(tmpname) then + report("file %a can't be opened, aborting",tmpname) + os.exit() + end + openfile(tmpname) + -- + luatex.registerstopactions(1,function() + lpdf.finalizedocument() + closefile() + end) + -- + luatex.registerpageactions(1,function() + lpdf.finalizepage(true) + end) + -- + fonts.constructors.autocleanup = false + -- + lpdf.registerdocumentfinalizer(wrapup,nil,"wrapping up") + end + -- + environment.lmtxmode = CONTEXTLMTXMODE + end + + local function wrapup() + if pdfname then + local ok = true + if isfile(pdfname) then + removefile(pdfname) + end + if isfile(pdfname) then + ok = false + else + renamefile(tmpname,pdfname) + if isfile(tmpname) then + ok = false + end + end + if not ok then + print(formatters["\nerror in renaming %a to %a\n"](tmpname,pdfname)) + end + pdfname = nil + tmpname = nil + end + end + + local function cleanup() + if tmpname then + closefile(true) + if isfile(tmpname) then + removefile(tmpname) + end + pdfname = nil + tmpname = nil + end + end + + local function convert(boxnumber) + lpdf.convert(tex.box[boxnumber],"page") + end + + drivers.install { + name = "pdf", + actions = { + prepare = prepare, + wrapup = wrapup, + convert = convert, + cleanup = cleanup, + -- + initialize = initialize, + finalize = finalize, + updatefontstate = updatefontstate, + outputfilename = outputfilename, + }, + flushers = { + character = flushcharacter, + rule = flushrule, + simplerule = flushsimplerule, + pushorientation = pushorientation, + poporientation = poporientation, + -- + pdfliteral = flushpdfliteral, + pdfsetmatrix = flushpdfsetmatrix, + pdfsave = flushpdfsave, + pdfrestore = flushpdfrestore, + pdfimage = flushpdfimage, + }, + } + +end diff --git a/tex/context/base/mkiv/back-lua.lua b/tex/context/base/mkiv/back-lua.lua new file mode 100644 index 000000000..257fda0a2 --- /dev/null +++ b/tex/context/base/mkiv/back-lua.lua @@ -0,0 +1,52 @@ +if not modules then modules = { } end modules ['back-lua'] = { + version = 1.001, + comment = "companion to lpdf-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local buffer = { } +local b = 0 + +local function reset() + buffer = { } + b = 0 +end + +local function initialize(specification) + reset() +end + +local function finalize() +end + +local function fetch() + local saved = buffer + reset() + return saved +end + +local function flushcharacter(current, pos_h, pos_v, pod_r, font, char) + b = b + 1 ; buffer[b] = { "glyph", font, char, pos_h, pos_v, pos_r } +end + +local function flushrule(current, pos_h, pos_v, pos_r, size_h, size_v) + b = b + 1 ; buffer[b] = { "rule", size_h, size_v, pos_h, pos_v, pos_r } +end + +-- file stuff too + +drivers.install { + name = "lua", + actions = { + initialize = initialize, + finalize = finalize, + fetch = fetch, + reset = reset, + }, + flushers = { + character = flushcharacter, + rule = flushrule, + } +} diff --git a/tex/context/base/mkiv/back-mps.lua b/tex/context/base/mkiv/back-mps.lua new file mode 100644 index 000000000..380fb7a35 --- /dev/null +++ b/tex/context/base/mkiv/back-mps.lua @@ -0,0 +1,94 @@ +if not modules then modules = { } end modules ['back-mps'] = { + version = 1.001, + comment = "companion to lpdf-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- The basics are the same as the lua variant. + +local formatters = string.formatters +local bpfactor = number.dimenfactors.bp + +local buffer = { } +local b = 0 + +local function reset() + buffer = { } + b = 0 +end + +local function initialize(specification) + reset() +end + +local function finalize() +end + +local function fetch() + local saved = buffer + reset() + return saved +end + +local function flushcharacter(current, pos_h, pos_v, pod_r, font, char) + b = b + 1 ; buffer[b] = { "glyph", font, char, pos_h, pos_v, pos_r } +end + +local function flushrule(current, pos_h, pos_v, pod_r, size_h, size_v) + b = b + 1 ; buffer[b] = { "rule", size_h, size_v, pos_h, pos_v, pos_r } +end + +drivers.install { + name = "mps", + actions = { + initialize = initialize, + finalize = finalize, + fetch = fetch, + reset = reset, + }, + flushers = { + character = flushcharacter, + rule = flushrule, + } +} + +if not mp then + return +end + +local mpprint = mp.print + +local f_glyph = formatters[ [[draw textext.drt("\setfontid%i\relax\char%i\relax") shifted (%N,%N);]] ] +local f_rule = formatters[ [[fill unitsquare xscaled %N yscaled %N shifted (%N,%N);]] ] + +local current = nil +local size = 0 + +function mp.place_buffermake(box) + drivers.convert("mps",box) + current = drivers.action("mps","fetch") + size = #current +end + +function mp.place_buffersize() + mpprint(size) +end + +function mp.place_bufferslot(i) + if i > 0 and i <= size then + local b = buffer[i] + local t = b[1] + if t == "glyph" then + mpprint(f_glyph(b[2],b[3],b[4]*bpfactor,b[5]*bpfactor)) + elseif t == "rule" then + mpprint(f_rule(b[2]*bpfactor,b[3]*bpfactor,b[4]*bpfactor,b[5]*bpfactor)) + end + end +end + +function mp.place_bufferwipe() + current = nil + size = 0 +end diff --git a/tex/context/base/mkiv/back-out.lua b/tex/context/base/mkiv/back-out.lua new file mode 100644 index 000000000..a0e05afca --- /dev/null +++ b/tex/context/base/mkiv/back-out.lua @@ -0,0 +1,291 @@ +if not modules then modules = { } end modules ['back-out'] = { + version = 1.001, + comment = "companion to lpdf-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +if CONTEXTLMTXMODE == 0 then + + return + +elseif CONTEXTLMTXMODE == 1 then + + local type = type + local getdata = nodes.nuts.getdata + local loadstring = loadstring + + function backends.latelua(current,pos_h,pos_v,cur_h,cur_v) + data = getdata(current) + local kind = type(data) + if kind == "function" then + data() + elseif kind == "table" then + data.action(data) + else + -- if kind ~= "string" then + -- data = tokentostring(data) + -- end + if #data ~= "" then + local code = loadstring(data) + if code then + code() + end + end + end + end + + return +end + +local type = type +local loadstring = loadstring + +local context = context + +-- tokens.scanners..... + +local get = token.get_index +local scaninteger = token.scan_int +local scanstring = token.scan_string +local scankeyword = token.scan_keyword +local scantokenlist = token.scan_tokenlist +local scancode = token.scan_code + +local tokentostring = token.to_string + +local logwriter = logs.writer +local openfile = io.open + +local nuts = nodes.nuts +local tonode = nuts.tonode +local copynode = nuts.copy +local nodepool = nuts.pool + +local getdata = nuts.getdata + +local whatsit_code = nodes.nodecodes.whatsit + +local whatsitcodes = nodes.whatsitcodes + +local literalvalues = nodes.literalvalues +local originliteral_code = literalvalues.origin +local pageliteral_code = literalvalues.page +local directliteral_code = literalvalues.direct +local rawliteral_code = literalvalues.raw + +local nodeproperties = nodes.properties.data + +local channels = { } + +local register = nodepool.register +local newnut = nuts.new + +local opennode = register(newnut(whatsit_code,whatsitcodes.open)) +local writenode = register(newnut(whatsit_code,whatsitcodes.write)) +local closenode = register(newnut(whatsit_code,whatsitcodes.close)) +local lateluanode = register(newnut(whatsit_code,whatsitcodes.latelua)) +local literalnode = register(newnut(whatsit_code,whatsitcodes.literal)) +local savenode = register(newnut(whatsit_code,whatsitcodes.save)) +local restorenode = register(newnut(whatsit_code,whatsitcodes.restore)) +local setmatrixnode = register(newnut(whatsit_code,whatsitcodes.setmatrix)) + +local tomatrix = drivers.helpers.tomatrix + +local open_command, write_command, close_command + +backends = backends or { } + +local function openout(immediate) + local channel = scaninteger() + scankeyword("=") -- hack + local filename = scanstring() + if not immediate then + local n = copynode(opennode) + nodeproperties[n] = { channel = channel, filename = filename } -- action = "open" + return context(tonode(n)) + elseif not channels[channel] then + local handle = openfile(filename,"wb") or false + if handle then + channels[channel] = handle + else + -- error + end + end +end + +function backends.openout(n) + local p = nodeproperties[n] + if p then + local handle = openfile(p.filename,"wb") or false + if handle then + channels[p.channel] = handle + else + -- error + end + end +end + +local function write(immediate) + local channel = scaninteger() + if not immediate then + local t = scantokenlist() + local n = copynode(writenode) + nodeproperties[n] = { channel = channel, data = t } -- action = "write" + return context(tonode(n)) + else + local content = scanstring() + local handle = channels[channel] + if handle then + handle:write(content,"\n") + else + logwriter(content,"\n") + end + end +end + +function backends.writeout(n) + local p = nodeproperties[n] + if p then + local handle = channels[p.channel] + local content = tokentostring(p.data) + if handle then + handle:write(content,"\n") + else + logwriter(content,"\n") + end + end +end + +local function closeout(immediate) + local channel = scaninteger() + if not immediate then + local n = copynode(closenode) + nodeproperties[n] = { channel = channel } -- action = "close" + return context(tonode(n)) + else + local handle = channels[channel] + if handle then + handle:close() + channels[channel] = false + else + -- error + end + end +end + +function backends.closeout(n) + local p = nodeproperties[n] + if p then + local channel = p.channel + local handle = channels[channel] + if handle then + handle:close() + channels[channel] = false + else + -- error + end + end +end + +local function immediate() + local command = scancode() + if command == write_command then + write(true) + elseif command == open_command then + openout(true) + elseif command == close_command then + closeout(true) + end +end + +local noflatelua = 0 + +local function latelua() + local node = copynode(lateluanode) + local name = "latelua" + if scankeyword("name") then + name = scanstring() + end + local data = scantokenlist() + nodeproperties[node] = { name = name, data = data } + return context(tonode(node)) +end + +function backends.latelua(current,pos_h,pos_v,cur_h,cur_v) + local p = nodeproperties[current] + if p then + data = p.data + else + data = getdata(current) + end + noflatelua = noflatelua + 1 + local kind = type(data) + if kind == "table" then + data.action(data.specification or data) + elseif kind == "function" then + data() + else + if kind ~= "string" then + data = tokentostring(data) + end + if #data ~= "" then + local code = loadstring(data) + if code then + code() + end + end + end +end + +function backends.noflatelua() + return noflatelua +end + +function nodepool.originliteral(str) local t = copynode(literalnode) nodeproperties[t] = { data = str, mode = originliteral_code } return t end +function nodepool.pageliteral (str) local t = copynode(literalnode) nodeproperties[t] = { data = str, mode = pageliteral_code } return t end +function nodepool.directliteral(str) local t = copynode(literalnode) nodeproperties[t] = { data = str, mode = directliteral_code } return t end +function nodepool.rawliteral (str) local t = copynode(literalnode) nodeproperties[t] = { data = str, mode = rawliteral_code } return t end + +local pdfliterals = { + [originliteral_code] = originliteral_code, [literalvalues[originliteral_code]] = originliteral_code, + [pageliteral_code] = pageliteral_code, [literalvalues[pageliteral_code]] = pageliteral_code, + [directliteral_code] = directliteral_code, [literalvalues[directliteral_code]] = directliteral_code, + [rawliteral_code] = rawliteral_code, [literalvalues[rawliteral_code]] = rawliteral_code, +} + +function nodepool.literal(mode,str) + local t = copynode(literalnode) + if str then + nodeproperties[t] = { data = str, mode = pdfliterals[mode] or pageliteral_code } + else + nodeproperties[t] = { data = mode, mode = pageliteral_code } + end + return t +end + +function nodepool.save() + return copynode(savenode) +end + +function nodepool.restore() + return copynode(restorenode) +end + +function nodepool.setmatrix(rx,sx,sy,ry,tx,ty) + local t = copynode(setmatrixnode) + nodeproperties[t] = { matrix = tomatrix(rx,sx,sy,ry,tx,ty) } + return t +end + +interfaces.implement { name = "immediate", actions = immediate, public = true, protected = true } +interfaces.implement { name = "openout", actions = openout, public = true, protected = true } +interfaces.implement { name = "write", actions = write, public = true, protected = true } +interfaces.implement { name = "closeout", actions = closeout, public = true, protected = true } +interfaces.implement { name = "latelua", actions = latelua, public = true, protected = true } +interfaces.implement { name = "special", actions = scanstring, public = true, protected = true } + +open_command = get(token.create("openout")) +write_command = get(token.create("write")) +close_command = get(token.create("closeout")) diff --git a/tex/context/base/mkiv/back-out.mkiv b/tex/context/base/mkiv/back-out.mkiv new file mode 100644 index 000000000..26548a0a4 --- /dev/null +++ b/tex/context/base/mkiv/back-out.mkiv @@ -0,0 +1,23 @@ +%D \module +%D [ file=back-out, +%D version=2019.02.08, +%D title=\CONTEXT\ Backend Macros, +%D subtitle=Output, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\registerctxluafile{back-out}{} + +\let\normalimmediate\immediate +\let\normalopenout \openout +\let\normalwrite \write +\let\normalcloseout \closeout +\let\normallatelua \latelua +\let\normalspecial \special + +\endinput diff --git a/tex/context/base/mkiv/back-pdf.lua b/tex/context/base/mkiv/back-pdf.lua index cc8d31597..8886967e0 100644 --- a/tex/context/base/mkiv/back-pdf.lua +++ b/tex/context/base/mkiv/back-pdf.lua @@ -6,10 +6,21 @@ if not modules then modules = { } end modules ['back-pdf'] = { license = "see context related readme files" } +-- We hide the pdf table from users so that we can guarantee no interference with +-- the way we manage resources, info, etc. Users should use the \type {lpdf} +-- interface instead. If needed I will provide replacement functionality. + interfaces.implement { name = "setpdfcompression", arguments = { "integer", "integer" }, actions = lpdf.setcompression, } +if CONTEXTLMTXMODE == 0 then + updaters.apply("backend.update.pdf") + updaters.apply("backend.update.lpdf") + updaters.apply("backend.update.tex") + updaters.apply("backend.update") +end + backends.install("pdf") diff --git a/tex/context/base/mkiv/buff-ini.lua b/tex/context/base/mkiv/buff-ini.lua index 632565fc7..ecb5d9dd0 100644 --- a/tex/context/base/mkiv/buff-ini.lua +++ b/tex/context/base/mkiv/buff-ini.lua @@ -167,7 +167,8 @@ local function collectcontent(name,separator) -- no print elseif nnames == 1 then return getcontent(names[1]) else - local t, n = { }, 0 + local t = { } + local n = 0 for i=1,nnames do local c = getcontent(names[i]) if c ~= "" then @@ -350,11 +351,17 @@ buffers.undent = undent -- commands.doifelse(more) -- end +local split = table.setmetatableindex(function(t,k) + local v = totable(k) + t[k] = v + return v +end) + function tokens.pickup(start,stop) - local stoplist = totable(stop) + local stoplist = split[stop] -- totable(stop) local stoplength = #stoplist local stoplast = stoplist[stoplength] - local startlist = totable(start) + local startlist = split[start] -- totable(start) local startlength = #startlist local startlast = startlist[startlength] local list = { } diff --git a/tex/context/base/mkiv/buff-ver.lua b/tex/context/base/mkiv/buff-ver.lua index bfc9ef89c..969a28055 100644 --- a/tex/context/base/mkiv/buff-ver.lua +++ b/tex/context/base/mkiv/buff-ver.lua @@ -142,7 +142,8 @@ local functions = { __index = { local handlers = { } function visualizers.newhandler(name,data) - local tname, tdata = type(name), type(data) + local tname = type(name) + local tdata = type(data) if tname == "table" then -- (data) setmetatable(name,getmetatable(name) or functions) return name @@ -615,7 +616,12 @@ end local onlyspaces = S(" \t\f\n\r")^0 * P(-1) local function getstrip(lines,first,last) - local first, last = first or 1, last or #lines + if not first then + first = 1 + end + if not last then + last = #lines + end for i=first,last do local li = lines[i] if #li == 0 or lpegmatch(onlyspaces,li) then @@ -741,9 +747,10 @@ local function filter(lines,settings) -- todo: inline or display in settings if strip ~= v_no and strip ~= false then lines = realign(lines,strip) end - local line, n = 0, 0 - local first, last, m = getstrip(lines) + local line = 0 + local n = 0 local range = settings.range + local first, last, m = getstrip(lines) if range then first, last = getrange(lines,first,last,range) first, last = getstrip(lines,first,last) @@ -810,7 +817,7 @@ local function typestring(settings) local compact = settings.compact local compactor = compact and compactors[compact] if compactor then - content = lpegmatch(compactor,content) + content = lpegmatch(compactor,content) or content end -- content = decodecomment(content) -- content = dotabs(content,settings) @@ -846,7 +853,7 @@ implement { actions = typestring, arguments = { { - { "data" }, + { "data" }, { "tab" }, { "method" }, { "compact" }, @@ -856,6 +863,50 @@ implement { } } +-- implement { +-- name = "type_x", +-- actions = typestring, +-- arguments = { +-- { +-- { "data", "verbatim" }, +-- { "tab" }, +-- { "method" }, +-- { "compact" }, +-- { "nature" }, +-- { "escape" }, +-- } +-- } +-- } + +-- local function typestring_y(settings) +-- local content = tex.toks[settings.n] +-- if content and content ~= "" then +-- local compact = settings.compact +-- local compactor = compact and compactors[compact] +-- if compactor then +-- content = lpegmatch(compactor,content) +-- end +-- -- content = decodecomment(content) +-- -- content = dotabs(content,settings) +-- visualize(content,checkedsettings(settings,"inline")) +-- end +-- end + +-- implement { +-- name = "type_y", +-- actions = typestring_y, +-- arguments = { +-- { +-- { "n", "integer" }, +-- { "tab" }, +-- { "method" }, +-- { "compact" }, +-- { "nature" }, +-- { "escape" }, +-- } +-- } +-- } + implement { name = "processbuffer", actions = processbuffer, diff --git a/tex/context/base/mkiv/char-ini.lua b/tex/context/base/mkiv/char-ini.lua index 62e509151..fb9d9f126 100644 --- a/tex/context/base/mkiv/char-ini.lua +++ b/tex/context/base/mkiv/char-ini.lua @@ -617,7 +617,8 @@ characters.otfscripts = otfscripts setmetatableindex(otfscripts,function(t,unicode) for k, v in next, blocks do - local first, last = v.first, v.last + local first = v.first + local last = v.last if unicode >= first and unicode <= last then local script = v.otf or "dflt" for u=first,last do @@ -1057,7 +1058,8 @@ setmetatableindex(specialchars, function(t,u) local c = data[u] local s = c and c.specials if s then - local tt, ttn = { }, 0 + local tt = { } + local ttn = 0 for i=2,#s do local si = s[i] local c = data[si] diff --git a/tex/context/base/mkiv/char-ini.mkiv b/tex/context/base/mkiv/char-ini.mkiv index 0519aaf91..5979b8685 100644 --- a/tex/context/base/mkiv/char-ini.mkiv +++ b/tex/context/base/mkiv/char-ini.mkiv @@ -57,14 +57,34 @@ \unexpanded\def\checkedtextchar#1% #2% {\clf_doifelsecharinfont\numexpr#1\relax{\char#1}} % {#2} +% \unexpanded\def\textormathchar#1% +% {\relax\ifmmode +% \char#1\relax +% \else\iffontchar\font#1\relax +% \char#1\relax +% \else +% \normalstartimath\char#1\normalstopimath +% \fi\fi} + +\newconditional\prefermathovertextchar + \unexpanded\def\textormathchar#1% - {\relax\ifmmode - \char#1\relax - \else\iffontchar\font#1\relax - \char#1\relax + {\begingroup + \scratchcounter#1\relax + \ifmmode + \char\scratchcounter \else - \normalstartimath\char#1\normalstopimath - \fi\fi} + \ifconditional\prefermathovertextchar + % dirty trick .. maybe let this adapt to bf too ? + \setfontid\fontid\textfont\c_font_fam_mr + \fi + \iffontchar\font\scratchcounter + \char\scratchcounter + \else + \normalstartimath\char\scratchcounter\normalstopimath + \fi + \fi + \endgroup} \unexpanded\def\textormathchars#1% {{\font_text_or_mathchars#1\relax}} diff --git a/tex/context/base/mkiv/char-tex.lua b/tex/context/base/mkiv/char-tex.lua index 66997a647..bbaf11875 100644 --- a/tex/context/base/mkiv/char-tex.lua +++ b/tex/context/base/mkiv/char-tex.lua @@ -600,14 +600,17 @@ if not csletters then end -- if isletter then - local lc, uc = chr.lccode, chr.uccode + local lc = chr.lccode + local uc = chr.uccode if not lc then - chr.lccode, lc = u, u + chr.lccode = u + lc = u elseif type(lc) == "table" then lc = u end if not uc then - chr.uccode, uc = u, u + chr.uccode = u + uc = u elseif type(uc) == "table" then uc = u end @@ -631,12 +634,14 @@ if not csletters then -- local lc, uc = chr.lccode, chr.uccode if not lc then - chr.lccode, lc = u, u + chr.lccode = u + lc = u elseif type(lc) == "table" then lc = u end if not uc then - chr.uccode, uc = u, u + chr.uccode = u + uc = u elseif type(uc) == "table" then uc = u end diff --git a/tex/context/base/mkiv/char-utf.lua b/tex/context/base/mkiv/char-utf.lua index 4dc7eba7a..110a4a48c 100644 --- a/tex/context/base/mkiv/char-utf.lua +++ b/tex/context/base/mkiv/char-utf.lua @@ -107,8 +107,10 @@ else local function backtrack(v,last,target) local vs = v.specials if vs and #vs == 3 and vs[1] == "char" then - local one, two = vs[2], vs[3] - local first, second = utfchar(one), utfchar(two) .. last + local one = vs[2] + local two = vs[3] + local first = utfchar(one) + local second = utfchar(two) .. last collapsed[first..second] = target backtrack(data[one],second,target) end @@ -141,8 +143,11 @@ else local size = #vs if kind == "char" and size == 3 then -- what if more than 3 -- - local one, two = vs[2], vs[3] - local first, second, combination = utfchar(one), utfchar(two), utfchar(unicode) + local one = vs[2] + local two = vs[3] + local first = utfchar(one) + local second = utfchar(two) + local combination = utfchar(unicode) -- collapsed[first..second] = combination backtrack(data[one],second,combination) diff --git a/tex/context/base/mkiv/cldf-bas.lua b/tex/context/base/mkiv/cldf-bas.lua index 4088348f6..f55132a06 100644 --- a/tex/context/base/mkiv/cldf-bas.lua +++ b/tex/context/base/mkiv/cldf-bas.lua @@ -195,10 +195,28 @@ context.registers = { do - function context.latelua(f) - local latelua = new_latelua(f) - setattrlist(latelua,true) - ctx_flushnode(latelua,true) + if CONTEXTLMTXMODE > 1 then + + function context.latelua(f) + -- table check moved elsewhere + local latelua = new_latelua(f) + setattrlist(latelua,true) -- will become an option + ctx_flushnode(latelua,true) + end + + else + + function context.latelua(f) + if type(f) == "table" then + local action = f.action + local specification = f.specification or f + f = function() action(specification) end + end + local latelua = new_latelua(f) + setattrlist(latelua,true) -- will become an option + ctx_flushnode(latelua,true) + end + end end diff --git a/tex/context/base/mkiv/cldf-ini.lua b/tex/context/base/mkiv/cldf-ini.lua index 489ed1158..463ece151 100644 --- a/tex/context/base/mkiv/cldf-ini.lua +++ b/tex/context/base/mkiv/cldf-ini.lua @@ -137,7 +137,7 @@ function context.trialtypesetting() return texgetcount(trialtypesettingstate) ~= 0 end -local knownfunctions = lua.get_functions_table() +local knownfunctions = (lua.getfunctionstable or lua.get_functions_table)(true) local showstackusage = false trackers.register("context.stack",function(v) showstackusage = v end) @@ -793,7 +793,7 @@ local function writer(parent,command,...) -- already optimized before call tj = storefunction(tj) if tokenflushmode then if newtoken then - flush(currentcatcodes,"[",newtoken(tj,lua_expandable_call_code),"]") + flush(currentcatcodes,"[",newtoken(tj,lua_expandable_call_token_code),"]") else flush(currentcatcodes,"[",t_cldl_luafunction,tj,"]") end @@ -811,7 +811,7 @@ local function writer(parent,command,...) -- already optimized before call tj = storefunction(tj) if tokenflushmode then if newtoken then - flush(currentcatcodes,"[",newtoken(tj,lua_expandable_call_code),j == tn and "]" or ",") + flush(currentcatcodes,"[",newtoken(tj,lua_expandable_call_token_code),j == tn and "]" or ",") else flush(currentcatcodes,"[",t_cldl_luafunction,tj,j == tn and "]" or ",") end @@ -1218,7 +1218,8 @@ local tracedwriter = function(parent,...) -- also catcodes ? nofwriters = nofwriters + 1 local savedflush = flush local savedflushdirect = flushdirect -- unlikely to be used here - local t, n = { "w : - : " }, 1 + local t = { "w : - : " } + local n = 1 local traced = function(catcodes,...) -- todo: check for catcodes local s = type(catcodes) == "number" and { ... } or { catcodes, ... } for i=1,#s do @@ -1262,9 +1263,10 @@ end local traced = function(one,two,...) if two ~= nil then -- only catcodes if 'one' is number - local catcodes = type(one) == "number" and one + local catcodes = type(one) == "number" and one local arguments = catcodes and { two, ... } or { one, two, ... } - local collapsed, c = { formatters["f : %s : "](catcodes or '-') }, 1 + local collapsed = { formatters["f : %s : "](catcodes or '-') } + local c = 1 for i=1,#arguments do local argument = arguments[i] local argtype = type(argument) diff --git a/tex/context/base/mkiv/cldf-int.lua b/tex/context/base/mkiv/cldf-int.lua index a97eadf35..52cfea8d0 100644 --- a/tex/context/base/mkiv/cldf-int.lua +++ b/tex/context/base/mkiv/cldf-int.lua @@ -88,9 +88,10 @@ function interfaces.definecommand(name,specification) -- name is optional else -- we could flush immediate but tracing is bad then stack[name] = { } - local opt, done = 0, false + local opt = 0 + local done = false local snippets = { } -- we can reuse it - local mkivdo = "\\mkivdo" .. name -- maybe clddo + local mkivdo = "\\mkivdo" .. name -- maybe clddo snippets[#snippets+1] = "\\def" snippets[#snippets+1] = mkivdo for i=1,na do diff --git a/tex/context/base/mkiv/colo-ini.lua b/tex/context/base/mkiv/colo-ini.lua index d24939896..3c8d23abc 100644 --- a/tex/context/base/mkiv/colo-ini.lua +++ b/tex/context/base/mkiv/colo-ini.lua @@ -312,7 +312,8 @@ local function definetransparency(name,n,global) end local settings = settings_to_hash_strict(n) if settings then - local a, t = settings.a, settings.t + local a = settings.a + local t = settings.t if a and t then definetransparent(name, transparencies.register(name,transparent[a] or tonumber(a) or 1,tonumber(t) or 1), global) else @@ -443,16 +444,23 @@ local function defineprocesscolor(name,str,global,freeze) -- still inconsistent else local settings = settings_to_hash_strict(str) if settings then - local r, g, b = settings.r, settings.g, settings.b + local r = settings.r + local g = settings.g + local b = settings.b if r or g or b then -- we can consider a combined rgb cmyk s definition definecolor(name, register_color(name,'rgb', tonumber(r) or 0, tonumber(g) or 0, tonumber(b) or 0), global) else - local c, m, y, k = settings.c, settings.m, settings.y, settings.k + local c = settings.c + local m = settings.m + local y = settings.y + local k = settings.k if c or m or y or k then definecolor(name, register_color(name,'cmyk',tonumber(c) or 0, tonumber(m) or 0, tonumber(y) or 0, tonumber(k) or 0), global) else - local h, s, v = settings.h, settings.s, settings.v + local h = settings.h + local s = settings.s + local v = settings.v if v then r, g, b = colors.hsvtorgb(tonumber(h) or 0, tonumber(s) or 1, tonumber(v) or 1) -- maybe later native definecolor(name, register_color(name,'rgb',r,g,b), global) @@ -471,7 +479,8 @@ local function defineprocesscolor(name,str,global,freeze) -- still inconsistent end end end - local a, t = settings.a, settings.t + local a = settings.a + local t = settings.t if a and t then definetransparent(name, transparencies.register(name,transparent[a] or tonumber(a) or 1,tonumber(t) or 1), global) elseif colors.couple then @@ -523,7 +532,8 @@ local function definespotcolor(name,parent,str,global) do_registerspotcolor(parent,cp,t.e,1,"",tp) -- p not really needed, only diagnostics if name and name ~= "" then definecolor(name,register_color(name,'spot',parent,1,"",tp),true) - local ta, tt = t.a, t.t + local ta = t.a + local tt = t.t if ta and tt then definetransparent(name, transparencies.register(name,transparent[ta] or tonumber(ta) or 1,tonumber(tt) or 1), global) elseif colors.couple then @@ -600,7 +610,10 @@ local function definemixcolor(makecolor,name,fractions,cs,global,freeze) end local function definemultitonecolor(name,multispec,colorspec,selfspec) - local dd, pp, nn, max = { }, { }, { }, 0 + local dd = { } + local pp = { } + local nn = { } + local max = 0 for k,v in gmatch(multispec,"([^=,]+)=([^%,]*)") do -- use settings_to_array max = max + 1 dd[max] = k diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv index f9d8a6b2c..a94cb5d08 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{2019.02.14 16:57} +\newcontextversion{2019.04.04 13:31} %D This file is loaded at runtime, thereby providing an excellent place for %D hacks, patches, extensions and new features. @@ -32,12 +32,6 @@ % \let\assumelongusagecs\relax % todo: fails on legends-001.tex -% experimental - -\ifdefined\enablelmtx\else - \let\enablelmtx\relax -\fi - % done \protect \endinput diff --git a/tex/context/base/mkiv/cont-run.mkiv b/tex/context/base/mkiv/cont-run.mkiv index 3d6103148..f841ce530 100644 --- a/tex/context/base/mkiv/cont-run.mkiv +++ b/tex/context/base/mkiv/cont-run.mkiv @@ -22,10 +22,6 @@ \unprotect -\ifdefined\enablelmtx\else - \let\enablelmtx\relax -\fi - \let\synctexsetfilename \clf_synctexsetfilename \let\synctexresetfilename\clf_synctexresetfilename \let\synctexblockfilename\clf_synctexblockfilename diff --git a/tex/context/base/mkiv/context.mkiv b/tex/context/base/mkiv/context.mkiv index f8ab3d7a6..98d964b24 100644 --- a/tex/context/base/mkiv/context.mkiv +++ b/tex/context/base/mkiv/context.mkiv @@ -42,12 +42,12 @@ %D has to match \type {YYYY.MM.DD HH:MM} format. \edef\contextformat {\jobname} -\edef\contextversion{2019.02.14 16:57} +\edef\contextversion{2019.04.04 13:31} \edef\contextkind {beta} %D Kind of special: -\chardef\contextlmtxmode\directlua{tex.print(CONTEXTLMTXMODE and 1 or 0)}\relax +\chardef\contextlmtxmode\directlua{tex.print(CONTEXTLMTXMODE or 0)}\relax %D For those who want to use this: @@ -66,8 +66,6 @@ \def\loadmkiifile#1{} \def\loadmkivfile#1{\normalinput#1.mkiv\relax} \def\loadmkvifile#1{\normalinput#1.mkvi\relax} -\def\loadlmtxfile#1{\ifcase\contextlmtxmode\else\normalinput#1.mkiv\relax\fi} - %D First we load the system modules. These implement a lot of %D manipulation macros. We start with setting up some basic \TEX\ @@ -137,7 +135,7 @@ \loadmkvifile{file-res} \loadmkvifile{file-lib} -\loadlmtxfile{core-lmt} +\loadmarkfile{core-lmt} % needs more checking for clashes: % @@ -600,7 +598,7 @@ \loadmarkfile{cont-run} % the main runner (used in cont-yes.mkiv) -\loadlmtxfile{driv-shp} +\loadmarkfile{driv-shp} \setupcurrentlanguage[\defaultlanguagetag] diff --git a/tex/context/base/mkiv/core-dat.lua b/tex/context/base/mkiv/core-dat.lua index dbb14c36e..b49750159 100644 --- a/tex/context/base/mkiv/core-dat.lua +++ b/tex/context/base/mkiv/core-dat.lua @@ -108,6 +108,9 @@ end datasets.setdata = setdata function datasets.extend(name,tag) + if type(name) == "table" then + name, tag = name.name, name.tag + end local set = sets[name] local order = set.order + 1 local realpage = texgetcount("realpageno") @@ -148,10 +151,8 @@ local function setdataset(settings) local name, tag = setdata(settings) if settings.delay ~= v_yes then -- - elseif type(tag) == "number" then - context(new_latelua(formatters["job.datasets.extend(%q,%i)"](name,tag))) else - context(new_latelua(formatters["job.datasets.extend(%q,%q)"](name,tag))) + context(new_latelua { action = job.datasets.extend, name = name, tag = tag }) end end diff --git a/tex/context/base/mkiv/core-lmt.mkiv b/tex/context/base/mkiv/core-lmt.mkiv index 0398537d4..eda667969 100644 --- a/tex/context/base/mkiv/core-lmt.mkiv +++ b/tex/context/base/mkiv/core-lmt.mkiv @@ -11,6 +11,8 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. +\ifcase\contextlmtxmode\expandafter\endinput\fi + \writestatus{loading}{ConTeXt System Macros / Primitives} \ifdefined\textdir \else diff --git a/tex/context/base/mkiv/core-sys.lua b/tex/context/base/mkiv/core-sys.lua index 4078ab8a8..7e9648fb8 100644 --- a/tex/context/base/mkiv/core-sys.lua +++ b/tex/context/base/mkiv/core-sys.lua @@ -53,6 +53,10 @@ function environment.initializefilenames() environment.filename = filename environment.suffix = suffix + -- if tex then + -- tex.jobname = jobfilename + -- end + report_files("jobname %a, input %a, result %a",jobfilename,inputfilename,outputfilename) function environment.initializefilenames() end diff --git a/tex/context/base/mkiv/data-aux.lua b/tex/context/base/mkiv/data-aux.lua index 1e020d1e8..c57f16d2c 100644 --- a/tex/context/base/mkiv/data-aux.lua +++ b/tex/context/base/mkiv/data-aux.lua @@ -50,7 +50,7 @@ function resolvers.updatescript(oldname,newname) -- oldname -> own.name, not per local newdata = io.loaddata(newscript) if newdata then if trace_locating then - report_scripts("old script content replaced by new content") + report_scripts("old script content replaced by new content: %s",oldscript) end io.savedata(oldscript,newdata) break diff --git a/tex/context/base/mkiv/data-exp.lua b/tex/context/base/mkiv/data-exp.lua index 76fd3c7b0..ce7f95222 100644 --- a/tex/context/base/mkiv/data-exp.lua +++ b/tex/context/base/mkiv/data-exp.lua @@ -344,9 +344,11 @@ local function scan(files,remap,spec,path,n,m,r,onlyone,tolerant) local pattern = tolerant and lessweird or weird local filelist = { } local noffiles = 0 - for name in directory(full) do + for name, mode in directory(full) do if not lpegmatch(pattern,name) then - local mode = attributes(full..name,"mode") + if not mode then + mode = attributes(full..name,"mode") + end if mode == "file" then n = n + 1 noffiles = noffiles + 1 diff --git a/tex/context/base/mkiv/data-tmp.lua b/tex/context/base/mkiv/data-tmp.lua index 948827161..d25a6b2f9 100644 --- a/tex/context/base/mkiv/data-tmp.lua +++ b/tex/context/base/mkiv/data-tmp.lua @@ -68,6 +68,8 @@ caches.ask = false caches.relocate = false caches.defaults = { "TMPDIR", "TEMPDIR", "TMP", "TEMP", "HOME", "HOMEPATH" } +directives.register("system.caches.fast",function(v) caches.fast = true end) + local writable, readables, usedreadables = nil, { }, { } -- we could use a metatable for writable and readable but not yet @@ -364,7 +366,9 @@ local saveoptions = { compact = true } function caches.savedata(filepath,filename,data,raw) local tmaname, tmcname = caches.setluanames(filepath,filename) data.cache_uuid = os.uuid() - if caches.direct then + if caches.fast then + file.savedata(tmaname,table.fastserialize(data,true)) + elseif caches.direct then file.savedata(tmaname,table.serialize(data,true,saveoptions)) else table.tofile(tmaname,data,true,saveoptions) diff --git a/tex/context/base/mkiv/data-zip.lua b/tex/context/base/mkiv/data-zip.lua index 6f20b4a9d..388ae0c10 100644 --- a/tex/context/base/mkiv/data-zip.lua +++ b/tex/context/base/mkiv/data-zip.lua @@ -37,6 +37,81 @@ zip.archives = archives local registeredfiles = zip.registeredfiles or { } zip.registeredfiles = registeredfiles +local zipfiles = utilities.zipfiles + +local openzip, closezip, validfile, wholefile, filehandle, traversezip + +if zipfiles then + + local ipairs = ipairs + + openzip = zipfiles.open + closezip = zipfiles.close + validfile = zipfiles.found + wholefile = zipfiles.unzip + + traversezip = function(zfile) + return ipairs(zipfiles.list(zfile)) + end + + local streams = utilities.streams + local openstream = streams.open + local readstring = streams.readstring + local streamsize = streams.size + + local metatable = { + close = streams.close, + read = function(stream,n) + readstring(stream,n == "*a" and streamsize(stream) or n) + end + } + + filehandle = function(zfile,queryname) + local data = wholefile(zfile,queryname) + if data then + local stream = openstream(data) + if stream then + return setmetatableindex(stream,metatable) + end + end + end + +else + + openzip = zip.open + closezip = zip.close + + validfile = function(zfile,queryname) + local dfile = zfile:open(queryname) + if dfile then + dfile:close() + return true + end + return false + end + + traversezip = function(zfile) + return z:files() + end + + wholefile = function(zfile,queryname) + local dfile = zfile:open(queryname) + if dfile then + local s = dfile:read("*all") + dfile:close() + return s + end + end + + filehandle = function(zfile,queryname) + local dfile = zfile:open(queryname) + if dfile then + return dfile + end + end + +end + local function validzip(str) -- todo: use url splitter if not find(str,"^zip://") then return "zip:///" .. str @@ -52,7 +127,7 @@ function zip.openarchive(name) local arch = archives[name] if not arch then local full = resolvers.findfile(name) or "" - arch = full ~= "" and zip.open(full) or false + arch = full ~= "" and openzip(full) or false archives[name] = arch end return arch @@ -61,7 +136,7 @@ end function zip.closearchive(name) if not name or (name == "" and archives[name]) then - zip.close(archives[name]) + closezip(archives[name]) archives[name] = nil end end @@ -106,9 +181,7 @@ function resolvers.finders.zip(specification) if trace_locating then report_zip("finder: archive %a found",archive) end - local dfile = zfile:open(queryname) - if dfile then - dfile:close() + if validfile(zfile,queryname) then if trace_locating then report_zip("finder: file %a found",queryname) end @@ -139,12 +212,12 @@ function resolvers.openers.zip(specification) if trace_locating then report_zip("opener; archive %a opened",archive) end - local dfile = zfile:open(queryname) - if dfile then + local handle = filehandle(zfile,queryname) + if handle then if trace_locating then report_zip("opener: file %a found",queryname) end - return resolvers.openers.helpers.textopener('zip',original,dfile) + return resolvers.openers.helpers.textopener('zip',original,handle) elseif trace_locating then report_zip("opener: file %a not found",queryname) end @@ -171,15 +244,13 @@ function resolvers.loaders.zip(specification) if trace_locating then report_zip("loader: archive %a opened",archive) end - local dfile = zfile:open(queryname) - if dfile then + local data = wholefile(zfile,queryname) + if data then logs.show_load(original) if trace_locating then report_zip("loader; file %a loaded",original) end - local s = dfile:read("*all") - dfile:close() - return true, s, #s + return true, data, #data elseif trace_locating then report_zip("loader: file %a not found",queryname) end @@ -231,7 +302,7 @@ function resolvers.registerzipfile(z,tree) if trace_locating then report_zip("registering: using filter %a",filter) end - for i in z:files() do + for i in traversezip(z) do local filename = i.filename local path, name = match(filename,filter) if not path then diff --git a/tex/context/base/mkiv/driv-ini.lua b/tex/context/base/mkiv/driv-ini.lua index e16327f27..f3d62c778 100644 --- a/tex/context/base/mkiv/driv-ini.lua +++ b/tex/context/base/mkiv/driv-ini.lua @@ -21,11 +21,13 @@ local instances = { } local helpers = { } local prepared = { } local wrappedup = { } +local cleanedup = { } local currentdriver = "default" local prepare = nil local convert = nil local wrapup = nil +local cleanup = nil local outputfilename = nil drivers = drivers or { @@ -42,6 +44,7 @@ local defaulthandlers = { finalize = dummy, updatefontstate = dummy, wrapup = dummy, + cleanup = dummy, convert = dummy, outputfilename = dummy, } @@ -78,13 +81,23 @@ function drivers.outputfilename() return outputfilename() end - luatex.wrapup(function() - if not wrappedup[currentdriver] then + if wrapup and not wrappedup[currentdriver] then starttiming(drivers) wrapup() stoptiming(drivers) wrappedup[currentdriver] = true + cleanedup[currentdriver] = true + end +end) + +luatex.cleanup(function() + if cleanup and not cleanedup[currentdriver] then + starttiming(drivers) + cleanup() + stoptiming(drivers) + wrappedup[currentdriver] = true + cleanedup[currentdriver] = true end end) @@ -93,6 +106,7 @@ function drivers.enable(name) local actions = instances[currentdriver].actions prepare = actions.prepare wrapup = actions.wrapup + cleanup = actions.cleanup convert = actions.convert outputfilename = actions.outputfilename -- diff --git a/tex/context/base/mkiv/driv-shp.lua b/tex/context/base/mkiv/driv-shp.lua new file mode 100644 index 000000000..7938e3e5c --- /dev/null +++ b/tex/context/base/mkiv/driv-shp.lua @@ -0,0 +1,1388 @@ +if not modules then modules = { } end modules ['driv-shp'] = { + version = 1.001, + comment = "companion to driv-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local type, next = type, next +local round = math.round + +local setmetatableindex = table.setmetatableindex +local formatters = string.formatters +local concat = table.concat +local keys = table.keys +local sortedhash = table.sortedhash +local splitstring = string.split +local idiv = number.idiv +local extract = bit32.extract +local nuts = nodes.nuts + +local tonut = nodes.tonut +local tonode = nodes.tonode + +local getdirection = nuts.getdirection +local getlist = nuts.getlist +local getoffsets = nuts.getoffsets +local getorientation = nuts.getorientation +local getfield = nuts.getfield +local getwhd = nuts.getwhd +local getkern = nuts.getkern +local getheight = nuts.getheight +local getdepth = nuts.getdepth +local getwidth = nuts.getwidth +local getnext = nuts.getnext +local getsubtype = nuts.getsubtype +local getid = nuts.getid +local getleader = nuts.getleader +local getglue = nuts.getglue +local getshift = nuts.getshift +local getdata = nuts.getdata +local getboxglue = nuts.getboxglue +local getexpansion = nuts.getexpansion + +----- getall = node.direct.getall + +local setdirection = nuts.setdirection +local setfield = nuts.setfield +local setlink = nuts.setlink + +local isglyph = nuts.isglyph +local findtail = nuts.tail +local nextdir = nuts.traversers.dir +local nextnode = nuts.traversers.node + +local rangedimensions = nuts.rangedimensions +local effectiveglue = nuts.effective_glue + +local nodecodes = nodes.nodecodes +local whatsitcodes = nodes.whatsitcodes +local leadercodes = nodes.leadercodes +local subtypes = nodes.subtypes + +local dircodes = nodes.dircodes +local normaldir_code = dircodes.normal + +local dirvalues = nodes.dirvalues +local lefttoright_code = dirvalues.lefttoright +local righttoleft_code = dirvalues.righttoleft + +local glyph_code = nodecodes.glyph +local kern_code = nodecodes.kern +local glue_code = nodecodes.glue +local hlist_code = nodecodes.hlist +local vlist_code = nodecodes.vlist +local dir_code = nodecodes.dir +local disc_code = nodecodes.disc +local math_code = nodecodes.math +local rule_code = nodecodes.rule +local marginkern_code = nodecodes.marginkern +local whatsit_code = nodecodes.whatsit + +local leader_code = leadercodes.leader +local cleader_code = leadercodes.cleader +local xleader_code = leadercodes.xleader +local gleader_code = leadercodes.gleader + +local saveposwhatsit_code = whatsitcodes.savepos +local userdefinedwhatsit_code = whatsitcodes.userdefined +local openwhatsit_code = whatsitcodes.open +local writewhatsit_code = whatsitcodes.write +local closewhatsit_code = whatsitcodes.close +local lateluawhatsit_code = whatsitcodes.latelua +local literalwhatsit_code = whatsitcodes.literal +local setmatrixwhatsit_code = whatsitcodes.setmatrix +local savewhatsit_code = whatsitcodes.save +local restorewhatsit_code = whatsitcodes.restore + +local texget = tex.get + +local fonthashes = fonts.hashes +local fontdata = fonthashes.identifiers +local characters = fonthashes.characters +local parameters = fonthashes.parameters + +local report = logs.reporter("drivers") + +local getpagedimensions getpagedimensions = function() + getpagedimensions = backends.codeinjections.getpagedimensions + return getpagedimensions() +end + +local drivers = drivers +local instances = drivers.instances + +--------------------------------------------------------------------------------------- + +local synctex = false + +local lastfont = nil +local fontcharacters = nil + +local magicconstants = tex.magicconstants +local trueinch = magicconstants.trueinch +local maxdimen = magicconstants.maxdimen +local running = magicconstants.running + +local pos_h = 0 +local pos_v = 0 +local pos_r = lefttoright_code +local shippingmode = "none" + +local abs_max_v = 0 +local abs_max_h = 0 + +local shipbox_h = 0 +local shipbox_v = 0 +local page_size_h = 0 +local page_size_v = 0 +----- page_h_origin = 0 -- trueinch +----- page_v_origin = 0 -- trueinch + +local initialize +local finalize +local updatefontstate +local pushorientation +local poporientation +local flushcharacter +local flushrule +local flushpdfliteral +local flushpdfsetmatrix +local flushpdfsave +local flushpdfrestore +local flushspecial +local flushpdfimage + +-- make local + +function drivers.getpos () return round(pos_h), round(pos_v) end +function drivers.gethpos() return round(pos_h) end +function drivers.getvpos() return round(pos_v) end + +-- local function synch_pos_with_cur(ref_h, ref_v, h, v) +-- if pos_r == righttoleft_code then +-- pos_h = ref_h - h +-- else +-- pos_h = ref_h + h +-- end +-- pos_v = ref_v - v +-- end + +-- characters + +local flush_character + +local stack = setmetatableindex("table") +local level = 0 +local nesting = 0 +local main = 0 + +-- todo: cache streams + +local function flush_vf_packet(pos_h,pos_v,pos_r,font,char,data,factor,vfcommands) + + if nesting > 100 then + return + elseif nesting == 0 then + main = font + end + + nesting = nesting + 1 + + local saved_h = pos_h + local saved_v = pos_v + local saved_r = pos_r + pos_r = lefttoright_code + + local data = fontdata[font] + local fnt = font + local fonts = data.fonts + local siz = (data.parameters.factor or 1)/65536 + + local function flushchar(font,char,fnt,chr,f,e) + if fnt then + local nest = char ~= chr or font ~= fnt + if fnt == 0 then + fnt = main + end + return flush_character(false,fnt,chr,factor,nest,pos_h,pos_v,pos_r,f,e) + else + return 0 + end + end + + -- we assume resolved fonts: id mandate but maybe also size + + for i=1,#vfcommands do + local packet = vfcommands[i] + local command = packet[1] + if command == "char" then + local chr = packet[2] + local f = packet[3] + local e = packet[4] + pos_h = pos_h + flushchar(font,char,fnt,chr,f,e) + elseif command == "slot" then + local index = packet[2] + local chr = packet[3] + local f = packet[4] + local e = packet[5] + if index == 0 then + pos_h = pos_h + flushchar(font,char,font,chr,f,e) + else + local okay = fonts and fonts[index] + if okay then + local fnt = okay.id + if fnt then + pos_h = pos_h + flushchar(font,char,fnt,chr,f,e) + end + end + end + elseif command == "right" then + local h = packet[2] -- * siz + if factor ~= 0 and h ~= 0 then + h = h + h * factor / 1000 -- expansion + end + pos_h = pos_h + h + elseif command == "down" then + local v = packet[2] -- * siz + pos_v = pos_v - v + elseif command == "push" then + level = level + 1 + local s = stack[level] + s[1] = pos_h + s[2] = pos_v + elseif command == "pop" then + if level > 0 then + local s = stack[level] + pos_h = s[1] + pos_v = s[2] + level = level - 1 + end + elseif command == "pdf" then + flushpdfliteral(false,pos_h,pos_v,packet[2],packet[3]) + elseif command == "rule" then + local size_v = packet[2] + local size_h = packet[3] + if factor ~= 0 and size_h > 0 then + size_h = size_h + size_h * factor / 1000 + end + if size_h > 0 and size_v > 0 then + flushsimplerule(pos_h,pos_v,pos_r,size_h,size_v) + pos_h = pos_h + size_h + end + elseif command == "font" then + local index = packet[2] + local okay = fonts and fonts[index] + if okay then + fnt = okay.id or fnt -- or maybe just return + end + elseif command == "lua" then + local code = packet[2] + if type(code) ~= "function" then + code = loadstring(code) + end + if type(code) == "function" then + code(font,char,pos_h,pos_v) + end + elseif command == "node" then + hlist_out(packet[2]) + elseif command == "image" then + -- doesn't work because intercepted by engine so we use a different + -- mechanism (for now) + local image = packet[2] + -- to do + elseif command == "pdfmode" then + -- doesn't happen + -- elseif command == "special" then + -- -- not supported + -- elseif command == "nop" then + -- -- nothing to do| + -- elseif command == "scale" then + -- -- not supported + end + end + + pos_h = saved_h + pos_v = saved_v + pos_r = saved_r + + -- synch_pos_with_cur(ref_h, ref_v, pos_h,pos_v) + nesting = nesting - 1 +end + +local onetimemessage -- could be defined later (todo: make plug for this) + +flush_character = function(current,font,char,factor,vfcommands,pos_h,pos_v,pos_r,f,e) + + if font ~= lastfont then + lastfont = font + fontcharacters = characters[font] + updatefontstate(font) + end + + local data = fontcharacters[char] + if not data then + if not onetimemessage then + onetimemessage = fonts.loggers.onetimemessage + end + onetimemessage(font,char,"missing") + return 0, 0, 0 + end + + local width, height, depth + if current then +-- width, height, depth = getwhd(current) +-- factor = getexpansion(current) + width, height, depth, factor = getwhd(current,true) + if factor ~= 0 then + width = (1.0 + factor/1000000.0) * width + end + else + width = data.width or 0 + height = data.height or 0 + depth = data.depth or 0 + if not factor then + factor = 0 + end + end + if pos_r == righttoleft_code then + pos_h = pos_h - width + end + if vfcommands then + vfcommands = data.commands + end + if vfcommands then + flush_vf_packet(pos_h,pos_v,pos_r,font,char,data,factor,vfcommands) -- also f ? + else + local orientation = data.orientation + if orientation and (orientation == 1 or orientation == 3) then + local x = data.xoffset + local y = data.yoffset + if x then + pos_h = pos_h + x + end + if y then + pos_v = pos_v + y + end + pushorientation(orientation,pos_h,pos_v) + flushcharacter(current,pos_h,pos_v,pos_r,font,char,data,factor,width,f,e) + poporientation(orientation,pos_h,pos_v) + else + flushcharacter(current,pos_h,pos_v,pos_r,font,char,data,factor,width,f,e) + end + end + return width, height, depth +end + +-- end of characters + +local function reset_state() + pos_h = 0 + pos_v = 0 + pos_r = lefttoright_code + shipbox_h = 0 + shipbox_v = 0 + shippingmode = "none" + page_size_h = 0 + page_size_v = 0 + -- page_h_origin = 0 -- trueinch + -- page_v_origin = 0 -- trueinch +end + +local function dirstackentry(t,k) + local v = { + cur_h = 0, + cur_v = 0, + ref_h = 0, + ref_v = 0, + } + t[k] = v + return v +end + +local dirstack = setmetatableindex(dirstackentry) + +local function reset_dir_stack() + dirstack = setmetatableindex(dirstackentry) +end + +local function flushlatelua(current) + return backends.latelua(current) +end + +local function flushwriteout(current) + if not doing_leaders then + backends.writeout(current) + end +end + +local function flushopenout(current) + if not doing_leaders then + backends.openout(current) + end +end + +local function flushcloseout(current) + if not doing_leaders then + backends.closeout(current) + end +end + +local hlist_out, vlist_out do + + -- effective_glue : + -- + -- local cur_g = 0 + -- local cur_glue = 0.0 + -- + -- local width, stretch, shrink, stretch_order, shrink_order = getglue(current) + -- if g_sign == 1 then -- stretching + -- if stretch_order == g_order then + -- -- rule_wd = width - cur_g + -- -- cur_glue = cur_glue + stretch + -- -- cur_g = g_set * cur_glue + -- -- rule_wd = rule_wd + cur_g + -- rule_ht = width + g_set * stretch + -- else + -- rule_wd = width + -- end + -- else + -- if shrink_order == g_order then + -- -- rule_wd = width - cur_g + -- -- cur_glue = cur_glue - shrink + -- -- cur_g = g_set * cur_glue + -- -- rule_wd = rule_wd + cur_g + -- rule_ht = width - g_set * shrink + -- else + -- rule_wd = width + -- end + -- end + + local function applyanchor(orientation,x,y,width,height,depth,woffset,hoffset,doffset,xoffset,yoffset) + local ot = extract(orientation, 0,4) + local ay = extract(orientation, 4,4) + local ax = extract(orientation, 8,4) + local of = extract(orientation,12,4) + if ot == 4 then + ot, ay = 0, 1 + elseif ot == 5 then + ot, ay = 0, 2 + end + if ot == 0 or ot == 2 then + if ax == 1 then x = x - width + elseif ax == 2 then x = x + width + elseif ax == 3 then x = x - width/2 + elseif ax == 4 then x = x + width/2 + end + if ot == 2 then + doffset, hoffset = hoffset, doffset + end + if ay == 1 then y = y - doffset + elseif ay == 2 then y = y + hoffset + elseif ay == 3 then y = y + (doffset + hoffset)/2 - doffset + end + elseif ot == 1 or ot == 3 then + if ay == 1 then y = y - height + elseif ay == 2 then y = y + height + elseif ay == 3 then y = y - height/2 + end + if ot == 1 then + doffset, hoffset = hoffset, doffset + end + if ax == 1 then x = x - width + elseif ax == 2 then x = x + width + elseif ax == 3 then x = x - width/2 + elseif ax == 4 then x = x + width/2 + elseif ax == 5 then x = x - hoffset + elseif ax == 6 then x = x + doffset + end + end + return ot, x + xoffset, y - yoffset + end + + -- rangedir can stick to widths only + + rangedimensions = node.direct.naturalwidth or rangedimensions + + local function calculate_width_to_enddir(this_box,begindir) -- can be a helper + local dir_nest = 1 + local enddir = begindir + for current, subtype in nextdir, getnext(begindir) do + if subtype == normaldir_code then -- todo + dir_nest = dir_nest + 1 + else + dir_nest = dir_nest - 1 + end + if dir_nest == 0 then -- does the type matter + enddir = current + local width = rangedimensions(this_box,begindir,enddir) + return enddir, width + end + end + if enddir == begindir then + local width = rangedimensions(this_box,begindir) -- ,enddir) + return enddir, width + end + return enddir, 0 + end + + -- check frequencies of nodes + + hlist_out = function(this_box,current) + local outer_doing_leaders = false + + local ref_h = pos_h + local ref_v = pos_v + local ref_r = pos_r + pos_r = getdirection(this_box) + + local boxwidth, + boxheight, + boxdepth = getwhd(this_box) + local g_set, + g_order, + g_sign = getboxglue(this_box) + + local cur_h = 0 + local cur_v = 0 + + if not current then + current = getlist(this_box) + end + + -- if synctex then + -- synctexhlist(this_box) + -- end + + while current do + local char, id = isglyph(current) + if char then + local x_offset, y_offset = getoffsets(current) + if x_offset ~= 0 or y_offset ~= 0 then + -- synch_pos_with_cur(ref_h, ref_v, cur_h + x_offset, cur_v - y_offset) + if pos_r == righttoleft_code then + pos_h = ref_h - (cur_h + x_offset) + else + pos_h = ref_h + (cur_h + x_offset) + end + pos_v = ref_v - (cur_v - y_offset) + -- synced + end + local wd, ht, dp = flush_character(current,id,char,false,true,pos_h,pos_v,pos_r) + cur_h = cur_h + wd + elseif id == glue_code then + local gluewidth + if g_sign == 0 then + gluewidth = getwidth(current) + else + gluewidth = effectiveglue(current,this_box) + end + if gluewidth ~= 0 then + local leader = getleader(current) + if leader then + local width, height, depth = getwhd(leader) + if getid(leader) == rule_code then + if gluewidth > 0 then + if height == running then + height = boxheight + end + if depth == running then + depth = boxdepth + end + local total = height + depth + if total > 0 then + if pos_r == righttoleft_code then + pos_h = pos_h - gluewidth + end + pos_v = pos_v - depth + flushrule(leader,pos_h,pos_v,pos_r,gluewidth,total) + end + cur_h = cur_h + gluewidth + end + elseif width > 0 and gluewidth > 0 then + local boxdir = getdirection(leader) or lefttoright_code + gluewidth = gluewidth + 10 + local edge = cur_h + gluewidth + local lx = 0 + local subtype = getsubtype(current) + if subtype == gleader_code then + local save_h = cur_h + if pos_r == righttoleft_code then + cur_h = ref_h - shipbox_h - cur_h + cur_h = width * (cur_h / width) + cur_h = ref_h - shipbox_h - cur_h + else + cur_h = cur_h + ref_h - shipbox_h + cur_h = width * (cur_h / width) + cur_h = cur_h - ref_h - shipbox_h + end + if cur_h < save_h then + cur_h = cur_h + width + end + elseif subtype == leader_code then -- aleader ? + local save_h = cur_h + cur_h = width * (cur_h / width) + if cur_h < save_h then + cur_h = cur_h + width + end + else + lq = gluewidth / width + lr = gluewidth % width + if subtype == cleader_code then + cur_h = cur_h + lr / 2 + else + lx = lr / (lq + 1) + cur_h = cur_h + (lr - (lq - 1) * lx) / 2 + end + end + local shift = getshift(leader) + while cur_h + width <= edge do + local basepoint_h = 0 + -- local basepoint_v = shift + if boxdir ~= pos_r then + basepoint_h = boxwidth + end + -- synch_pos_with_cur(ref_h,ref_v,cur_h + basepoint_h,shift) + if pos_r == righttoleft_code then + pos_h = ref_h - (cur_h + basepoint_h) + else + pos_h = ref_h + (cur_h + basepoint_h) + end + pos_v = ref_v - shift + -- synced + outer_doing_leaders = doing_leaders + doing_leaders = true + if getid(leader) == vlist_code then + vlist_out(leader) + else + hlist_out(leader) + end + doing_leaders = outer_doing_leaders + cur_h = cur_h + width + lx + end + cur_h = edge - 10 + else + cur_h = cur_h + gluewidth + -- if synctex then + -- synch_pos_with_cur(ref_h, ref_v, cur_h, cur_v) + -- synctexhorizontalruleorglue(p, this_box) + -- end + end + else + cur_h = cur_h + gluewidth + -- if synctex then + -- synch_pos_with_cur(ref_h, ref_v, cur_h, cur_v) + -- synctexhorizontalruleorglue(p, this_box) + -- end + end + end + elseif id == hlist_code or id == vlist_code then + -- w h d dir l, s, o = getall(current) + local boxdir = getdirection(current) or lefttoright_code + local width, height, depth = getwhd(current) + local list = getlist(current) + if list then + local shift, orientation = getshift(current) + if not orientation then +-- local width, height, depth, list, boxdir, shift, orientation = getall(current) +-- if list then +-- if not orientation then + local basepoint_h = boxdir ~= pos_r and width or 0 + -- local basepoint_v = shift + -- synch_pos_with_cur(ref_h,ref_v,cur_h + basepoint_h,shift) + if pos_r == righttoleft_code then + pos_h = ref_h - (cur_h + basepoint_h) + else + pos_h = ref_h + (cur_h + basepoint_h) + end + pos_v = ref_v - shift + -- synced + if id == vlist_code then + vlist_out(current,list) + else + hlist_out(current,list) + end + elseif orientation == 0x1000 then + local orientation, xoffset, yoffset = getorientation(current) + local basepoint_h = boxdir ~= pos_r and width or 0 + -- local basepoint_v = shift + -- synch_pos_with_cur(ref_h,ref_v,cur_h + basepoint_h + xoffset,shift - yoffset) + if pos_r == righttoleft_code then + pos_h = ref_h - (cur_h + basepoint_h + xoffset) + else + pos_h = ref_h + (cur_h + basepoint_h + xoffset) + end + pos_v = ref_v - (shift - yoffset) + -- synced + if id == vlist_code then + vlist_out(current,list) + else + hlist_out(current,list) + end + else + local orientation, xoffset, yoffset, woffset, hoffset, doffset = getorientation(current) + local orientation, basepoint_h, basepoint_v = applyanchor(orientation,0,shift,width,height,depth,woffset,hoffset,doffset,xoffset,yoffset) + if orientation == 1 then + basepoint_h = basepoint_h + doffset + if boxdir == pos_r then + basepoint_v = basepoint_v - height + end + elseif orientation == 2 then + if boxdir == pos_r then + basepoint_h = basepoint_h + width + end + elseif orientation == 3 then + basepoint_h = basepoint_h + hoffset + if boxdir ~= pos_r then + basepoint_v = basepoint_v - height + end + end + -- synch_pos_with_cur(ref_h,ref_v,cur_h+basepoint_h,cur_v + basepoint_v) + if pos_r == righttoleft_code then + pos_h = ref_h - (cur_h + basepoint_h) + else + pos_h = ref_h + (cur_h + basepoint_h) + end + pos_v = ref_v - (cur_v + basepoint_v) + -- synced + pushorientation(orientation,pos_h,pos_v,pos_r) + if id == vlist_code then + vlist_out(current,list) + else + hlist_out(current,list) + end + poporientation(orientation,pos_h,pos_v,pos_r) + end + else + -- if synctex then + -- if id == vlist_code then + -- synctexvoidvlist(p,this_box) + -- else + -- synctexvoidhlist(p,this_box) + -- end + -- end + end + cur_h = cur_h + width + elseif id == disc_code then + local replace = getfield(current,"replace") + if replace and getsubtype(current) ~= select_disc then + -- we could flatten .. no gain + setlink(findtail(replace),getnext(current)) + setlink(current,replace) + setfield(current,"replace") + end + elseif id == kern_code then + -- if synctex then + -- synctexkern(p, this_box) + -- end +-- local kern = getkern(current) +-- local factor = getexpansion(current) + local kern, factor = getkern(current,true) + if kern ~= 0 then + if factor and factor ~= 0 then + cur_h = cur_h + (1.0 + factor/1000000.0) * kern + else + cur_h = cur_h + kern + end + end + elseif id == rule_code then + -- w h d x y = getall(current) + local width, height, depth = getwhd(current) + if width > 0 then + if height == running then + height = boxheight + end + if depth == running then + depth = boxdepth + end + local total = height + depth + if total > 0 then + local xoffset, yoffset, left, right = getoffsets(current) + if left ~= 0 then + pos_v = pos_v + left + total = total - left + end + if right ~= 0 then + depth = depth - right + total = total - right + end + if pos_r == righttoleft_code then + pos_h = pos_h - width + xoffset = - xoffset + end + pos_v = pos_v - depth + flushrule(current,pos_h + xoffset,pos_v + yoffset,pos_r,width,total) + end + cur_h = cur_h + width + end + elseif id == math_code then + -- if synctex then + -- synctexmath(p, this_box) + -- end + local kern = getkern(current) + if kern ~= 0 then + cur_h = cur_h + kern + elseif g_sign == 0 then + cur_h = cur_h + getwidth(current) + else + cur_h = cur_h + effectiveglue(current,this_box) + end + elseif id == dir_code then + -- we normally have proper begin-end pairs + -- a begin without end is (silently) handled + -- an end without a begin will be (silently) skipped + -- we only need to move forward so a faster calculation + local dir, cancel = getdirection(current) + if cancel then + local ds = dirstack[current] + ref_h = ds.ref_h + ref_v = ds.ref_v + cur_h = ds.cur_h + cur_v = ds.cur_v + pos_r = dir + else + local enddir, width = calculate_width_to_enddir(this_box,current) + local ds = dirstack[enddir] + ds.cur_h = cur_h + width + if dir ~= pos_r then + cur_h = ds.cur_h + end + if enddir ~= current then + local ds = dirstack[enddir] + ds.cur_v = cur_v + ds.ref_h = ref_h + ds.ref_v = ref_v + setdirection(enddir,pos_r) + end + -- synch_pos_with_cur(ref_h,ref_v,cur_h,cur_v) + if pos_r == righttoleft_code then + pos_h = ref_h - cur_h + else + pos_h = ref_h + cur_h + end + pos_v = ref_v - cur_v + -- synced + ref_h = pos_h + ref_v = pos_v + cur_h = 0 + cur_v = 0 + pos_r = dir + end + elseif id == whatsit_code then + local subtype = getsubtype(current) + if subtype == literalwhatsit_code then + flushpdfliteral(current,pos_h,pos_v) + elseif subtype == lateluawhatsit_code then + flushlatelua(current,pos_h,pos_v,cur_h,cur_v) + elseif subtype == setmatrixwhatsit_code then + flushpdfsetmatrix(current,pos_h,pos_v) + elseif subtype == savewhatsit_code then + flushpdfsave(current,pos_h,pos_v) + elseif subtype == restorewhatsit_code then + flushpdfrestore(current,pos_h,pos_v) + elseif subtype == saveposwhatsit_code then + last_position_x = pos_h -- or pdf_h + last_position_y = pos_v -- or pdf_v + elseif subtype == writewhatsit_code then + flushwriteout(current) + elseif subtype == closewhatsit_code then + flushcloseout(current) + elseif subtype == openwhatsit_code then + flushopenout(current) + end + elseif id == marginkern_code then + cur_h = cur_h + getkern(current) + end + current = getnext(current) + -- synch_pos_with_cur(ref_h, ref_v, cur_h, cur_v) -- already done in list so skip + if pos_r == righttoleft_code then + pos_h = ref_h - cur_h + else + pos_h = ref_h + cur_h + end + pos_v = ref_v - cur_v + -- synced + end + -- if synctex then + -- synctextsilh(this_box) + -- end + pos_h = ref_h + pos_v = ref_v + pos_r = ref_r + end + + vlist_out = function(this_box,current) + local outer_doing_leaders = false + + local ref_h = pos_h + local ref_v = pos_v + local ref_r = pos_r + pos_r = getdirection(this_box) + + local boxwidth, + boxheight, + boxdepth = getwhd(this_box) + local g_set, + g_order, + g_sign = getboxglue(this_box) + + local cur_h = 0 + local cur_v = - boxheight + + local top_edge = cur_v + + -- synch_pos_with_cur(ref_h, ref_v, cur_h, cur_v) + if pos_r == righttoleft_code then + pos_h = ref_h - cur_h + else + pos_h = ref_h + cur_h + end + pos_v = ref_v - cur_v + -- synced + + if not current then + current = getlist(this_box) + end + + -- if synctex then + -- synctexvlist(this_box) + -- end + + -- while current do + -- local id = getid(current) + for current, id, subtype in nextnode, current do + if id == glue_code then + local glueheight + if g_sign == 0 then + glueheight = getwidth(current) + else + glueheight = effectiveglue(current,this_box) + end + local leader = getleader(current) + if leader then + local width, height, depth = getwhd(leader) + local total = height + depth + if getid(leader) == rule_code then + depth = 0 -- hm + if total > 0 then + if width == running then + width = boxwidth + end + if width > 0 then + if pos_r == righttoleft_code then + cur_h = cur_h - width + end + flushrule(leader,pos_h,pos_v - total,pos_r,width,total) + end + cur_v = cur_v + total + end + else + if total > 0 and glueheight > 0 then + glueheight = glueheight + 10 + local edge = cur_v + glueheight + local ly = 0 + if subtype == gleader_code then + save_v = cur_v + cur_v = ref_v - shipbox_v - cur_v + cur_v = total * (cur_v / total) + cur_v = ref_v - shipbox_v - cur_v + if cur_v < save_v then + cur_v = cur_v + total + end + elseif subtype == leader_code then -- aleader + save_v = cur_v + cur_v = top_edge + total * ((cur_v - top_edge) / total) + if cur_v < save_v then + cur_v = cur_v + total + end + else + lq = glueheight / total + lr = glueheight % total + if subtype == cleaders_code then + cur_v = cur_v + lr / 2 + else + ly = lr / (lq + 1) + cur_v = cur_v + (lr - (lq - 1) * ly) / 2 + end + end + local shift = getshift(leader) + while cur_v + total <= edge do -- todo: <= edge - total + -- synch_pos_with_cur(ref_h, ref_v, getshift(leader), cur_v + height) + if pos_r == righttoleft_code then + pos_h = ref_h - shift + else + pos_h = ref_h + shift + end + pos_v = ref_v - (cur_v + height) + -- synced + outer_doing_leaders = doing_leaders + doing_leaders = true + if getid(leader) == vlist_code then + vlist_out(leader) + else + hlist_out(leader) + end + doing_leaders = outer_doing_leaders + cur_v = cur_v + total + ly + end + cur_v = edge - 10 + else + cur_v = cur_v + glueheight + end + end + else + cur_v = cur_v + glueheight + end + elseif id == hlist_code or id == vlist_code then + -- w h d dir l, s, o = getall(current) + local boxdir = getdirection(current) or lefttoright_code + local width, height, depth = getwhd(current) + local list = getlist(current) + if list then + local shift, orientation = getshift(current) + if not orientation then +-- local width, height, depth, list, boxdir, shift, orientation = getall(current) +-- if list then +-- if not orientation then + -- local basepoint_h = shift + -- local basepoint_v = height + if boxdir ~= pos_r then + shift = shift + width + end + -- synch_pos_with_cur(ref_h,ref_v,shift,cur_v + height) + if pos_r == righttoleft_code then + pos_h = ref_h - shift + else + pos_h = ref_h + shift + end + pos_v = ref_v - (cur_v + height) + -- synced + if id == vlist_code then + vlist_out(current,list) + else + hlist_out(current,list) + end + elseif orientation == 0x1000 then + local orientation, xoffset, yoffset = getorientation(current) + -- local basepoint_h = shift + -- local basepoint_v = height + if boxdir ~= pos_r then + shift = shift + width + end + -- synch_pos_with_cur(ref_h,ref_v,shift + xoffset,cur_v + height - yoffset) + if pos_r == righttoleft_code then + pos_h = ref_h - (shift + xoffset) + else + pos_h = ref_h + (shift + xoffset) + end + pos_v = ref_v - (cur_v + height - yoffset) + -- synced + if id == vlist_code then + vlist_out(current,list) + else + hlist_out(current,list) + end + else + local orientation, xoffset, yoffset, woffset, hoffset, doffset = getorientation(current) + local orientation, basepoint_h, basepoint_v = applyanchor(orientation,shift,height,width,height,depth,woffset,hoffset,doffset,xoffset,yoffset) + if orientation == 1 then + basepoint_h = basepoint_h + width - height + basepoint_v = basepoint_v - height + elseif orientation == 2 then + basepoint_h = basepoint_h + width + basepoint_v = basepoint_v + depth - height + elseif orientation == 3 then -- weird + basepoint_h = basepoint_h + height + end + -- synch_pos_with_cur(ref_h,ref_v,basepoint_h,cur_v + basepoint_v) + if pos_r == righttoleft_code then + pos_h = ref_h - basepoint_h + else + pos_h = ref_h + basepoint_h + end + pos_v = ref_v - (cur_v + basepoint_v) + -- synced + pushorientation(orientation,pos_h,pos_v,pos_r) + if id == vlist_code then + vlist_out(current,list) + else + hlist_out(current,list) + end + poporientation(orientation,pos_h,pos_v,pos_r) + end + else + -- if synctex then + -- synch_pos_with_cur(ref_h, ref_v, cur_h, cur_v) + -- if id == vlist_code then + -- synctexvoidvlist(current, this_box) + -- else + -- synctexvoidhlist(current, this_box) + -- end + -- end + end + cur_v = cur_v + height + depth + elseif id == kern_code then + cur_v = cur_v + getkern(current) + elseif id == rule_code then + -- w h d x y = getall(current) + local width, height, depth = getwhd(current) + local total = height + depth + if total > 0 then + if width == running then + width = boxwidth + end + if width > 0 then + local xoffset, yoffset, left, right = getoffsets(current) + if left ~= 0 then + width = width - left + cur_h = cur_h + left + end + if right ~= 0 then + width = width - right + end + if pos_r == righttoleft_code then + cur_h = cur_h - width + xoffset = - xoffset + end + flushrule(current,pos_h + xoffset,pos_v - total - yoffset,pos_r,width,total) + end + cur_v = cur_v + total + end + elseif id == whatsit_code then + if subtype == literalwhatsit_code then + flushpdfliteral(current,pos_h,pos_v) + elseif subtype == lateluawhatsit_code then + flushlatelua(current,pos_h,pos_v,cur_h,cur_v) + elseif subtype == setmatrixwhatsit_code then + flushpdfsetmatrix(current,pos_h,pos_v) + elseif subtype == savewhatsit_code then + flushpdfsave(current,pos_h,pos_v) + elseif subtype == restorewhatsit_code then + flushpdfrestore(current,pos_h,pos_v) + elseif subtype == saveposwhatsit_code then + last_position_x = pos_h -- or pdf_h + last_position_y = pos_v -- or pdf_v + elseif subtype == writewhatsit_code then + flushwriteout(current) + elseif subtype == closewhatsit_code then + flushcloseout(current) + elseif subtype == openwhatsit_code then + flushopenout(current) + end + end + -- synch_pos_with_cur(ref_h, ref_v, cur_h, cur_v) + if pos_r == righttoleft_code then + pos_h = ref_h - cur_h + else + pos_h = ref_h + cur_h + end + pos_v = ref_v - cur_v + -- synced + end + -- if synctex then + -- synctextsilh(this_box) + -- end + pos_h = ref_h + pos_v = ref_v + pos_r = ref_r + end + +end + +function lpdf.convert(box,smode,objnum,specification) -- temp name + + if box then + box = tonut(box) + else + report("error in converter, no box") + return + end + + local driver = instances.pdf + if driver then + -- tracing + else + return + end + + local actions = driver.actions + local flushers = driver.flushers + + initialize = actions.initialize + finalize = actions.finalize + updatefontstate = actions.updatefontstate + + pushorientation = flushers.pushorientation + poporientation = flushers.poporientation + + flushcharacter = flushers.character + flushrule = flushers.rule + flushsimplerule = flushers.simplerule + flushspecial = flushers.special + flushpdfliteral = flushers.pdfliteral + flushpdfsetmatrix = flushers.pdfsetmatrix + flushpdfsave = flushers.pdfsave + flushpdfrestore = flushers.pdfrestore + flushpdfimage = flushers.pdfimage + + reset_dir_stack() + reset_state() + + shippingmode = smode + + -- synctex = texget("synctex") + + -- if synctex then + -- synctexsheet(1000) + -- end + + local width, height, depth = getwhd(box) + + local total = height + depth + + ----- v_offset_par = 0 + ----- h_offset_par = 0 + + local max_v = total -- + v_offset_par + local max_h = width -- + h_offset_par + + if height > maxdimen or depth > maxdimen or width > maxdimen then + goto DONE + end + + if max_v > maxdimen then + goto DONE + elseif max_v > abs_max_v then + abs_max_v = max_v + end + + if max_h > maxdimen then + goto DONE + elseif max_h > abs_max_h then + abs_max_h = max_h + end + + if shippingmode == "page" then + + -- We have zero offsets in ConTeXt. + + local pagewidth, pageheight = getpagedimensions() + -- local h_offset_par, v_offset_par = texget("hoffset"), texget("voffset") + + -- page_h_origin = trueinch + -- page_v_origin = trueinch + + pos_r = lefttoright_code + + if pagewidth > 0 then + page_size_h = pagewidth + else + page_size_h = width + end + + if page_size_h == 0 then + page_size_h = width + end + + if pageheight > 0 then + page_size_v = pageheight + else + page_size_v = total + end + + if page_size_v == 0 then + page_size_v = total + end + + local refpoint_h = 0 -- + page_h_origin + h_offset_par + local refpoint_v = page_size_v -- - page_v_origin - v_offset_par + + -- synch_pos_with_cur(refpoint_h,refpoint_v,0,height) + if pos_r == righttoleft_code then + pos_h = refpoint_h + else + pos_h = refpoint_h + end + pos_v = refpoint_v - height + -- synced + + else + + -- page_h_origin = 0 + -- page_v_origin = 0 + page_size_h = width + page_size_v = total + pos_r = getdirection(box) + pos_v = depth + pos_h = pos_r == righttoleft_code and width or 0 + + end + + shipbox_ref_h = pos_h + shipbox_ref_v = pos_v + + initialize { + shippingmode = smode, -- target + boundingbox = { 0, 0, page_size_h, page_size_v }, + objectnumber = objnum, + } + + if getid(box) == vlist_code then + vlist_out(box) + else + hlist_out(box) + end + + ::DONE:: + + -- if synctex then + -- synctexteehs() + -- end + + finalize(objnum,specification) + shippingmode = "none" +end + +-- This will move to back-out.lua eventually. + +do + + ----- sortedhash = table.sortedhash + + ----- tonut = nodes.tonut + local properties = nodes.properties.data + local flush = texio.write_nl + + local periods = utilities.strings.newrepeater(".") + + local function showdetails(n,l) + local p = properties[tonut(n)] + if p then + local done = false + for k, v in sortedhash(p) do + if done then + flush("\n") + else + done = true + end + flush(periods[l+1] .. " " .. k .. " = " .. tostring(v)) + end + end + end + + local whatsittracers = { + latelua = showdetails, + literal = showdetails, + } + + callback.register("show_whatsit",function(n,l) + local s = nodes.whatsitcodes[n.subtype] + texio.write(" [" .. s .. "]") + local w = whatsittracers[s] + if w then + w(n,l) + end + end) + +end diff --git a/tex/context/base/mkiv/driv-shp.mkiv b/tex/context/base/mkiv/driv-shp.mkiv new file mode 100644 index 000000000..031d0265f --- /dev/null +++ b/tex/context/base/mkiv/driv-shp.mkiv @@ -0,0 +1,28 @@ +%D \module +%D [ file=driv-shp, +%D version=2018.07.26, +%D title=\CONTEXT\ Driver Macros, +%D subtitle=Shipout, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\ifcase\contextlmtxmode\expandafter\endinput\fi + +\unprotect + +\registerctxluafile{driv-shp}{optimize} + +\registerctxluafile{back-lpd}{optimize} +\registerctxluafile{back-lua}{optimize} +\registerctxluafile{back-mps}{optimize} + +\appendtoks + \clf_enabledriver{pdf}% for now this way +\to \everyjob + +\protect \endinput diff --git a/tex/context/base/mkiv/font-cff.lua b/tex/context/base/mkiv/font-cff.lua index 75486624b..46deedb5f 100644 --- a/tex/context/base/mkiv/font-cff.lua +++ b/tex/context/base/mkiv/font-cff.lua @@ -1950,7 +1950,8 @@ end -- 1, -- 1 -- else - local g, l = #globals, #locals + local g = #globals + local l = #locals return ((g < 1240 and 107) or (g < 33900 and 1131) or 32768) + 1, ((l < 1240 and 107) or (l < 33900 and 1131) or 32768) + 1 diff --git a/tex/context/base/mkiv/font-cft.lua b/tex/context/base/mkiv/font-cft.lua index 2e1610f17..ee9ffa6a7 100644 --- a/tex/context/base/mkiv/font-cft.lua +++ b/tex/context/base/mkiv/font-cft.lua @@ -242,7 +242,6 @@ do hasitalics = t_boolean, autoitalicamount = t_float, nostackmath = t_boolean, - noglyphnames = t_boolean, mode = t_string, hasmath = t_boolean, mathitalics = t_boolean, diff --git a/tex/context/base/mkiv/font-con.lua b/tex/context/base/mkiv/font-con.lua index 9f85ee208..93ce9f5da 100644 --- a/tex/context/base/mkiv/font-con.lua +++ b/tex/context/base/mkiv/font-con.lua @@ -547,7 +547,6 @@ function constructors.scale(tfmdata,specification) local hasitalics = properties.hasitalics local autoitalicamount = properties.autoitalicamount local stackmath = not properties.nostackmath - local nonames = properties.noglyphnames local haskerns = properties.haskerns or properties.mode == "base" -- we can have afm in node mode local hasligatures = properties.hasligatures or properties.mode == "base" -- we can have afm in node mode local realdimensions = properties.realdimensions @@ -677,9 +676,10 @@ function constructors.scale(tfmdata,specification) description = descriptions[unicode] or character index = description.index or unicode end - local width = description.width - local height = description.height - local depth = description.depth + local width = description.width + local height = description.height + local depth = description.depth + local isunicode = description.unicode if realdimensions then -- this is mostly for checking issues if not height or height == 0 then @@ -706,16 +706,16 @@ function constructors.scale(tfmdata,specification) -- if depth then depth = vdelta*depth else depth = scaleddepth end if depth and depth ~= 0 then depth = delta*depth - if nonames then + if isunicode then chr = { - index = index, - height = height, - depth = depth, - width = width, + index = index, + height = height, + depth = depth, + width = width, + unicode = isunicode, } else chr = { - name = description.name, index = index, height = height, depth = depth, @@ -723,36 +723,23 @@ function constructors.scale(tfmdata,specification) } end else - -- this saves a little bit of memory time and memory, esp for big cjk fonts - if nonames then + if isunicode then chr = { - index = index, - height = height, - width = width, + index = index, + height = height, + width = width, + unicode = isunicode, } else chr = { - name = description.name, index = index, height = height, width = width, } end end - local isunicode = description.unicode if addtounicode then - if isunicode then - chr.unicode = isunicode - chr.tounicode = tounicode(isunicode) - -- in luatex > 0.85 we can do this: - -- chr.tounicode = isunicode - else - chr.tounicode = unknowncode - end - else - if isunicode then - chr.unicode = isunicode - end + chr.tounicode = isunicode and tounicode(isunicode) or unknowncode end if hasquality then -- we could move these calculations elsewhere (saves calculations) @@ -827,7 +814,10 @@ function constructors.scale(tfmdata,specification) if stackmath then local mk = character.mathkerns if mk then - local tr, tl, br, bl = mk.topright, mk.topleft, mk.bottomright, mk.bottomleft + local tr = mk.topright + local tl = mk.topleft + local br = mk.bottomright + local bl = mk.bottomleft chr.mathkern = { -- singular -> should be patched in luatex ! top_right = tr and mathkerns(tr,vdelta) or nil, top_left = tl and mathkerns(tl,vdelta) or nil, @@ -1174,7 +1164,9 @@ loose our testcases for <l n='luatex'/>.</p> --ldx]]-- function constructors.hashinstance(specification,force) - local hash, size, fallbacks = specification.hash, specification.size, specification.fallbacks + local hash = specification.hash + local size = specification.size + local fallbacks = specification.fallbacks if force or not hash then hash = constructors.hashfeatures(specification) specification.hash = hash @@ -1612,7 +1604,8 @@ end -- while typesetting function constructors.collectprocessors(what,tfmdata,features,trace,report) - local processes, nofprocesses = { }, 0 + local processes = { } + local nofprocesses = 0 if features and next(features) then local properties = tfmdata.properties local whathandler = handlers[what] diff --git a/tex/context/base/mkiv/font-ctx.lua b/tex/context/base/mkiv/font-ctx.lua index 98825c3b6..6847a2b8d 100644 --- a/tex/context/base/mkiv/font-ctx.lua +++ b/tex/context/base/mkiv/font-ctx.lua @@ -793,7 +793,8 @@ end local function registercontext(fontnumber,extraname,option) local extra = setups[extraname] if extra then - local mergedfeatures, mergedname = { }, nil + local mergedfeatures = { } + local mergedname = nil if option < 0 then mergedname = fontnumber .. "-" .. extraname else @@ -3297,7 +3298,8 @@ function fonts.helpers.collectanchors(tfmdata) a[target] = { anchor } return end - local x, y = anchor[1], anchor[2] + local x = anchor[1] + local y = anchor[2] for k, v in next, t do if v[1] == x and v[2] == y then return diff --git a/tex/context/base/mkiv/font-dsp.lua b/tex/context/base/mkiv/font-dsp.lua index c5fb14d46..f8bf6f2c8 100644 --- a/tex/context/base/mkiv/font-dsp.lua +++ b/tex/context/base/mkiv/font-dsp.lua @@ -3502,14 +3502,15 @@ function readers.avar(f,fontdata,specification) local lastfrom = false local lastto = false for i=1,nofvalues do - local f, t = read2dot14(f), read2dot14(f) - if lastfrom and f <= lastfrom then + local from = read2dot14(f) + local to = read2dot14(f) + if lastfrom and from <= lastfrom then -- ignore - elseif lastto and t >= lastto then + elseif lastto and to >= lastto then -- ignore else - values[#values+1] = { f, t } - lastfrom, lastto = f, t + values[#values+1] = { from, to } + lastfrom, lastto = from, to end end nofvalues = #values diff --git a/tex/context/base/mkiv/font-fbk.lua b/tex/context/base/mkiv/font-fbk.lua index cf500d0ce..122e43ddc 100644 --- a/tex/context/base/mkiv/font-fbk.lua +++ b/tex/context/base/mkiv/font-fbk.lua @@ -115,9 +115,15 @@ local function composecharacters(tfmdata) local ab = descriptions[acc].boundingbox -- todo: adapt height if cb and ab then - local c_llx, c_lly, c_urx, c_ury = scale*cb[1], scale*cb[2], scale*cb[3], scale*cb[4] - local a_llx, a_lly, a_urx, a_ury = scale*ab[1], scale*ab[2], scale*ab[3], scale*ab[4] - local done = false + local c_llx = scale*cb[1] + local c_lly = scale*cb[2] + local c_urx = scale*cb[3] + local c_ury = scale*cb[4] + local a_llx = scale*ab[1] + local a_lly = scale*ab[2] + local a_urx = scale*ab[3] + local a_ury = scale*ab[4] + local done = false if compose then local i_compose = compose[i] local i_anchored = i_compose and i_compose.anchored diff --git a/tex/context/base/mkiv/font-fil.mkvi b/tex/context/base/mkiv/font-fil.mkvi index ff6a46d73..ae83ef4c4 100644 --- a/tex/context/base/mkiv/font-fil.mkvi +++ b/tex/context/base/mkiv/font-fil.mkvi @@ -85,33 +85,53 @@ \expandafter\font_basics_define_font_synonym_yes \fi} -\def\font_basics_define_font_synonym_nop +\unexpanded\def\font_basics_define_font_synonym_nop {\expandafter\let\csname\??fontfile\m_font_name\endcsname\m_font_file \doifelsenextoptionalcs\font_basics_define_font_synonym_nop_opt\font_basics_define_font_synonym_nop_nil} -\def\font_basics_define_font_synonym_yes +\unexpanded\def\font_basics_define_font_synonym_yes {\expandafter\let\csname\??fontfile\fontclass\m_font_name\endcsname\m_font_file \doifelsenextoptionalcs\font_basics_define_font_synonym_yes_opt\font_basics_define_font_synonym_yes_nil} -\def\font_basics_define_font_synonym_nop_opt[#specification]% +\unexpanded\def\edefinefontsynonym[#name]#crap[#file]% + {\edef\m_font_name{#name}% + \edef\m_font_file{#file}% + \ifx\fontclass\empty + \expandafter\font_basics_define_font_synonym_nop_expanded + \else + \expandafter\font_basics_define_font_synonym_yes_expanded + \fi} + +\unexpanded\def\font_basics_define_font_synonym_nop_expanded#crap[#spec]% + {\expandafter\let\csname\??fontfile\m_font_name\endcsname\m_font_file + \normalexpanded{\font_basics_define_font_synonym_nop_opt[#1]}} + +\unexpanded\def\font_basics_define_font_synonym_yes_expanded#crap[#spec]% + {\expandafter\let\csname\??fontfile\fontclass\m_font_name\endcsname\m_font_file + \normalexpanded{\font_basics_define_font_synonym_yes_opt[#spec]}} + +\unexpanded\def\font_basics_define_font_synonym_nop_opt[#specification]% {\let\p_features \undefined \let\p_fallbacks \undefined \let\p_goodies \undefined \let\p_designsize\undefined \expandafter\font_basics_get_font_parameter_nop#specification,]=,} -\def\font_basics_define_font_synonym_yes_opt[#specification]% +\unexpanded\def\font_basics_define_font_synonym_yes_opt[#specification]% {\let\p_features \undefined \let\p_fallbacks \undefined \let\p_goodies \undefined \let\p_designsize\undefined \expandafter\font_basics_get_font_parameter_yes#specification,]=,} +% todo: check if we can use \edef but then we need to protect \mathsizesuffix .. in fact that +% can be default then: \let\mathsizesuffix\relax .. i need to play with it first + \def\font_basics_get_font_parameter_nop#key=#value,% {\if]#key% \font_basics_get_font_parameter_nop_finish \else - \expandafter\normaledef\csname p_#key\endcsname{#value}% + \expandafter\normaldef\csname p_#key\endcsname{#value}% % no edef as we need to keep \mathsizesuffix \expandafter\font_basics_get_font_parameter_nop \fi} @@ -119,7 +139,7 @@ {\if]#key% \font_basics_get_font_parameter_yes_finish \else - \expandafter\normaledef\csname p_#key\endcsname{#value}% + \expandafter\normaldef\csname p_#key\endcsname{#value}% % no edef as we need to keep \mathsizesuffix \expandafter\font_basics_get_font_parameter_yes \fi} diff --git a/tex/context/base/mkiv/font-imp-quality.lua b/tex/context/base/mkiv/font-imp-quality.lua index 224d8dc27..01f0afe63 100644 --- a/tex/context/base/mkiv/font-imp-quality.lua +++ b/tex/context/base/mkiv/font-imp-quality.lua @@ -451,9 +451,12 @@ local function initialize(tfmdata,value) right = right, } for i, chr in next, tfmdata.characters do - local v, pl, pr = vector[i], nil, nil + local v = vector[i] + local pl = nil + local pr = nil if v then - pl, pr = v[1], v[2] + pl = v[1] + pr = v[2] else local d = data[i] if d then @@ -461,13 +464,15 @@ local function initialize(tfmdata,value) if not s then -- sorry elseif type(s) == "table" then - local vl, vr = vector[s[1]], vector[s[#s]] + local vl = vector[s[1]] + local vr = vector[s[#s]] if vl then pl = vl[1] end if vr then pr = vr[2] end else v = vector[s] if v then - pl, pr = v[1], v[2] + pl = v[1] + pr = v[2] end end end diff --git a/tex/context/base/mkiv/font-lib.mkvi b/tex/context/base/mkiv/font-lib.mkvi index 3cff81751..081ae0f38 100644 --- a/tex/context/base/mkiv/font-lib.mkvi +++ b/tex/context/base/mkiv/font-lib.mkvi @@ -50,6 +50,7 @@ \registerctxluafile{font-otc}{} \registerctxluafile{font-oth}{} \registerctxluafile{font-osd}{} +% \doifelsefileexists{font-osm.lua}{\registerctxluafile{font-osm}{}}{} \registerctxluafile{font-ocl}{} % we use otf code for type one diff --git a/tex/context/base/mkiv/font-map.lua b/tex/context/base/mkiv/font-map.lua index 7dd538858..d931b822e 100644 --- a/tex/context/base/mkiv/font-map.lua +++ b/tex/context/base/mkiv/font-map.lua @@ -523,7 +523,8 @@ function mappings.addtounicode(data,filename,checklookups,forceligatures) glyph.unicode = unicode end else - local t, n = { }, 0 + local t = { } + local n = 0 for l=1,nsplit do local base = split[l] local u = unicodes[base] or unicodevector[base] or contextvector[name] diff --git a/tex/context/base/mkiv/font-mps.lua b/tex/context/base/mkiv/font-mps.lua index 6d4da9059..895835958 100644 --- a/tex/context/base/mkiv/font-mps.lua +++ b/tex/context/base/mkiv/font-mps.lua @@ -109,9 +109,12 @@ function metapost.paths(d,xfactor,yfactor) elseif operator =="q" then -- "quadraticto" size = size + 1 -- first is always a moveto - local l_x, l_y = xfactor*sequence[i-2], yfactor*sequence[i-1] - local m_x, m_y = xfactor*sequence[i+1], yfactor*sequence[i+2] - local r_x, r_y = xfactor*sequence[i+3], yfactor*sequence[i+4] + local l_x = xfactor*sequence[i-2] + local l_y = yfactor*sequence[i-1] + local m_x = xfactor*sequence[i+1] + local m_y = yfactor*sequence[i+2] + local r_x = xfactor*sequence[i+3] + local r_y = yfactor*sequence[i+4] path[size] = f_curveto ( l_x + 2/3 * (m_x-l_x), l_y + 2/3 * (m_y-l_y), @@ -149,9 +152,12 @@ function metapost.paths(d,xfactor,yfactor) size = size + 1 -- first is always a moveto local prev = segments[i-1] - local l_x, l_y = xfactor*prev[#prev-2], yfactor*prev[#prev-1] - local m_x, m_y = xfactor*segment[1], yfactor*segment[2] - local r_x, r_y = xfactor*segment[3], yfactor*segment[4] + local l_x = xfactor*prev[#prev-2] + local l_y = yfactor*prev[#prev-1] + local m_x = xfactor*segment[1] + local m_y = yfactor*segment[2] + local r_x = xfactor*segment[3] + local r_y = yfactor*segment[4] path[size] = f_curveto ( l_x + 2/3 * (m_x-l_x), l_y + 2/3 * (m_y-l_y), @@ -208,7 +214,10 @@ function metapost.maxbounds(data,index,factor) local boundingbox = glyph.boundingbox local xmin, ymin, xmax, ymax if not maxbounds then - xmin, ymin, xmax, ymax = 0, 0, 0, 0 + xmin = 0 + ymin = 0 + xmax = 0 + ymax = 0 for i=1,#glyphs do local d = glyphs[i] if d then diff --git a/tex/context/base/mkiv/font-nod.lua b/tex/context/base/mkiv/font-nod.lua index 6beaef469..a0eb88a25 100644 --- a/tex/context/base/mkiv/font-nod.lua +++ b/tex/context/base/mkiv/font-nod.lua @@ -112,7 +112,8 @@ end function char_tracers.collect(head,list,tag,n) n = n or 0 - local ok, fn = false, nil + local ok = false + local fn = nil while head do local char, id = isglyph(head) if char then @@ -159,7 +160,8 @@ function char_tracers.equal(ta, tb) return false else for i=1,#ta do - local a, b = ta[i], tb[i] + local a = ta[i] + local b = tb[i] -- if a[1] ~= b[1] or a[2] ~= b[2] or a[3] ~= b[3] then if a[1] ~= b[1] or a[2] ~= b[2] then return false diff --git a/tex/context/base/mkiv/font-one.lua b/tex/context/base/mkiv/font-one.lua index 48bf117fe..9b296cac5 100644 --- a/tex/context/base/mkiv/font-one.lua +++ b/tex/context/base/mkiv/font-one.lua @@ -86,14 +86,16 @@ function afm.load(filename) local name = file.removesuffix(file.basename(filename)) local data = containers.read(afm.cache,name) local attr = lfs.attributes(filename) - local size, time = attr and attr.size or 0, attr and attr.modification or 0 + local size = attr and attr.size or 0 + local time = attr and attr.modification or 0 -- local pfbfile = file.replacesuffix(name,"pfb") local pfbname = resolvers.findfile(pfbfile,"pfb") or "" if pfbname == "" then pfbname = resolvers.findfile(file.basename(pfbfile),"pfb") or "" end - local pfbsize, pfbtime = 0, 0 + local pfbsize = 0 + local pfbtime = 0 if pfbname ~= "" then local attr = lfs.attributes(pfbname) pfbsize = attr.size or 0 @@ -324,7 +326,8 @@ local addthem = function(rawdata,ligatures) local one = descriptions[unicodes[ligname]] if one then for _, pair in next, ligdata do - local two, three = unicodes[pair[1]], unicodes[pair[2]] + local two = unicodes[pair[1]] + local three = unicodes[pair[2]] if two and three then local ol = one.ligatures if ol then @@ -392,7 +395,7 @@ local function enhance_add_extra_kerns(rawdata) -- using shcodes is not robust h if what then for complex, simple in next, what do complex = unicodes[complex] - simple = unicodes[simple] + simple = unicodes[simple] if complex and simple then local complexdescription = descriptions[complex] if complexdescription then -- optional @@ -445,7 +448,8 @@ local function adddimensions(data) -- we need to normalize afm to otf i.e. index for unicode, description in next, data.descriptions do local bb = description.boundingbox if bb then - local ht, dp = bb[4], -bb[2] + local ht = bb[4] + local dp = -bb[2] if ht == 0 or ht < 0 then -- no need to set it and no negative heights, nil == 0 else @@ -757,7 +761,7 @@ local function check_afm(specification,fullname) if foundname == "" then foundname = fonts.names.getfilename(fullname,"afm") or "" end - if foundname == "" and afm.autoprefixed then + if fullname and foundname == "" and afm.autoprefixed then local encoding, shortname = match(fullname,"^(.-)%-(.*)$") -- context: encoding-name.* if encoding and shortname and fonts.encodings.known[encoding] then shortname = findbinfile(shortname,'afm') or "" -- just to be sure diff --git a/tex/context/base/mkiv/font-osd.lua b/tex/context/base/mkiv/font-osd.lua index 32d791b48..f51ae7bf7 100644 --- a/tex/context/base/mkiv/font-osd.lua +++ b/tex/context/base/mkiv/font-osd.lua @@ -615,6 +615,8 @@ local function initializedevanagi(tfmdata) end end -- + -- needs checking: this might be needed per instance ? + -- if script == "deva" then sharedfeatures["dv04"] = true -- dv04_remove_joiners elseif script == "dev2" then @@ -689,7 +691,7 @@ local function initialize_one(font,attr) -- we need a proper hook into the datas if not devanagaridata then - devanagaridata = { + devanagaridata = { reph = false, vattu = false, blwfcache = { }, @@ -1329,7 +1331,7 @@ end function handlers.devanagari_remove_joiners(head,start,kind,lookupname,replacement) local stop = getnext(start) - local font = getfont(start) + local font = getfont(start) -- hm local last = start while stop do local char = ischar(stop,font) diff --git a/tex/context/base/mkiv/font-ota.lua b/tex/context/base/mkiv/font-ota.lua index a0bf616e7..76c267a81 100644 --- a/tex/context/base/mkiv/font-ota.lua +++ b/tex/context/base/mkiv/font-ota.lua @@ -302,9 +302,9 @@ if not classifiers then end function methods.arab(head,font,attr) - local first, last = nil, nil - local c_first, c_last = nil, nil - local current, done = head, false + local first, last, c_first, c_last + local current = head + local done = false current = tonut(current) while current do local char, id = ischar(current,font) diff --git a/tex/context/base/mkiv/font-otc.lua b/tex/context/base/mkiv/font-otc.lua index 595778e34..a774a81c2 100644 --- a/tex/context/base/mkiv/font-otc.lua +++ b/tex/context/base/mkiv/font-otc.lua @@ -278,7 +278,8 @@ local function addfeature(data,feature,specifications) if not nocheck and not description then skip = skip + 1 elseif type(replacement) == "table" then - local r, n = { }, 0 + local r = { } + local n = 0 for i=1,#replacement do local u = tounicode(replacement[i]) if nocheck or descriptions[u] then diff --git a/tex/context/base/mkiv/font-otj.lua b/tex/context/base/mkiv/font-otj.lua index df9756f4e..bb3038935 100644 --- a/tex/context/base/mkiv/font-otj.lua +++ b/tex/context/base/mkiv/font-otj.lua @@ -456,7 +456,8 @@ function injections.setmove(current,factor,rlmode,x,injection) end function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk,checkmark) -- ba=baseanchor, ma=markanchor - local dx, dy = factor*(ba[1]-ma[1]), factor*(ba[2]-ma[2]) + local dx = factor*(ba[1]-ma[1]) + local dy = factor*(ba[2]-ma[2]) nofregisteredmarks = nofregisteredmarks + 1 if rlmode >= 0 then dx = tfmbase.width - dx -- see later commented ox diff --git a/tex/context/base/mkiv/font-otl.lua b/tex/context/base/mkiv/font-otl.lua index df83dc968..6e0939e76 100644 --- a/tex/context/base/mkiv/font-otl.lua +++ b/tex/context/base/mkiv/font-otl.lua @@ -495,7 +495,6 @@ local function copytotfm(data,cache_id) properties.space = spacer properties.encodingbytes = 2 properties.format = data.format or formats.otf - properties.noglyphnames = true properties.filename = filename properties.fontname = fontname properties.fullname = fullname diff --git a/tex/context/base/mkiv/font-oto.lua b/tex/context/base/mkiv/font-oto.lua index c32a7af25..6f6d89d43 100644 --- a/tex/context/base/mkiv/font-oto.lua +++ b/tex/context/base/mkiv/font-oto.lua @@ -49,7 +49,9 @@ local function gref(descriptions,n) return f_unicode(n) end elseif n then - local num, nam, j = { }, { }, 0 + local num = { } + local nam = { } + local j = 0 for i=1,#n do local ni = n[i] if tonumber(ni) then -- first is likely a key @@ -121,8 +123,8 @@ local basehash, basehashes, applied = { }, 1, { } local function registerbasehash(tfmdata) local properties = tfmdata.properties - local hash = concat(applied," ") - local base = basehash[hash] + local hash = concat(applied," ") + local base = basehash[hash] if not base then basehashes = basehashes + 1 base = basehashes @@ -310,13 +312,16 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis for i=1,nofligatures do local ligature = ligatures[i] - local unicode, tree = ligature[1], ligature[2] + local unicode = ligature[1] + local tree = ligature[2] make_1(present,tree,"ctx_"..unicode) end for i=1,nofligatures do - local ligature = ligatures[i] - local unicode, tree, lookupname = ligature[1], ligature[2], ligature[3] + local ligature = ligatures[i] + local unicode = ligature[1] + local tree = ligature[2] + local lookupname = ligature[3] make_2(present,tfmdata,characters,tree,"ctx_"..unicode,unicode,unicode,done,sequence) end diff --git a/tex/context/base/mkiv/font-otr.lua b/tex/context/base/mkiv/font-otr.lua index c7ff6b726..e851c3157 100644 --- a/tex/context/base/mkiv/font-otr.lua +++ b/tex/context/base/mkiv/font-otr.lua @@ -74,7 +74,6 @@ local lpegmatch = lpeg.match local rshift = bit32.rshift local setmetatableindex = table.setmetatableindex -local formatters = string.formatters local sortedkeys = table.sortedkeys local sortedhash = table.sortedhash local stripstring = string.nospaces diff --git a/tex/context/base/mkiv/font-ots.lua b/tex/context/base/mkiv/font-ots.lua index 4d011a934..b9f719a5f 100644 --- a/tex/context/base/mkiv/font-ots.lua +++ b/tex/context/base/mkiv/font-ots.lua @@ -829,7 +829,7 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip end end if not match and not pre or not replace then - local n = getnext(discfound) + local n = getnext(discfound) local char = ischar(n,currentfont) if char and ligature[char] then match = true @@ -841,8 +841,8 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip local prev = getprev(start) if stop then setnext(stop) - local tail = getprev(stop) local copy = copy_node_list(start) + local tail = stop -- was: getprev(stop) -- Kai: needs checking on your samples local liat = find_node_tail(copy) if pre then setlink(liat,pre) @@ -939,7 +939,8 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,skiphash,st end local format = step.format if format == "pair" then - local a, b = krn[1], krn[2] + local a = krn[1] + local b = krn[2] if a == true then -- zero elseif a then -- #a > 0 @@ -1559,7 +1560,8 @@ function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlm end local format = currentlookup.format if format == "pair" then - local a, b = krn[1], krn[2] + local a = krn[1] + local b = krn[2] if a == true then -- zero elseif a then @@ -3192,7 +3194,7 @@ local function testrun(disc,t_run,c_run,...) local d = d_replace > d_post and d_replace or d_post local head = getnext(disc) -- is: next local tail = head - for i=2,d do -- must start at 2 according to Kai + for i=2,d do -- must start at 2 according to Kai local nx = getnext(tail) local id = getid(nx) if id == disc_code then diff --git a/tex/context/base/mkiv/font-oup.lua b/tex/context/base/mkiv/font-oup.lua index e7f483642..d1faadbf7 100644 --- a/tex/context/base/mkiv/font-oup.lua +++ b/tex/context/base/mkiv/font-oup.lua @@ -1466,7 +1466,9 @@ function readers.pack(data) end return false elseif nt >= threshold then - local one, two, rest = 0, 0, 0 + local one = 0 + local two = 0 + local rest = 0 if pass == 1 then for k,v in next, c do if v == 1 then diff --git a/tex/context/base/mkiv/font-shp.lua b/tex/context/base/mkiv/font-shp.lua index 08eda9fdb..d5c194c85 100644 --- a/tex/context/base/mkiv/font-shp.lua +++ b/tex/context/base/mkiv/font-shp.lua @@ -389,9 +389,12 @@ local function segmentstopdf(segments,factor,bt,et) elseif w == "q" then local p = segments[i-1] local n = #p - local l_x, l_y = factor*p[n-2], factor*p[n-1] - local m_x, m_y = factor*s[1], factor*s[2] - local r_x, r_y = factor*s[3], factor*s[4] + local l_x = factor*p[n-2] + local l_y = factor*p[n-1] + local m_x = factor*s[1] + local m_y = factor*s[2] + local r_x = factor*s[3] + local r_y = factor*s[4] m = m + 1 t[m] = f_c ( l_x + 2/3 * (m_x-l_x), l_y + 2/3 * (m_y-l_y), diff --git a/tex/context/base/mkiv/font-sol.lua b/tex/context/base/mkiv/font-sol.lua index c7bd5feca..002f9df13 100644 --- a/tex/context/base/mkiv/font-sol.lua +++ b/tex/context/base/mkiv/font-sol.lua @@ -348,8 +348,14 @@ directives.register("builders.paragraphs.solutions.splitters.encapsulate", funct end) function splitters.split(head) -- best also pass the direction - local current, r2l, start, stop, attribute = head, false, nil, nil, 0 - cache, max_less, max_more = { }, 0, 0 + local current = head + local r2l = false + local start = nil + local stop = nil + local attribute = 0 + cache = { } + max_less = 0 + max_more = 0 local function flush() -- we can move this local font = getfont(start) local last = getnext(stop) @@ -445,12 +451,14 @@ function splitters.split(head) -- best also pass the direction flush() end nofparagraphs = nofparagraphs + 1 - nofwords = nofwords + #cache + nofwords = nofwords + #cache return head end local function collect_words(list) -- can be made faster for attributes - local words, w, word = { }, 0, nil + local words = { } + local w = 0 + local word = nil if encapsulate then for current, subtype in nextwhatsit, list do if subtype == userdefinedwhatsit_code then -- hm @@ -472,7 +480,8 @@ local function collect_words(list) -- can be made faster for attributes end end else - local current, first, last, index = list, nil, nil, nil + local first, last, index + local current = list while current do -- todo: disc and kern local id = getid(current) @@ -537,7 +546,9 @@ local function collect_words(list) -- can be made faster for attributes if trace_split then for i=1,#words do local w = words[i] - local n, f, l = w[1], w[2], w[3] + local n = w[1] + local f = w[2] + local l = w[3] local c = cache[n] if c then report_splitters("found %4i: word %a, cached %a",n,nodes_to_utf(f,true,true,l),nodes_to_utf(c.original,true)) @@ -793,7 +804,8 @@ function splitters.optimize(head) set, max = "less", max_less end -- we can keep the best variants - local lastbest, lastbadness = nil, badness + local lastbest = nil + local lastbadness = badness if preroll then local bb, base for i=1,max do @@ -866,7 +878,7 @@ statistics.register("optimizer statistics", function() if nofwords > 0 then local elapsed = statistics.elapsedtime(splitters) local average = noftries/elapsed - return format("%s words identified in %s paragraphs, %s words retried, %s lines tried, %0.3f seconds used, %s adapted, %0.1f lines per second", + return format("%s words identified in %s paragraphs, %s words retried, %s lines tried, %s seconds used, %s adapted, %0.1f lines per second", nofwords,nofparagraphs,noftries,nofadapted+nofkept,elapsed,nofadapted,average) end end) diff --git a/tex/context/base/mkiv/font-syn.lua b/tex/context/base/mkiv/font-syn.lua index 3951e8742..18c25fbfd 100644 --- a/tex/context/base/mkiv/font-syn.lua +++ b/tex/context/base/mkiv/font-syn.lua @@ -515,15 +515,20 @@ local function cleanname(name) end local function cleanfilename(fullname,defaultsuffix) - local path, name, suffix = splitname(fullname) - name = gsub(lower(name),"[^%a%d]","") - if suffix and suffix ~= "" then - return name .. ".".. suffix - elseif defaultsuffix and defaultsuffix ~= "" then - return name .. ".".. defaultsuffix - else - return name + if fullname then + local path, name, suffix = splitname(fullname) + if name then + name = gsub(lower(name),"[^%a%d]","") + if suffix and suffix ~= "" then + return name .. ".".. suffix + elseif defaultsuffix and defaultsuffix ~= "" then + return name .. ".".. defaultsuffix + else + return name + end + end end + return "badfontname" end local sorter = function(a,b) @@ -2009,7 +2014,8 @@ local lastlookups, lastpattern = { }, "" local function look_them_up(lookups,specification) for key, value in sortedhash(specification) do - local t, n = { }, 0 + local t = { } + local n = 0 if find(value,"*",1,true) then value = topattern(value) for i=1,#lookups do diff --git a/tex/context/base/mkiv/font-tpk.lua b/tex/context/base/mkiv/font-tpk.lua new file mode 100644 index 000000000..8f4b00b56 --- /dev/null +++ b/tex/context/base/mkiv/font-tpk.lua @@ -0,0 +1,1292 @@ + if not modules then modules = { } end modules ['font-tpk'] = { + version = 1.001, + comment = "companion to font-lib.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- The bitmap loader is more or less derived from the luatex version (taco) +-- which is derived from pdftex (thanh) who uses code from dvips (thomas) +-- adapted by piet ... etc. The tfm and vf readers are also derived from +-- luatex. All do things a bit more luaish and errors are of course mine. + +local next = next +local extract, band, lshift, rshift = bit32.extract, bit32.band, bit32.lshift, bit32.rshift +local idiv = number.idiv +local char = string.char +local concat, insert, remove, copy = table.concat, table.insert, table.remove, table.copy +local tobitstring = number.tobitstring +local formatters = string.formatters +local round = math.round + +local streams = utilities.streams +local openstream = streams.open +local streamsize = streams.size +local readcardinal1 = streams.readcardinal1 +local readcardinal2 = streams.readcardinal2 +local readcardinal3 = streams.readcardinal3 +local readcardinal4 = streams.readcardinal4 +local readinteger1 = streams.readinteger1 +local readinteger2 = streams.readinteger2 +local readinteger3 = streams.readinteger3 +local readinteger4 = streams.readinteger4 +local readbyte = streams.readbyte +local readbytes = streams.readbytes +local readstring = streams.readstring +local skipbytes = streams.skipbytes +local getposition = streams.getposition +local setposition = streams.setposition + +if not fonts then fonts = { handlers = { tfm = { } } } end + +local handlers = fonts.handlers +local tfm = handlers.tfm or { } +handlers.tfm = tfm +local readers = tfm.readers or { } +tfm.readers = readers + +tfm.version = 1.005 +tfm.cache = containers.define("fonts", "tfm", tfm.version, true) + +-- Performance is no real issue here so I didn't optimize too much. After +-- all, these files are small and we mostly use opentype or type1 fonts. + +do + + local function readbitmap(glyph,s,flagbyte) + + local inputbyte = 0 + local bitweight = 0 + local dynf = 0 + local remainder = 0 + local realfunc = nil + local repeatcount = 0 + + local function getnyb() -- can be inlined + if bitweight == 0 then + bitweight = 16 + inputbyte = readbyte(s) + return extract(inputbyte,4,4) + else + bitweight = 0 + return band(inputbyte,15) + end + end + + local function getbit() -- can be inlined + bitweight = rshift(bitweight,1) + if bitweight == 0 then -- actually we can check for 1 + inputbyte = readbyte(s) + bitweight = 128 + end + return band(inputbyte,bitweight) + end + + local function pkpackednum() + local i = getnyb(s) + if i == 0 then + repeat + j = getnyb() + i = i + 1 + until (j ~= 0) + if i > 3 then + return handlehuge(i,j) + else + for i=1,i do + j = j * 16 + getnyb() + end + return j - 15 + (13 - dynf) * 16 + dynf + end + elseif i <= dynf then + return i + elseif i < 14 then + return (i - dynf - 1) * 16 + getnyb() + dynf + 1 + elseif i == 14 then + repeatcount = pkpackednum() + else + repeatcount = 1 + end + return realfunc() + end + + local function rest() + if remainder < 0 then + remainder = -remainder + return 0 + elseif remainder > 4000 then + remainder = 4000 - remainder + return 4000 + elseif remainder > 0 then + local i = remainder + remainder = 0 + realfunc = pkpackednum + return i + else + -- error = "pk issue that shouldn't happen" + return 0 + end + end + + local function handlehuge(i,j) + while i ~= 0 do + j = lshift(j,4) + getnyb() + -- j = extract(j,8,4) + getnyb() + i = i - 1 + end + remainder = j - 15 + (13 - dynf) * 16 + dynf + realfunc = rest + return rest() + end + + local gpower = { [0] = + 0, 1, 3, 7, 15, 31, 63, 127, + 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, + 65535 + } + + local raster = { } + local r = 0 + glyph.stream = raster + + local xsize = glyph.xsize + local ysize = glyph.ysize + local word = 0 + local wordweight = 0 + local wordwidth = idiv(xsize + 15,16) + local rowsleft = 0 + local turnon = band(flagbyte,8) == 8 and true or false + local hbit = 0 + local count = 0 + -- + realfunc = pkpackednum + dynf = idiv(flagbyte,16) + -- + if dynf == 14 then + bitweight = 0 + for i=1,ysize do + word = 0 + wordweight = 32768 + for j=1,xsize do + if getbit() ~= 0 then + word = word + wordweight + end + wordweight = rshift(wordweight,1) + if wordweight == 0 then + r = r + 1 + raster[r] = word + word = 0 + wordweight = 32768 + end + end + if wordweight ~= 32768 then + r = r + 1 + raster[r] = word + end + end + else + rowsleft = ysize + hbit = xsize + repeatcount = 0 + wordweight = 16 + word = 0 + bitweight = 0 + while rowsleft > 0 do + count = realfunc() + while count ~= 0 do + if count < wordweight and count < hbit then + if turnon then + word = word + gpower[wordweight] - gpower[wordweight - count] + end + hbit = hbit - count + wordweight = wordweight - count + count = 0 + elseif count >= hbit and hbit <= wordweight then + if turnon then + word = word + gpower[wordweight] - gpower[wordweight - hbit] + end + r = r + 1 + raster[r] = word + for i=1,repeatcount*wordwidth do + r = r + 1 + raster[r] = raster[r - wordwidth] + end + rowsleft = rowsleft - repeatcount - 1 + repeatcount = 0 + word = 0 + wordweight = 16 + count = count - hbit + hbit = xsize + else + if turnon then + word = word + gpower[wordweight] + end + r = r + 1 + raster[r] = word + word = 0 + count = count - wordweight + hbit = hbit - wordweight + wordweight = 16 + end + end + turnon = not turnon + end + if rowsleft ~= 0 or hbit ~= xsize then + print("ERROR",rowsleft,hbit,xsize) + -- error = "error while unpacking, more bits than required" + end + end + + end + + function readers.showpk(glyph) + local xsize = glyph.xsize + local ysize = glyph.ysize + local stream = glyph.stream + local result = { } + local rr = { } + local r = 0 + local s = 0 + local cw = idiv(xsize+ 7, 8) + local rw = idiv(xsize+15,16) + local extra = 2 * rw == cw + local b + for y=1,ysize do + r = 0 + for x=1,rw-1 do + s = s + 1 ; b = stream[s] + r = r + 1 ; rr[r] = tobitstring(b,16,16) + end + s = s + 1 ; b = stream[s] + if extra then + r = r + 1 ; rr[r] = tobitstring(b,16,16) + else + r = r + 1 ; rr[r] = tobitstring(extract(b,8+(8-cw),cw),cw,cw) + end + result[y] = concat(rr) + end + return concat(result,"\n") + end + + local template = formatters [ [[ + %.3N 0 %i %i %i %i d1 + q + %i 0 0 %i %i %i cm + BI + /W %i + /H %i + /IM true + /BPC 1 + /D [1 0] + ID %t + EI + Q]] ] + + function readers.pktopdf(glyph,width) + local xsize = glyph.xsize or 0 + local ysize = glyph.ysize or 0 + local xoffset = glyph.xoffset or 0 + local yoffset = glyph.yoffset or 0 + local stream = glyph.stream + + local dpi = 1 + local newdpi = 1 + + local xdpi = dpi * xsize / newdpi + local ydpi = dpi * ysize / newdpi + + local llx = - xoffset + local lly = yoffset - ysize + 1 + local urx = llx + xsize + 1 + local ury = lly + ysize + + local result = { } + local r = 0 + local s = 0 + local cw = idiv(xsize+ 7, 8) + local rw = idiv(xsize+15,16) + local extra = 2 * rw == cw + local b + for y=1,ysize do + for x=1,rw-1 do + s = s + 1 ; b = stream[s] + r = r + 1 ; result[r] = char(extract(b,8,8),extract(b,0,8)) + end + s = s + 1 ; b = stream[s] + if extra then + r = r + 1 ; result[r] = char(extract(b,8,8),extract(b,0,8)) + else + r = r + 1 ; result[r] = char(extract(b,8,8)) + end + end + return + template(width,llx,lly,urx,ury,xdpi,ydpi,llx,lly,xsize,ysize,result), + llx, lly, urx, ury + end + + function readers.loadpk(filename) + local s = openstream(filename) + local preamble = readcardinal1(s) + local version = readcardinal1(s) + local comment = readstring(s,readcardinal1(s)) + local designsize = readcardinal4(s) + local checksum = readcardinal4(s) + local hppp = readcardinal4(s) + local vppp = readcardinal4(s) + if preamble ~= 247 or version ~= 89 or not vppp then + return { error = "invalid preamble" } + end + local glyphs = { } + local data = { + designsize = designsize, + comment = comment, + hppp = hppp, + vppp = vppp, + glyphs = glyphs, + } + while true do + local flagbyte = readcardinal1(s) + if flagbyte < 240 then + local c = band(flagbyte,7) + local length, index, width, pixels, xsize, ysize, xoffset, yoffset + if c >= 0 and c <= 3 then + length = band(flagbyte,7) * 256 + readcardinal1(s) - 3 + index = readcardinal1(s) + width = readinteger3(s) + pixels = readcardinal1(s) + xsize = readcardinal1(s) + ysize = readcardinal1(s) + xoffset = readcardinal1(s) + yoffset = readcardinal1(s) + if xoffset > 127 then + xoffset = xoffset - 256 + end + if yoffset > 127 then + yoffset = yoffset - 256 + end + elseif c >= 4 and c <= 6 then + length = band(flagbyte,3) * 65536 + readcardinal1(s) * 256 + readcardinal1(s) - 4 + index = readcardinal1(s) + width = readinteger3(s) + pixels = readcardinal2(s) + xsize = readcardinal2(s) + ysize = readcardinal2(s) + xoffset = readcardinal2(s) + yoffset = readcardinal2(s) + else -- 7 + length = readcardinal4(s) - 9 + index = readcardinal4(s) + width = readinteger4(s) + pixels = readcardinal4(s) + readcardinal4(s) + xsize = readcardinal4(s) + ysize = readcardinal4(s) + xoffset = readcardinal4(s) + yoffset = readcardinal4(s) + end + local glyph = { + index = index, + width = width, + pixels = pixels, + xsize = xsize, + ysize = ysize, + xoffset = xoffset, + yoffset = yoffset, + } + if length <= 0 then + data.error = "bad packet" + return data + end + readbitmap(glyph,s,flagbyte) + glyphs[index] = glyph + elseif flagbyte == 240 then + -- k[1] x[k] + skipbytes(s,readcardinal1(s)) + elseif flagbyte == 241 then + -- k[2] x[k] + skipbytes(s,readcardinal2(s)*2) + elseif flagbyte == 242 then + -- k[3] x[k] + skipbytes(s,readcardinal3(s)*3) + elseif flagbyte == 243 then + -- k[4] x[k] + skipbytes(s,readcardinal4(s)*4) -- readinteger4 + elseif flagbyte == 244 then + -- y[4] + skipbytes(s,4) + elseif flagbyte == 245 then + break + elseif flagbyte == 246 then + -- nop + else + data.error = "unknown pk command" + break + end + end + return data + end + +end + +do + + local leftboundary = -1 + local rightboundary = -2 + local boundarychar = 65536 + + function readers.loadtfm(filename) + local data + -- + local function someerror(m) + if not data then + data = { } + end + data.error = m or "fatal error" + return data + end + -- + local s = openstream(filename) + if not s then + return someerror() + end + -- + local wide = false + local header = 0 + local max = 0 + local size = streamsize(s) + local glyphs = table.setmetatableindex(function(t,k) local v = { } t[k] = v return v end) + local parameters = { } + local direction = 0 + -- + local lf, lh, bc, ec, nw, nh, nd, ni, nl, nk, ne, np + -- + lf = readcardinal2(s) + if lf ~= 0 then + header = 6 + max = 255 + wide = false + lh = readcardinal2(s) + bc = readcardinal2(s) + ec = readcardinal2(s) + nw = readcardinal2(s) + nh = readcardinal2(s) + nd = readcardinal2(s) + ni = readcardinal2(s) + nl = readcardinal2(s) + nk = readcardinal2(s) + ne = readcardinal2(s) + np = readcardinal2(s) + else + header = 14 + max = 65535 + wide = readcardinal4(s) == 0 + if not wide then + return someerror("invalid format") + end + lf = readcardinal4(s) + lh = readcardinal4(s) + bc = readcardinal4(s) + ec = readcardinal4(s) + nw = readcardinal4(s) + nh = readcardinal4(s) + nd = readcardinal4(s) + ni = readcardinal4(s) + nl = readcardinal4(s) + nk = readcardinal4(s) + ne = readcardinal4(s) + np = readcardinal4(s) + direction = readcardinal4(s) + end + if (bc > ec + 1) or (ec > max) then + return someerror("file is too small") + end + if bc > max then + bc, ec = 1, 0 + end + local nlw = (wide and 2 or 1) * nl + local neew = (wide and 2 or 1) * ne + local ncw = (wide and 2 or 1) * (ec - bc + 1) + if lf ~= (header + lh + ncw + nw + nh + nd + ni + nlw + nk + neew + np) then + return someerror("file is too small") + end + if nw == 0 or nh == 0 or nd == 0 or ni == 0 then + return someerror("no glyphs") + end + if lf * 4 > size then + return someerror("file is too small") + end + local slh = lh + if lh < 2 then + return someerror("file is too small") + end + local checksum = readcardinal4(s) + local designsize = readcardinal2(s) + designsize = designsize * 256 + readcardinal1(s) + designsize = designsize * 16 + rshift(readcardinal1(s),4) + if designsize < 0xFFFF then + return someerror("weird designsize") + end + -- + local alpha = 16 + local z = designsize + while z >= 040000000 do + z = rshift(z,1) + alpha = alpha + alpha + end + local beta = idiv(256,alpha) + alpha = alpha * z + -- + local function readscaled() + local a, b, c, d = readbytes(s,4) + local n = idiv(rshift(rshift(d*z,8)+c*z,8)+b*z,beta) + if a == 0 then + return n + elseif a == 255 then + return n - alpha + else + return 0 + end + end + -- + local function readunscaled() + local a, b, c, d = readbytes(s,4) + if a > 127 then + a = a - 256 + end + return a * 0xFFFFF + b * 0xFFF + c * 0xF + rshift(d,4) + end + -- + while lh > 2 do -- can be one-liner + skipbytes(s,4) + lh = lh - 1 + end + local saved = getposition(s) + setposition(s,(header + slh + ncw) * 4 + 1) + local widths = { } for i=0,nw-1 do widths [i] = readscaled() end + local heights = { } for i=0,nh-1 do heights[i] = readscaled() end + local depths = { } for i=0,nd-1 do depths [i] = readscaled() end + local italics = { } for i=0,ni-1 do italics[i] = readscaled() end + if widths[0] ~= 0 or heights[0] ~= 0 or depths[0] ~= 0 then + return someerror("invalid dimensions") + end + -- + local blabel = nl + local bchar = boundarychar + -- + local ligatures = { } + if nl > 0 then + for i=0,nl-1 do + local a, b, c, d = readbytes(s,4) + ligatures[i] = { + skip = a, + nxt = b, + op = c, + rem = d, + } + if a > 128 then + if 256 * c + d >= nl then + return someerror("invalid ligature table") + end + if a == 255 and i == 0 then + bchar = b + end + else + if c < 128 then + -- whatever + elseif 256 * (c - 128) + d >= nk then + return someerror("invalid ligature table") + end + if (a < 128) and (i - 0 + a + 1 >= nl) then + return someerror("invalid ligature table") + end + end + if a == 255 then + blabel = 256 * c + d + end + end + end + local allkerns = { } + for i=0,nk-1 do + allkerns[i] = readscaled() + end + local extensibles = { } + for i=0,ne-1 do + extensibles[i] = wide and { + top = readcardinal2(s), + bot = readcardinal2(s), + mid = readcardinal2(s), + rep = readcardinal2(s), + } or { + top = readcardinal1(s), + bot = readcardinal1(s), + mid = readcardinal1(s), + rep = readcardinal1(s), + } + end + for i=1,np do + if i == 1 then + parameters[i] = readunscaled() + else + parameters[i] = readscaled() + end + end + for i=1,7 do + if not parameters[i] then + parameters[i] = 0 + end + end + -- + setposition(s,saved) + local extras = false + if blabel ~= nl then + local k = blabel + while true do + local l = ligatures[k] + local skip = l.skip + if skip <= 128 then + -- if l.op >= 128 then + -- extras = true -- kern + -- else + extras = true -- ligature + -- end + end + if skip == 0 then + k = k + 1 + else + if skip >= 128 then + break + end + k = k + skip + 1 + end + end + end + if extras then + local ligas = { } + local kerns = { } + local k = blabel + while true do + local l = ligatures[k] + local skip = l.skip + if skip <= 128 then + local nxt = l.nxt + local op = l.op + local rem = l.rem + if op >= 128 then + kerns[nxt] = allkerns[256 * (op - 128) + rem] + else + ligas[nxt] = { type = op * 2 + 1, char = rem } + end + end + if skip == 0 then + k = k + 1 + else + if skip >= 128 then + break; + end + k = k + skip + 1 + end + end + if next(kerns) then + local glyph = glyphs[leftboundary] + glyph.kerns = kerns + glyph.remainder = 0 + end + if next(ligas) then + local glyph = glyphs[leftboundary] + glyph.ligatures = ligas + glyph.remainder = 0 + end + end + for i=bc,ec do + local glyph, width, height, depth, italic, tag, remainder + if wide then + width = readcardinal2(s) + height = readcardinal1(s) + depth = readcardinal1(s) + italic = readcardinal1(s) + tag = readcardinal1(s) + remainder = readcardinal2(s) + else + width = readcardinal1(s) + height = readcardinal1(s) + depth = extract(height,0,4) + height = extract(height,4,4) + italic = readcardinal1(s) + tag = extract(italic,0,2) + italic = extract(italic,2,6) + remainder = readcardinal1(s) + end + if width == 0 then + -- nothing + else + if width >= nw or height >= nh or depth >= nd or italic >= ni then + return someerror("invalid dimension index") + end + local extensible, nextinsize + if tag == 0 then + -- nothing special + else + local r = remainder + if tag == 1 then + if r >= nl then + return someerror("invalid ligature index") + end + elseif tag == 2 then + if r < bc or r > ec then + return someerror("invalid chain index") + end + while r < i do + local g = glyphs[r] + if g.tag ~= list_tag then + break + end + r = g.remainder + end + if r == i then + return someerror("cycles in chain") + end + nextinsize = r + elseif tag == 3 then + if r >= ne then + return someerror("bad extensible") + end + extensible = extensibles[r] -- remainder ? + remainder = 0 + end + end + glyphs[i] = { + width = widths [width], + height = heights[height], + depth = depths [depth], + italic = italics[italic], + tag = tag, + -- index = i, + remainder = remainder, + extensible = extensible, + next = nextinsize, + } + end + end + for i=bc,ec do + local glyph = glyphs[i] + if glyph.tag == 1 then + -- ligature + local k = glyph.remainder + local l = ligatures[k] + if l.skip > 128 then + k = 256 * l.op + l.rem + end + local ligas = { } + local kerns = { } + while true do + local l = ligatures[k] + local skip = l.skip + if skip <= 128 then + local nxt = l.nxt + local op = l.op + local rem = l.rem + if op >= 128 then + local kern = allkerns[256 * (op - 128) + rem] + if nxt == bchar then + kerns[rightboundary] = kern + end + kerns[nxt] = kern + else + local ligature = { type = op * 2 + 1, char = rem } + if nxt == bchar then + ligas[rightboundary] = ligature + end + ligas[nxt] = ligature -- shared + end + end + if skip == 0 then + k = k + 1 + else + if skip >= 128 then + break + end + k = k + skip + 1 + end + end + if next(kerns)then + glyph.kerns = kerns + glyph.remainder = 0 + end + if next(ligas) then + glyph.ligatures = ligas + glyph.remainder = 0 + end + end + end + -- + if bchar ~= boundarychar then + glyphs[rightboundary] = copy(glyphs[bchar]) + end + -- + -- for k, v in next, glyphs do + -- v.tag = nil + -- v.remainder = nil + -- end + -- + return { + name = file.nameonly(filename), + fontarea = file.pathpart(filename), + glyphs = glyphs, + parameters = parameters, + designsize = designsize, + size = designsize, + direction = direction, + -- checksum = checksum, + -- embedding = "unknown", + -- encodingbytes = 0, + -- extend = 1000, + -- slant = 0, + -- squeeze = 0, + -- format = "unknown", + -- identity = "unknown", + -- mode = 0, + -- streamprovider = 0, + -- tounicode = 0, + -- type = "unknown", + -- units_per_em = 0, + -- used = false, + -- width = 0, + -- writingmode = "unknown", + } + end + +end + +do + + local push = { "push" } + local push = { "pop" } + + local w, x, y, z, f + local stack + local s, result, r + local alpha, beta, z + + local function scaled1() + local a = readbytes(s,1) + if a == 0 then + return 0 + elseif a == 255 then + return - alpha + else + return 0 -- error + end + end + + local function scaled2() + local a, b = readbytes(s,2) + local sw = idiv(b*z,beta) + if a == 0 then + return sw + elseif a == 255 then + return sw - alpha + else + return 0 -- error + end + end + + local function scaled3() + local a, b, c = readbytes(s,3) + local sw = idiv(rshift(c*z,8)+b*z,beta) + if a == 0 then + return sw + elseif a == 255 then + return sw - alpha + else + return 0 -- error + end + end + + local function scaled4() + local a, b, c, d = readbytes(s,4) + local sw = idiv( rshift(rshift(d*z,8)+(c*z),8)+b*z,beta) + if a == 0 then + return sw + elseif a == 255 then + return sw - alpha + else + return 0 -- error + end + end + + local function dummy() + end + + local actions = { + + [128] = function() r = r + 1 result[r] = { "slot", f or 1, readcardinal1(s) } p = p + 1 end, + [129] = function() r = r + 1 result[r] = { "slot", f or 1, readcardinal2(s) } p = p + 2 end, + [130] = function() r = r + 1 result[r] = { "slot", f or 1, readcardinal3(s) } p = p + 3 end, + [131] = function() r = r + 1 result[r] = { "slot", f or 1, readcardinal4(s) } p = p + 4 end, + + [132] = function() + r = r + 1 + result[r] = { "rule", scaled4(), scaled4() } + p = p + 8 + end, + + [133] = function() + r = r + 1 result[r] = push + r = r + 1 result[r] = { "slot", f or 1, readcardinal1(s) } + r = r + 1 result[r] = pop + p = p + 1 + end, + [134] = function() + r = r + 1 result[r] = push + r = r + 1 result[r] = { "slot", f or 1, readcardinal2(s) } + r = r + 1 result[r] = pop + p = p + 2 + end, + [135] = function() + r = r + 1 result[r] = push + r = r + 1 result[r] = { "slot", f or 1, readcardinal2(s) } + r = r + 1 result[r] = pop + p = p + 3 + end, + [136] = function() + r = r + 1 result[r] = push + r = r + 1 result[r] = { "slot", f or 1, readcardinal4(s) } + r = r + 1 result[r] = pop + p = p + 4 + end, + + [137] = function() + r = r + 1 result[r] = push + r = r + 1 result[r] = { "rule", scaled4(), scaled4() } + r = r + 1 result[r] = pop + p = p + 8 + end, + + [138] = dummy, -- nop + [139] = dummy, -- bop + [140] = dummy, -- eop + + [141] = function() + insert(stack, { w, x, y, z }) + r = r + 1 + result[r] = push + end, + [142] = function() + local t = remove(stack) + if t then + w, x, y, z = t[1], t[2], t[3], t[4] + r = r + 1 + result[r] = pop + end + end, + + [143] = function() r = r + 1 result[r] = { "right", scaled1() } p = p + 1 end, + [144] = function() r = r + 1 result[r] = { "right", scaled2() } p = p + 2 end, + [145] = function() r = r + 1 result[r] = { "right", scaled3() } p = p + 3 end, + [146] = function() r = r + 1 result[r] = { "right", scaled4() } p = p + 4 end, + + [148] = function() w = scaled1() r = r + 1 result[r] = { "right", w } p = p + 1 end, + [149] = function() w = scaled2() r = r + 1 result[r] = { "right", w } p = p + 2 end, + [150] = function() w = scaled3() r = r + 1 result[r] = { "right", w } p = p + 3 end, + [151] = function() w = scaled4() r = r + 1 result[r] = { "right", w } p = p + 4 end, + + [153] = function() x = scaled1() r = r + 1 result[r] = { "right", x } p = p + 1 end, + [154] = function() x = scaled2() r = r + 1 result[r] = { "right", x } p = p + 2 end, + [155] = function() x = scaled3() r = r + 1 result[r] = { "right", x } p = p + 3 end, + [156] = function() x = scaled4() r = r + 1 result[r] = { "right", x } p = p + 4 end, + + [157] = function() r = r + 1 result[r] = { "down", scaled1() } p = p + 1 end, + [158] = function() r = r + 1 result[r] = { "down", scaled2() } p = p + 2 end, + [159] = function() r = r + 1 result[r] = { "down", scaled3() } p = p + 3 end, + [160] = function() r = r + 1 result[r] = { "down", scaled4() } p = p + 4 end, + + [162] = function() y = scaled1() r = r + 1 result[r] = { "down", y } p = p + 1 end, + [163] = function() y = scaled2() r = r + 1 result[r] = { "down", y } p = p + 2 end, + [164] = function() y = scaled3() r = r + 1 result[r] = { "down", y } p = p + 3 end, + [165] = function() y = scaled3() r = r + 1 result[r] = { "down", y } p = p + 4 end, + + [167] = function() z = scaled1() r = r + 1 ; result[r] = { "down", z } p = p + 4 end, + [168] = function() z = scaled2() r = r + 1 ; result[r] = { "down", z } p = p + 4 end, + [169] = function() z = scaled3() r = r + 1 ; result[r] = { "down", z } p = p + 4 end, + [170] = function() z = scaled4() r = r + 1 ; result[r] = { "down", z } p = p + 4 end, + + [147] = function() r = r + 1 result[r] = { "right", w } end, + [152] = function() r = r + 1 result[r] = { "right", x } end, + [161] = function() r = r + 1 result[r] = { "down", y } end, + [166] = function() r = r + 1 result[r] = { "down", z } end, + + [235] = function() f = readcardinal1(s) p = p + 1 end, + [236] = function() f = readcardinal2(s) p = p + 3 end, + [237] = function() f = readcardinal3(s) p = p + 3 end, + [238] = function() f = readcardinal4(s) p = p + 4 end, + + [239] = function() local n = readcardinal1(s) r = r + 1 result[r] = { "special", readstring(s,n) } p = p + 1 + n end, + [240] = function() local n = readcardinal2(s) r = r + 1 result[r] = { "special", readstring(s,n) } p = p + 2 + n end, + [241] = function() local n = readcardinal3(s) r = r + 1 result[r] = { "special", readstring(s,n) } p = p + 3 + n end, + [242] = function() local n = readcardinal4(s) r = r + 1 result[r] = { "special", readstring(s,n) } p = p + 4 + n end, + + [250] = function() local n = readcardinal1(s) r = r + 1 result[r] = { "pdf", readstring(s,n) } p = p + 1 + n end, + [251] = function() local n = readcardinal2(s) r = r + 1 result[r] = { "pdf", readstring(s,n) } p = p + 2 + n end, + [252] = function() local n = readcardinal3(s) r = r + 1 result[r] = { "pdf", readstring(s,n) } p = p + 3 + n end, + [253] = function() local n = readcardinal4(s) r = r + 1 result[r] = { "pdf", readstring(s,n) } p = p + 4 + n end, + + } + + table.setmetatableindex(actions,function(t,cmd) + local v + if cmd >= 0 and cmd <= 127 then + v = function() + if f == 0 then + f = 1 + end + r = r + 1 ; result[r] = { "slot", f, cmd } + end + elseif cmd >= 171 and cmd <= 234 then + cmd = cmd - 170 + v = function() + r = r + 1 ; result[r] = { "font", cmd } + end + else + v = dummy + end + t[cmd] = v + return v + end) + + function readers.loadvf(filename,data) + -- + local function someerror(m) + if not data then + data = { } + end + data.error = m or "fatal error" + return data + end + -- + s = openstream(filename) + if not s then + return someerror() + end + -- + local cmd = readcardinal1(s) + if cmd ~= 247 then + return someerror("bad preamble") + end + cmd = readcardinal1(s) + if cmd ~= 202 then + return someerror("bad version") + end + local header = readstring(s,readcardinal1(s)) + local checksum = readcardinal4(s) + local designsize = idiv(readcardinal4(s),16) + local fonts = data and data.fonts or { } + local glyphs = data and data.glyphs or { } + -- + alpha = 16 + z = designsize + while z >= 040000000 do + z = rshift(z,1) + alpha = alpha + alpha + end + beta = idiv(256,alpha) + alpha = alpha * z + -- + cmd = readcardinal1(s) + while true do + local n + if cmd == 243 then + n = readcardinal1(s) + 1 + elseif cmd == 244 then + n = readcardinal2(s) + 1 + elseif cmd == 245 then + n = readcardinal3(s) + 1 + elseif cmd == 246 then + n = readcardinal4(s) + 1 + else + break + end + local checksum = skipbytes(s,4) + local size = scaled4() + local designsize = idiv(readcardinal4(s),16) + local pathlen = readcardinal1(s) + local namelen = readcardinal1(s) + local path = readstring(s,pathlen) + local name = readstring(s,namelen) + fonts[n] = { path = path, name = name, size = size } + cmd = readcardinal1(s) + end + local index = 0 + while cmd and cmd <= 242 do + local width = 0 + local length = 0 + local checksum = 0 + if cmd == 242 then + length = readcardinal4(s) + checksum = readcardinal4(s) + width = readcardinal4(s) + else + length = cmd + checksum = readcardinal1(s) + width = readcardinal3(s) + end + w, x, y, z, f = 0, 0, 0, 0, false + stack, result, r, p = { }, { }, 0, 0 + while p < length do + local cmd = readcardinal1(s) + p = p + 1 + actions[cmd]() + end + local glyph = glyphs[index] + if glyph then + glyph.width = width + glyph.commands = result + else + glyphs[index] = { + width = width, + commands = result, + } + end + index = index + 1 + if #stack > 0 then + -- error: more pushes than pops + end + if packet_length ~= 0 then + -- error: invalid packet length + end + cmd = readcardinal1(s) + end + if readcardinal1(s) ~= 248 then + -- error: no post + end + s, result, r = nil, nil, nil + if data then + data.glyphs = data.glyphs or glyphs + data.fonts = data.fonts or fonts + return data + else + return { + name = file.nameonly(filename), + fontarea = file.pathpart(filename), + glyphs = glyphs, + designsize = designsize, + header = header, + fonts = fonts, + } + end + end + + -- the replacement loader (not sparse): + + function readers.loadtfmvf(tfmname,size) + local vfname = file.addsuffix(file.nameonly(tfmfile),"vf") + local tfmfile = tfmname + local vffile = resolvers.findbinfile(vfname,"ovf") + if tfmfile and tfmfile ~= "" then + if size < 0 then + size = idiv(65536 * -size,100) + end + local data = readers.loadtfm(tfmfile) + if data.error then + return data + end + if vffile and vffile ~= "" then + data = readers.loadvf(vffile,data) + if data.error then + return data + end + end + local designsize = data.designsize + local glyphs = data.glyphs + local parameters = data.parameters + local fonts = data.fonts + if size ~= designsize then + local factor = size / designsize + for index, glyph in next, glyphs do + if next(glyph) then + glyph.width = round(factor*glyph.width) + glyph.height = round(factor*glyph.height) + glyph.depth = round(factor*glyph.depth) + local italic = glyph.italic + if italic == 0 then + glyph.italic = nil + else + glyph.italic = round(factor*glyph.italic) + end + -- + local kerns = glyph.kerns + if kerns then + for index, kern in next, kerns do + kerns[index] = round(factor*kern) + end + end + -- + local commands = glyph.commands + if commands then + for i=1,#commands do + local c = commands[i] + local t = c[1] + if t == "down" or t == "right" then + c[2] = round(factor*c[2]) + elseif t == "rule" then + c[2] = round(factor*c[2]) + c[3] = round(factor*c[3]) + end + end + end + else + glyphs[index] = nil + end + end + for i=2,30 do + local p = parameters[i] + if p then + parameters[i] = round(factor*p) + else + break + end + end + if fonts then + for k, v in next, fonts do + v.size = round(factor*v.size) + end + end + else + for index, glyph in next, glyphs do + if next(glyph) then + if glyph.italic == 0 then + glyph.italic = nil + end + else + glyphs[index] = nil + end + end + end + -- + parameters.slant = parameters[1] + parameters.space = parameters[2] + parameters.space_stretch = parameters[3] + parameters.space_shrink = parameters[4] + parameters.x_height = parameters[5] + parameters.quad = parameters[6] + parameters.extra_space = parameters[7] + -- + for i=1,7 do + parameters[i] = nil -- so no danger for async + end + -- + data.characters = glyphs + data.glyphs = nil + data.size = size + -- + return data + end + end + +end + +-- inspect(readers.loadtfmvf(resolvers.find_file("mi-iwonari.tfm"))) +-- inspect(readers.loadtfm(resolvers.find_file("texnansi-palatinonova-regular.tfm"))) +-- inspect(readers.loadtfm(resolvers.find_file("cmex10.tfm"))) +-- inspect(readers.loadtfm(resolvers.find_file("cmr10.tfm"))) +-- local t = readers.loadtfmvf("texnansi-lte50019.tfm") +-- inspect(t) diff --git a/tex/context/base/mkiv/font-ttf.lua b/tex/context/base/mkiv/font-ttf.lua index 58e999e26..d2fe0917c 100644 --- a/tex/context/base/mkiv/font-ttf.lua +++ b/tex/context/base/mkiv/font-ttf.lua @@ -319,7 +319,8 @@ local function contours2outlines_normal(glyphs,shapes) -- maybe accept the bbox local nofsegments = 0 glyph.segments = segments if nofcontours > 0 then - local px, py = 0, 0 -- we could use these in calculations which saves a copy + local px = 0 + local py = 0 local first = 1 for i=1,nofcontours do local last = contours[i] @@ -347,15 +348,20 @@ local function contours2outlines_normal(glyphs,shapes) -- maybe accept the bbox end control_pt = first_pt end - local x, y = first_pt[1], first_pt[2] + local x = first_pt[1] + local y = first_pt[2] if not done then - xmin, ymin, xmax, ymax = x, y, x, y + xmin = x + ymin = y + xmax = x + ymax = y done = true end nofsegments = nofsegments + 1 segments[nofsegments] = { x, y, "m" } -- "moveto" if not quadratic then - px, py = x, y + px = x + py = y end local previous_pt = first_pt for i=first,last do @@ -375,8 +381,10 @@ local function contours2outlines_normal(glyphs,shapes) -- maybe accept the bbox control_pt = current_pt end elseif current_on then - local x1, y1 = control_pt[1], control_pt[2] - local x2, y2 = current_pt[1], current_pt[2] + local x1 = control_pt[1] + local y1 = control_pt[2] + local x2 = current_pt[1] + local y2 = current_pt[2] nofsegments = nofsegments + 1 if quadratic then segments[nofsegments] = { x1, y1, x2, y2, "q" } -- "quadraticto" @@ -386,8 +394,10 @@ local function contours2outlines_normal(glyphs,shapes) -- maybe accept the bbox end control_pt = false else - local x2, y2 = (previous_pt[1]+current_pt[1])/2, (previous_pt[2]+current_pt[2])/2 - local x1, y1 = control_pt[1], control_pt[2] + local x2 = (previous_pt[1]+current_pt[1])/2 + local y2 = (previous_pt[2]+current_pt[2])/2 + local x1 = control_pt[1] + local y1 = control_pt[2] nofsegments = nofsegments + 1 if quadratic then segments[nofsegments] = { x1, y1, x2, y2, "q" } -- "quadraticto" @@ -403,14 +413,17 @@ local function contours2outlines_normal(glyphs,shapes) -- maybe accept the bbox -- we're already done, probably a simple curve else nofsegments = nofsegments + 1 - local x2, y2 = first_pt[1], first_pt[2] + local x2 = first_pt[1] + local y2 = first_pt[2] if not control_pt then segments[nofsegments] = { x2, y2, "l" } -- "lineto" elseif quadratic then - local x1, y1 = control_pt[1], control_pt[2] + local x1 = control_pt[1] + local y1 = control_pt[2] segments[nofsegments] = { x1, y1, x2, y2, "q" } -- "quadraticto" else - local x1, y1 = control_pt[1], control_pt[2] + local x1 = control_pt[1] + local y1 = control_pt[2] x1, y1, x2, y2, px, py = curveto(x1, y1, px, py, x2, y2) segments[nofsegments] = { x1, y1, x2, y2, px, py, "c" } -- "curveto" -- px, py = x2, y2 @@ -474,7 +487,8 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) end control_pt = first_pt end - local x, y = first_pt[1], first_pt[2] + local x = first_pt[1] + local y = first_pt[2] if not done then xmin, ymin, xmax, ymax = x, y, x, y done = true @@ -487,7 +501,8 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) segments[nofsegments] = { x, y, "m" } -- "moveto" end if not quadratic then - px, py = x, y + px = x + py = y end local previous_pt = first_pt for i=first,last do @@ -497,7 +512,8 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) if previous_on then if current_on then -- both normal points - local x, y = current_pt[1], current_pt[2] + local x = current_pt[1] + local y = current_pt[2] if x < xmin then xmin = x elseif x > xmax then xmax = x end if y < ymin then ymin = y elseif y > ymax then ymax = y end if keepcurve then @@ -505,14 +521,17 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) segments[nofsegments] = { x, y, "l" } -- "lineto" end if not quadratic then - px, py = x, y + px = x + py = y end else control_pt = current_pt end elseif current_on then - local x1, y1 = control_pt[1], control_pt[2] - local x2, y2 = current_pt[1], current_pt[2] + local x1 = control_pt[1] + local y1 = control_pt[2] + local x2 = current_pt[1] + local y2 = current_pt[2] if quadratic then if x1 < xmin then xmin = x1 elseif x1 > xmax then xmax = x1 end if y1 < ymin then ymin = y1 elseif y1 > ymax then ymax = y1 end @@ -535,8 +554,10 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) end control_pt = false else - local x2, y2 = (previous_pt[1]+current_pt[1])/2, (previous_pt[2]+current_pt[2])/2 - local x1, y1 = control_pt[1], control_pt[2] + local x2 = (previous_pt[1]+current_pt[1])/2 + local y2 = (previous_pt[2]+current_pt[2])/2 + local x1 = control_pt[1] + local y1 = control_pt[2] if quadratic then if x1 < xmin then xmin = x1 elseif x1 > xmax then xmax = x1 end if y1 < ymin then ymin = y1 elseif y1 > ymax then ymax = y1 end @@ -569,8 +590,10 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) segments[nofsegments] = { first_pt[1], first_pt[2], "l" } -- "lineto" end else - local x1, y1 = control_pt[1], control_pt[2] - local x2, y2 = first_pt[1], first_pt[2] + local x1 = control_pt[1] + local y1 = control_pt[2] + local x2 = first_pt[1] + local y2 = first_pt[2] if x1 < xmin then xmin = x1 elseif x1 > xmax then xmax = x1 end if y1 < ymin then ymin = y1 elseif y1 > ymax then ymax = y1 end if quadratic then diff --git a/tex/context/base/mkiv/font-vir.lua b/tex/context/base/mkiv/font-vir.lua index d65136245..c3071cac0 100644 --- a/tex/context/base/mkiv/font-vir.lua +++ b/tex/context/base/mkiv/font-vir.lua @@ -106,8 +106,10 @@ local function combine_assign(g, name, from, to, start, force) if not from then from, to = 0, 0xFF00 end if not to then to = from end if not start then start = from end - local fc, gc = f.characters, g.characters - local fd, gd = f.descriptions, g.descriptions + local fc = f.characters + local gc = g.characters + local fd = f.descriptions + local gd = g.descriptions local hn = #g.fonts+1 g.fonts[hn] = { id = id } -- no need to be sparse for i=from,to do @@ -133,8 +135,10 @@ end local function combine_names(g,name,force) local f, id = constructors.readanddefine(name,g.specification.size) if f and id then - local fc, gc = f.characters, g.characters - local fd, gd = f.descriptions, g.descriptions + local fc = f.characters + local gc = g.characters + local fd = f.descriptions + local gd = g.descriptions g.fonts[#g.fonts+1] = { id = id } -- no need to be sparse local hn = #g.fonts for k, v in next, fc do @@ -149,7 +153,8 @@ local function combine_names(g,name,force) end local combine_feature = function(g,v) - local key, value = v[2], v[3] + local key = v[2] + local value = v[3] if key then if value == nil then value = true diff --git a/tex/context/base/mkiv/grph-bmp.lua b/tex/context/base/mkiv/grph-bmp.lua new file mode 100644 index 000000000..256b64309 --- /dev/null +++ b/tex/context/base/mkiv/grph-bmp.lua @@ -0,0 +1,85 @@ +if not modules then modules = { } end modules ['grph-bmp'] = { + version = 1.001, + comment = "companion to grph-inc.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local random = math.random +local context = context + +local report_bitmap = logs.reporter("graphics","bitmap") + +local bitmaps = { } +graphics.bitmaps = bitmaps + +local wrapimage = images.wrap + +function bitmaps.new(xsize,ysize,colorspace,colordepth,mask) + if not xsize or not ysize or xsize == 0 or ysize == 0 then + report_bitmap("provide 'xsize' and 'ysize' larger than zero") + return + end + if not colorspace then + report_bitmap("provide 'colorspace' (1, 2, 3, 'gray', 'rgb', 'cmyk'") + return + end + if not colordepth then + report_bitmap("provide 'colordepth' (1, 2)") + return + end + return graphics.identifiers.bitmap { + colorspace = colorspace, + colordepth = colordepth, + xsize = xsize, + ysize = ysize, + mask = mask and true or nil, + } +end + +local function flush(bitmap) + return wrapimage(lpdf.injectors.bitmap(bitmap)) +end + +bitmaps.flush = flush + +function bitmaps.tocontext(bitmap,width,height) + if type(width) == "number" then + width = width .. "sp" + end + if type(height) == "number" then + height = height .. "sp" + end + if width or height then + context.scale ( + { + width = width, + height = height, + }, + flush(bitmap) + ) + else + context(flush(bitmap)) + end +end + +local function placeholder(nx,ny) + + local nx = nx or 8 + local ny = ny or nx + local bitmap = bitmaps.new(nx,ny,"gray",1) + local data = bitmap.data + + for i=1,ny do + local d = data[i] + for j=1,nx do + d[j] = random(100,199) + end + end + + return lpdf.injectors.bitmap(bitmap) + +end + +bitmaps.placeholder = placeholder diff --git a/tex/context/base/mkiv/grph-chk.lua b/tex/context/base/mkiv/grph-chk.lua new file mode 100644 index 000000000..6356755aa --- /dev/null +++ b/tex/context/base/mkiv/grph-chk.lua @@ -0,0 +1,276 @@ +if not modules then modules = { } end modules ['grph-inc'] = { + version = 1.001, + comment = "companion to grph-inc.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local xpcall, pcall = xpcall, pcall + +local bpfactor = number.dimenfactors.bp + +local report = logs.reporter("graphics") +local report_inclusion = logs.reporter("graphics","inclusion") +local report_bitmap = logs.reporter("graphics","bitmap") + +local checkers = figures.checkers + +local placeholder = graphics.bitmaps.placeholder + +-- This is an experiment. The following method uses Lua to handle the embedding +-- using the epdf library. This feature will be used when we make the transition +-- from the pre 1.10 epdf library (using an unsuported low level poppler api) to a +-- new (lightweight, small and statically compiled) library. More on that later. +-- +-- The method implemented below has the same performance as the hard coded inclusion +-- but opens up some possibilities (like merging fonts) that I will look into some +-- day. + +local function pdf_checker(data) + local request = data.request + local used = data.used + if request and used and not request.scanimage then + local image = lpdf.epdf.image + local openpdf = image.open + local closepdf = image.close + local querypdf = image.query + local copypage = image.copy + local pdfdoc = nil + request.scanimage = function(t) + pdfdoc = openpdf(t.filename,request.userpassword,request.ownerpassword) + if pdfdoc then + -- + pdfdoc.nofcopiedpages = 0 + -- + local info = querypdf(pdfdoc,request.page,request.size) + if info then + local bbox = info and info.boundingbox or { 0, 0, 0, 0 } + local height = bbox[4] - bbox[2] + local width = bbox[3] - bbox[1] + local rotation = info.rotation or 0 + if rotation == 90 then + rotation, height, width = 3, width, height + elseif rotation == 180 then + rotation = 2 + elseif rotation == 270 then + rotation, height, width = 1, width, height + elseif rotation == 1 or rotation == 3 then + height, width = width, height + else + rotation = 0 + end + return { + filename = filename, + -- page = 1, + pages = pdfdoc.nofpages, + width = width, + height = height, + depth = 0, + colordepth = 0, + xres = 0, + yres = 0, + xsize = width, + ysize = height, + rotation = rotation, + pdfdoc = pdfdoc, + } + end + end + end + request.copyimage = function(t) + if not pdfdoc then + pdfdoc = t.pdfdoc + end + if pdfdoc then + local result = copypage(pdfdoc,request.page,nil,request.compact,request.width,request.height,request.attr) + pdfdoc.nofcopiedpages = pdfdoc.nofcopiedpages + 1 + if pdfdoc.nofcopiedpages >= pdfdoc.nofpages then + closepdf(pdfdoc) + pdfdoc = nil + t.pdfdoc = nil + end + return result + else + -- message, should not happen as we always first scan so that reopens + end + end + end + return checkers.generic(data) +end + +local function wrappedidentify(identify,filename) + local wrapup = function() report_inclusion("fatal error reading %a",filename) end + local _, result = xpcall(identify,wrapup,filename) + if result then + local xsize = result.xsize or 0 + local ysize = result.ysize or 0 + local xres = result.xres or 0 + local yres = result.yres or 0 + if xres == 0 or yres == 0 then + xres = 300 + yres = 300 + end + result.xsize = xsize + result.ysize = ysize + result.xres = xres + result.yres = yres + result.width = result.width or ((72/xres) * xsize / bpfactor) + result.height = result.height or ((72/yres) * ysize / bpfactor) + result.depth = result.depth or 0 + result.filename = filename + result.colordepth = result.colordepth or 0 + result.colorspace = result.colorspace or 0 + result.rotation = result.rotation or 0 + result.orientation = result.orientation or 0 + result.transform = result.transform or 0 + return result + else + return { error = "fatal error" } + end +end + +local function jpg_checker(data) + local request = data.request + local used = data.used + if request and used and not request.scanimage then + local identify = graphics.identify + local inject = lpdf.injectors.jpg + local found = false + request.scanimage = function(t) + local result = wrappedidentify(identify,t.filename) + found = not result.error + return { + filename = result.filename, + width = result.width, + height = result.height, + depth = result.depth, + colordepth = result.colordepth, + xres = result.xres, + yres = result.yres, + xsize = result.xsize, + ysize = result.ysize, + colorspace = result.colorspace, + rotation = result.rotation, + orientation = result.orientation, + transform = result.transform, + } + end + request.copyimage = function(t) + if found then + found = false + return inject(t) + end + end + end + return checkers.generic(data) +end + +local function jp2_checker(data) -- idem as jpg + local request = data.request + local used = data.used + if request and used and not request.scanimage then + local identify = graphics.identify + local inject = lpdf.injectors.jp2 + local found = false + request.scanimage = function(t) + local result = wrappedidentify(identify,t.filename) + found = not result.error + return { + filename = result.filename, + width = result.width, + height = result.height, + depth = result.depth, + colordepth = result.colordepth, + xres = result.xres, + yres = result.yres, + xsize = result.xsize, + ysize = result.ysize, + rotation = result.rotation, + colorspace = result.colorspace, + orientation = result.orientation, + transform = result.transform, + } + end + request.copyimage = function(t) + if found then + found = false + return inject(t) + end + end + end + return checkers.generic(data) +end + +local function png_checker(data) -- same as jpg (for now) + local request = data.request + local used = data.used + if request and used and not request.scanimage then + local identify = graphics.identify + local inject = lpdf.injectors.png + local found = false + request.scanimage = function(t) + local result = wrappedidentify(identify,t.filename) + found = not result.error + return { + filename = result.filename, + width = result.width, + height = result.height, + depth = result.depth, + colordepth = result.colordepth, + xres = result.xres, + yres = result.yres, + xsize = result.xsize, + ysize = result.ysize, + rotation = result.rotation, + colorspace = result.colorspace, + tables = result.tables, + interlace = result.interlace, + filter = result.filter, + orientation = result.orientation, + transform = result.transform, + } + end + request.copyimage = function(t) + t.colorref = used.colorref -- this is a bit of a hack + if found then + found = false + local ok, result = pcall(inject,t) + if ok then + return result + else + report_inclusion("bad bitmap image") + return placeholder() + end + end + end + end + return checkers.generic(data) +end + + +if CONTEXTLMTXMODE then + + checkers.pdf = pdf_checker + checkers.jpg = jpg_checker + checkers.jp2 = jp2_checker + checkers.png = png_checker + +else + + -- yes or no ... + + directives.register("graphics.pdf.uselua",function(v) + checkers.pdf = v and pdf_checker or nil + report("%s Lua based PDF inclusion",v and "enabling" or "disabling") + end) + + -- directives.register("graphics.uselua",function(v) + -- checkers.pdf = v and pdf_checker or nil + -- checkers.jpg = v and jpg_checker or nil + -- checkers.jp2 = v and jp2_checker or nil + -- checkers.png = v and png_checker or nil + -- -- report("%s Lua based PDF, PNG, JPG and JP2 inclusion",v and "enabling" or "disabling") + -- end) + +end diff --git a/tex/context/base/mkiv/grph-img.lua b/tex/context/base/mkiv/grph-img.lua new file mode 100644 index 000000000..9acd1a5de --- /dev/null +++ b/tex/context/base/mkiv/grph-img.lua @@ -0,0 +1,748 @@ + if not modules then modules = { } end modules ['grph-img'] = { + version = 1.001, + comment = "companion to grph-inc.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- The jpg identification and inclusion code is based on the code in \LUATEX\ but as we +-- use \LUA\ we can do it a bit cleaner. We can also use some helpers for reading from +-- file. We could make it even more lean and mean. When all works out ok I will clean +-- up this code a bit as we can divert more from luatex. + +local lower, strip = string.lower, string.strip +local round = math.round +local concat = table.concat +local suffixonly = file.suffix + +local files = utilities.files +local getsize = files.getsize +local readbyte = files.readbyte +local readstring = files.readstring +local readcardinal = files.readcardinal +local readcardinal2 = files.readcardinal2 +local readcardinal4 = files.readcardinal4 +local readcardinal2le = files.readcardinal2le +local readcardinal4le = files.readcardinal4le +local skipbytes = files.skip +local setposition = files.setposition +local getposition = files.getposition + +local setmetatableindex = table.setmetatableindex +local setmetatablecall = table.setmetatablecall + +local lpdf = lpdf or { } +local pdfmajorversion = lpdf.majorversion +local pdfminorversion = lpdf.minorversion + +local graphics = graphics or { } +local identifiers = { } +graphics.identifiers = identifiers + +do + + local colorspaces = { + [1] = 1, -- gray + [3] = 2, -- rgb + [4] = 3, -- cmyk + } + + local tags = { + [0xC0] = { name = "SOF0", }, -- baseline DCT + [0xC1] = { name = "SOF1", }, -- extended sequential DCT + [0xC2] = { name = "SOF2", }, -- progressive DCT + [0xC3] = { name = "SOF3", supported = false }, -- lossless (sequential) + + [0xC5] = { name = "SOF5", supported = false }, -- differential sequential DCT + [0xC6] = { name = "SOF6", supported = false }, -- differential progressive DCT + [0xC7] = { name = "SOF7", supported = false }, -- differential lossless (sequential) + + [0xC8] = { name = "JPG", }, -- reserved for JPEG extensions + [0xC9] = { name = "SOF9", }, -- extended sequential DCT + [0xCA] = { name = "SOF10", supported = false }, -- progressive DCT + [0xCB] = { name = "SOF11", supported = false }, -- lossless (sequential) + + [0xCD] = { name = "SOF13", supported = false }, -- differential sequential DCT + [0xCE] = { name = "SOF14", supported = false }, -- differential progressive DCT + [0xCF] = { name = "SOF15", supported = false }, -- differential lossless (sequential) + + [0xC4] = { name = "DHT" }, -- define Huffman table(s) + + [0xCC] = { name = "DAC" }, -- define arithmetic conditioning table + + [0xD0] = { name = "RST0", zerolength = true }, -- restart + [0xD1] = { name = "RST1", zerolength = true }, -- restart + [0xD2] = { name = "RST2", zerolength = true }, -- restart + [0xD3] = { name = "RST3", zerolength = true }, -- restart + [0xD4] = { name = "RST4", zerolength = true }, -- restart + [0xD5] = { name = "RST5", zerolength = true }, -- restart + [0xD6] = { name = "RST6", zerolength = true }, -- restart + [0xD7] = { name = "RST7", zerolength = true }, -- restart + + [0xD8] = { name = "SOI", zerolength = true }, -- start of image + [0xD9] = { name = "EOI", zerolength = true }, -- end of image + [0xDA] = { name = "SOS" }, -- start of scan + [0xDB] = { name = "DQT" }, -- define quantization tables + [0xDC] = { name = "DNL" }, -- define number of lines + [0xDD] = { name = "DRI" }, -- define restart interval + [0xDE] = { name = "DHP" }, -- define hierarchical progression + [0xDF] = { name = "EXP" }, -- expand reference image(s) + + [0xE0] = { name = "APP0" }, -- application marker, used for JFIF + [0xE1] = { name = "APP1" }, -- application marker + [0xE2] = { name = "APP2" }, -- application marker + [0xE3] = { name = "APP3" }, -- application marker + [0xE4] = { name = "APP4" }, -- application marker + [0xE5] = { name = "APP5" }, -- application marker + [0xE6] = { name = "APP6" }, -- application marker + [0xE7] = { name = "APP7" }, -- application marker + [0xE8] = { name = "APP8" }, -- application marker + [0xE9] = { name = "APP9" }, -- application marker + [0xEA] = { name = "APP10" }, -- application marker + [0xEB] = { name = "APP11" }, -- application marker + [0xEC] = { name = "APP12" }, -- application marker + [0xED] = { name = "APP13" }, -- application marker + [0xEE] = { name = "APP14" }, -- application marker, used by Adobe + [0xEF] = { name = "APP15" }, -- application marker + + [0xF0] = { name = "JPG0" }, -- reserved for JPEG extensions + [0xFD] = { name = "JPG13" }, -- reserved for JPEG extensions + [0xFE] = { name = "COM" }, -- comment + + [0x01] = { name = "TEM", zerolength = true }, -- temporary use + } + + -- More can be found in http://www.exif.org/Exif2-2.PDF but basically we have + -- good old tiff tags here. + + local function read_APP1_Exif(f, xres, yres, orientation) -- untested + local position = false + local readcardinal2 = readcardinal2 + local readcardinal4 = readcardinal4 + -- endian II|MM + while true do + position = getposition(f) + local b = readbyte(f) + if b == 0 then + -- next one + elseif b == 0x4D and readbyte(f) == 0x4D then -- M + -- big endian + break + elseif b == 0x49 and readbyte(f) == 0x49 then -- I + -- little endian + readcardinal2 = readcardinal2le + readcardinal4 = readcardinal4le + break + else + -- warning "bad exif data" + return xres, yres, orientation + end + end + -- version + local version = readcardinal2(f) + if version ~= 42 then + return xres, yres, orientation + end + -- offset to records + local offset = readcardinal4(f) + if not offset then + return xres, yres, orientation + end + setposition(f,position + offset) + local entries = readcardinal2(f) + if not entries or entries == 0 then + return xres, yres, orientation + end + local x_res, y_res, x_res_ms, y_res_ms, x_temp, y_temp + local res_unit, res_unit_ms + for i=1,entries do + local tag = readcardinal2(f) + local kind = readcardinal2(f) + local size = readcardinal4(f) + local value = 0 + local num = 0 + local den = 0 + if kind == 1 or kind == 7 then -- byte | undefined + value = readbyte(f) + skipbytes(f,3) + elseif kind == 3 or kind == 8 then -- (un)signed short + value = readcardinal2(f) + skipbytes(f,2) + elseif kind == 4 or kind == 9 then -- (un)signed long + value = readcardinal4(f) + elseif kind == 5 or kind == 10 then -- (s)rational + local offset = readcardinal4(f) + local saved = getposition(f) + setposition(f,position+offset) + num = readcardinal4(f) + den = readcardinal4(f) + setposition(f,saved) + else -- 2 -- ascii + skipbytes(f,4) + end + if tag == 274 then -- orientation + orientation = value + elseif tag == 282 then -- x resolution + if den ~= 0 then + x_res = num/den + end + elseif tag == 283 then -- y resolution + if den ~= 0 then + y_res = num/den + end + elseif tag == 296 then -- resolution unit + if value == 2 then + res_unit = 1 + elseif value == 3 then + res_unit = 2.54 + end + elseif tag == 0x5110 then -- pixel unit + res_unit_ms = value == 1 + elseif tag == 0x5111 then -- x pixels per unit + x_res_ms = value + elseif tag == 0x5112 then -- y pixels per unit + y_res_ms = value + end + end + if x_res and y_res and res_unit and res_unit > 0 then + x_temp = round(x_res * res_unit) + y_temp = round(y_res * res_unit) + elseif x_res_ms and y_res_ms and res_unit_ms then + x_temp = round(x_res_ms * 0.0254) -- in meters + y_temp = round(y_res_ms * 0.0254) -- in meters + end + if x_temp and a_temp and x_temp > 0 and y_temp > 0 then + if (x_temp ~= x_res or y_temp ~= y_res) and x_res ~= 0 and y_res ~= 0 then + -- exif resolution differs from already found resolution + elseif x_temp == 1 or y_temp == 1 then + -- exif resolution is kind of weird + else + return x_temp, y_temp, orientation + end + end + return round(xres), round(yres), orientation + end + + function identifiers.jpg(filename) + local specification = { + filename = filename, + filetype = "jpg", + } + if not filename or filename == "" then + specification.error = "invalid filename" + return specification -- error + end + local f = io.open(filename,"rb") + if not f then + specification.error = "unable to open file" + return specification -- error + end + specification.xres = 0 + specification.yres = 0 + specification.orientation = 1 + specification.totalpages = 1 + specification.pagenum = 1 + specification.length = 0 + local banner = readcardinal2(f) + if banner ~= 0xFFD8 then + specification.error = "no jpeg file" + return specification -- error + end + local xres = 0 + local yres = 0 + local orientation = 1 + local okay = false + local filesize = getsize(f) -- seek end + local majorversion = pdfmajorversion and pdfmajorversion() or 2 + local minorversion = pdfminorversion and pdfminorversion() or 2 + while getposition(f) < filesize do + local b = readbyte(f) + if not b then + break + elseif b ~= 0xFF then + if not okay then + -- or check for size + specification.error = "incomplete file" + end + break + end + local category = readbyte(f) + local position = getposition(f) + local length = 0 + local tagdata = tags[category] + if not tagdata then + specification.error = "invalid tag" + break + elseif tagdata.supported == false then + specification.error = "unsupported " .. tagdata.comment + break + end + local name = tagdata.name + if name == "SOF0" or name == "SOF1" or name == "SOF2" then + if majorversion == 1 and minorversion <= 2 then + specification.error = "no progressive DCT in PDF <= 1.2" + break + end + length = readcardinal2(f) + specification.colordepth = readcardinal(f) + specification.ysize = readcardinal2(f) + specification.xsize = readcardinal2(f) + specification.colorspace = colorspaces[readcardinal(f)] + if not specification.colorspace then + specification.error = "unsupported color space" + break + end + okay = true + elseif name == "APP0" then + length = readcardinal2(f) + if length > 6 then + local format = readstring(f,5) + if format == "JFIF\000" then + skipbytes(f,2) + units = readcardinal(f) + xres = readcardinal2(f) + yres = readcardinal2(f) + if units == 1 then + -- pixels per inch + if xres == 1 or yres == 1 then + -- warning + end + elseif units == 2 then + -- pixels per cm */ + xres = xres * 2.54 + yres = yres * 2.54 + else + xres = 0 + yres = 0 + end + end + end + elseif name == "APP1" then + length = readcardinal2(f) + if length > 7 then + local format = readstring(f,5) + if format == "Exif\000" then + xres, yres, orientation = read_APP1_Exif(f,xres,yres,orientation) + end + end + elseif not tagdata.zerolength then + length = readcardinal2(f) + end + if length > 0 then + setposition(f,position+length) + end + end + f:close() + if not okay then + specification.error = specification.error or "invalid file" + elseif not specification.error then + if xres == 0 and yres ~= 0 then + xres = yres + end + if yres == 0 and xres ~= 0 then + yres = xres + end + end + specification.xres = xres + specification.yres = yres + specification.orientation = orientation + specification.length = filesize + return specification + end + +end + +do + + local function read_boxhdr(specification,f) + local size = readcardinal4(f) + local kind = readstring(f,4) + if kind then + kind = strip(lower(kind)) + else + kind = "" + end + if size == 1 then + size = readcardinal4(f) * 0xFFFF0000 + readcardinal4(f) + end + if size == 0 and kind ~= "jp2c" then -- move this + specification.error = "invalid size" + end + return kind, size + end + + local function scan_ihdr(specification,f) + specification.ysize = readcardinal4(f) + specification.xsize = readcardinal4(f) + skipbytes(f,2) -- nc + specification.colordepth = readcardinal(f) + 1 + skipbytes(f,3) -- c unkc ipr + end + + local function scan_resc_resd(specification,f) + local vr_n = readcardinal2(f) + local vr_d = readcardinal2(f) + local hr_n = readcardinal2(f) + local hr_d = readcardinal2(f) + local vr_e = readcardinal(f) + local hr_e = readcardinal(f) + specification.xres = math.round((hr_n / hr_d) * math.exp(hr_e * math.log(10.0)) * 0.0254) + specification.yres = math.round((vr_n / vr_d) * math.exp(vr_e * math.log(10.0)) * 0.0254) + end + + local function scan_res(specification,f,last) + local pos = getposition(f) + while true do + local kind, size = read_boxhdr(specification,f) + pos = pos + size + if kind == "resc" then + if specification.xres == 0 and specification.yres == 0 then + scan_resc_resd(specification,f) + if getposition(f) ~= pos then + specification.error = "invalid resc" + return + end + end + elseif tpos == "resd" then + scan_resc_resd(specification,f) + if getposition(f) ~= pos then + specification.error = "invalid resd" + return + end + elseif pos > last then + specification.error = "invalid res" + return + elseif pos == last then + break + end + if specification.error then + break + end + setposition(f,pos) + end + end + + local function scan_jp2h(specification,f,last) + local okay = false + local pos = getposition(f) + while true do + local kind, size = read_boxhdr(specification,f) + pos = pos + size + if kind == "ihdr" then + scan_ihdr(specification,f) + if getposition(f) ~= pos then + specification.error = "invalid ihdr" + return false + end + okay = true + elseif kind == "res" then + scan_res(specification,f,pos) + elseif pos > last then + specification.error = "invalid jp2h" + return false + elseif pos == last then + break + end + if specification.error then + break + end + setposition(f,pos) + end + return okay + end + + function identifiers.jp2(filename) + local specification = { + filename = filename, + filetype = "jp2", + } + if not filename or filename == "" then + specification.error = "invalid filename" + return specification -- error + end + local f = io.open(filename,"rb") + if not f then + specification.error = "unable to open file" + return specification -- error + end + specification.xres = 0 + specification.yres = 0 + specification.orientation = 1 + specification.totalpages = 1 + specification.pagenum = 1 + specification.length = 0 + local xres = 0 + local yres = 0 + local orientation = 1 + local okay = false + local filesize = getsize(f) -- seek end + local majorversion = pdfmajorversion and pdfmajorversion() or 2 + local minorversion = pdfminorversion and pdfminorversion() or 2 + -- + local pos = 0 + -- signature + local kind, size = read_boxhdr(specification,f) + pos = pos + size + setposition(f,pos) + -- filetype + local kind, size = read_boxhdr(specification,f) + if kind ~= "ftyp" then + specification.error = "missing ftyp box" + return specification + end + pos = pos + size + setposition(f,pos) + while not okay do + local kind, size = read_boxhdr(specification,f) + pos = pos + size + if kind == "jp2h" then + okay = scan_jp2h(specification,f,pos) + elseif kind == "jp2c" and not okay then + specification.error = "no ihdr box found" + return specification + end + setposition(f,pos) + end + -- + f:close() + if not okay then + specification.error = "invalid file" + elseif not specification.error then + if xres == 0 and yres ~= 0 then + xres = yres + end + if yres == 0 and xres ~= 0 then + yres = xres + end + end + specification.xres = xres + specification.yres = yres + specification.orientation = orientation + specification.length = filesize + return specification + end + +end + +do + + -- 0 = gray "image b" + -- 2 = rgb "image c" + -- 3 = palette "image c" + "image i" + -- 4 = gray + alpha "image b" + -- 6 = rgb + alpha "image c" + + -- for i=1,length/3 do + -- palette[i] = readstring(f,3) + -- end + + local function grab(t,f,once) + if once then + for i=1,#t do + local l = t[i] + setposition(f,l.offset) + t[i] = readstring(f,l.length) + end + local data = concat(t) + -- t wiped in caller + return data + else + local data = { } + for i=1,#t do + local l = t[i] + setposition(f,l.offset) + data[i] = readstring(f,l.length) + end + return concat(data) + end + end + + function identifiers.png(filename) + local specification = { + filename = filename, + filetype = "png", + } + if not filename or filename == "" then + specification.error = "invalid filename" + return specification -- error + end + local f = io.open(filename,"rb") + if not f then + specification.error = "unable to open file" + return specification -- error + end + specification.xres = 0 + specification.yres = 0 + specification.orientation = 1 + specification.totalpages = 1 + specification.pagenum = 1 + specification.offset = 0 + specification.length = 0 + local filesize = getsize(f) -- seek end + local tables = { } + local banner = readstring(f,8) + if banner ~= "\137PNG\013\010\026\010" then + specification.error = "no png file" + return specification -- error + end + while true do + local position = getposition(f) + if position >= filesize then + break + end + local length = readcardinal4(f) + if not length then + break + end + local kind = readstring(f,4) + if kind then + kind = lower(kind) + else + break + end + if kind == "ihdr" then -- metadata + specification.xsize = readcardinal4(f) + specification.ysize = readcardinal4(f) + specification.colordepth = readcardinal(f) + specification.colorspace = readcardinal(f) + specification.compression = readcardinal(f) + specification.filter = readcardinal(f) + specification.interlace = readcardinal(f) + tables[kind] = true + elseif kind == "iend" then + tables[kind] = true + break + elseif kind == "phys" then + local x = readcardinal4(f) + local y = readcardinal4(f) + local u = readcardinal(f) + if u == 1 then -- meters + -- x = round(0.0254 * x) + -- y = round(0.0254 * y) + end + specification.xres = x + specification.yres = y + tables[kind] = true + elseif kind == "idat" or kind == "plte" or kind == "gama" or kind == "trns" then + local t = tables[kind] + if not t then + t = setmetatablecall(grab) + tables[kind] = t + end + t[#t+1] = { + offset = getposition(f), + length = length, + } + else + tables[kind] = true + end + setposition(f,position+length+12) -- #size #kind #crc + end + specification.tables = tables + return specification + end + +end + +do + + local function gray(t,k) + local v = 0 + t[k] = v + return v + end + + local function rgb(t,k) + local v = { 0, 0, 0 } + t[k] = v + return v + end + + local function cmyk(t,k) + local v = { 0, 0, 0, 0 } + t[k] = v + return v + end + + function identifiers.bitmap(specification) + local xsize = specification.xsize or 0 + local ysize = specification.ysize or 0 + local width = specification.width or xsize * 65536 + local height = specification.height or ysize * 65536 + local colordepth = specification.colordepth or 1 -- 1 .. 2 + local colorspace = specification.colorspace or 1 -- 1 .. 3 + local pixel = false + local data = specification.data + local mask = specification.mask + if colorspace == 1 or colorspace == "gray" then + pixel = gray + colorspace = 1 + elseif colorspace == 2 or colorspace == "rgb" then + pixel = rgb + colorspace = 2 + elseif colorspace == 3 or colorspace == "cmyk" then + pixel = cmyk + colorspace = 3 + else + return + end + if colordepth == 8 then + colordepth = 1 + elseif colordepth == 16 then + colordepth = 2 + end + if colordepth > 1 then + -- not yet + return + end + if data then + -- assume correct data + else + data = { } + for i=1,ysize do + data[i] = setmetatableindex(pixel) + end + end + if mask == true then + mask = { } + for i=1,ysize do + mask[i] = setmetatableindex(gray) + end + end + local specification = { + xsize = xsize, + ysize = ysize, + width = width, + height = height, + colordepth = colordepth, + colorspace = colorspace, + data = data, + mask = mask, + } + return specification + end + +end + +function graphics.identify(filename,filetype) + local identify = filetype and identifiers[filetype] + if identify then + return identify(filename) + end + local identify = identifiers[suffixonly(filename)] + if identify then + identify = identify(filename) + else + identify = { + filename = filename, + filetype = filetype, + error = "identification failed", + } + end + -- inspect(identify) + return identify +end + +-- inspect(identifiers.jpg("t:/sources/hacker.jpg")) +-- inspect(identifiers.png("t:/sources/mill.png")) diff --git a/tex/context/base/mkiv/grph-inc.lua b/tex/context/base/mkiv/grph-inc.lua index ee4ed2a28..0856e0de9 100644 --- a/tex/context/base/mkiv/grph-inc.lua +++ b/tex/context/base/mkiv/grph-inc.lua @@ -124,8 +124,8 @@ local ctx_doboxfigureobject = context.doboxfigureobject function checkimage(figure) if figure then - local width = figure.width - local height = figure.height + local width = figure.width or 0 + local height = figure.height or 0 if width <= 0 or height <= 0 then report_inclusion("image %a has bad dimensions (%p,%p), discarding",figure.filename or "?",width,height) return false, "bad dimensions" @@ -162,28 +162,28 @@ end local __img__ = type(img) == "table" and img or { } images.__img__ =__img__ -local img_new = __img__.new -local img_scan = __img__.scan -local img_copy = __img__.copy -local img_wrap = __img__.node -local img_embed = __img__.immediatewrite +local imgnew = __img__.new +local imgscan = __img__.scan +local imgcopy = __img__.copy +local imgwrap = __img__.node +local imgembed = __img__.immediatewrite -if img_new then +if imgnew then -- catch (actually we should be less picky in img) - local __img__new__ = img_new - img_new = function(t) + local __img__new__ = imgnew + imgnew = function(t) t.kind = nil return __img__new__(t) end end -updaters.register("backend.update",function() +updaters.register("backend.update.img",function() local img = images.__img__ - img_new = img.new - img_scan = img.scan - img_copy = img.copy - img_wrap = img.wrap - img_embed = img.embed + imgnew = img.new + imgscan = img.scan + imgcopy = img.copy + imgwrap = img.wrap + imgembed = img.embed end) local imagekeys = { -- only relevant ones @@ -217,25 +217,25 @@ images.sizes = imagesizes -- new interface local function createimage(specification) - return img_new(specification) + return imgnew(specification) end local function copyimage(specification) - return img_copy(specification) + return imgcopy(specification) end local function scanimage(specification) - return img_scan(specification) + return imgscan(specification) end local function embedimage(specification) -- write the image to file - return img_embed(specification) + return imgembed(specification) end local function wrapimage(specification) -- create an image rule - return img_wrap(specification) + return imgwrap(specification) end images.create = createimage @@ -918,6 +918,7 @@ local function register(askedname,specification) format = suffix end end +specification.format = format elseif io.exists(oldname) then report_inclusion("file %a is bugged",oldname) if format and imagetypes[format] then @@ -1285,6 +1286,7 @@ function figures.identify(data) for i=1,#list do local identifier = list[i] local data = identifier(data) +-- if data and (not data.status and data.status.status > 0) then if data and (not data.status and data.status.status > 0) then break end @@ -1575,6 +1577,11 @@ function figures.getrealpage(index) return pofimages[index] or 0 end +local function updatepage(specification) + local n = specification.n + pofimages[n] = pofimages[n] or tex.count.realpageno -- so when reused we register the first one only +end + function includers.generic(data) local dr, du, ds = data.request, data.used, data.status -- here we set the 'natural dimensions' @@ -1603,18 +1610,16 @@ function includers.generic(data) nofimages = nofimages + 1 ds.pageindex = nofimages local image = wrapimage(figure) - local pager = new_latelua(function() - pofimages[nofimages] = pofimages[nofimages] or tex.count.realpageno -- so when reused we register the first one only - end) - image.next = pager - pager.prev = image - local box = hpack(image) - -- indexed[figure.index] = figure - box.width = figure.width - box.height = figure.height - box.depth = 0 + local pager = new_latelua { action = updatepage, n = nofimages } + image.next = pager + pager.prev = image + local box = hpack(image) + box.width = figure.width + box.height = figure.height + box.depth = 0 texsetbox(nr,box) ds.objectnumber = figure.objnum + -- indexed[figure.index] = figure ctx_relocateexternalfigure() end return data @@ -1691,6 +1696,7 @@ local ctx_docheckfiguremps = context.docheckfiguremps local function internal(askedname) local spec, mprun, mpnum = match(lower(askedname),"mprun([:%.]?)(.-)%.(%d+)") + -- mpnum = tonumber(mpnum) or 0 -- can be string or number, fed to context anyway if spec ~= "" then return mprun, mpnum else diff --git a/tex/context/base/mkiv/grph-inc.mkiv b/tex/context/base/mkiv/grph-inc.mkiv index 6379c150d..20e7c11a6 100644 --- a/tex/context/base/mkiv/grph-inc.mkiv +++ b/tex/context/base/mkiv/grph-inc.mkiv @@ -40,7 +40,7 @@ %D Including graphics is complicated by the fact that we need to locate them first, %D optionally manipulate them and scale then next. Lookups are to be done as efficient %D as possible and inclusion of the data might happens only once. In \MKIV\ much of this -%D is delegated to the \LUA\ end. There is nor so much less code as in \MKII\ but it's +%D is delegated to the \LUA\ end. There is not so much less code as in \MKII\ but it's %D more powerful, flexible, pluggable and some of the extended functionality has been %D moved from modules to the core. The overall functionality is rather stable and has %D not changed much over the years. diff --git a/tex/context/base/mkiv/l-bit32.lua b/tex/context/base/mkiv/l-bit32.lua index 5f35b8fee..25716e0a8 100644 --- a/tex/context/base/mkiv/l-bit32.lua +++ b/tex/context/base/mkiv/l-bit32.lua @@ -20,7 +20,7 @@ elseif utf8 then -- lua 5.3: bitwise.lua, v 1.24 2014/12/26 17:20:53 roberto - bit32 = load ( [[ + load ( [[ local select = select -- instead of: arg = { ... } bit32 = { @@ -105,13 +105,13 @@ bit32 = { return ((a & ~(mask << f)) | ((v & mask) << f)) & 0xFFFFFFFF end, } - ]] ) + ]] ) () elseif bit then -- luajit (for now) - bit32 = load ( [[ + load ( [[ local band, bnot, rshift, lshift = bit.band, bit.bnot, bit.rshift, bit.lshift bit32 = { @@ -135,7 +135,7 @@ bit32 = { rrotate = bit.ror, rshift = rshift, } - ]] ) + ]] ) () else @@ -146,5 +146,3 @@ else xpcall(function() local _, t = require("bit32") if t then bit32 = t end return end,function() end) end - -return bit32 or false diff --git a/tex/context/base/mkiv/l-dir.lua b/tex/context/base/mkiv/l-dir.lua index b0b2c5283..325039cb1 100644 --- a/tex/context/base/mkiv/l-dir.lua +++ b/tex/context/base/mkiv/l-dir.lua @@ -91,13 +91,15 @@ local function glob_pattern_function(path,patt,recurse,action) end local dirs local nofdirs = 0 - for name in walkdir(usedpath) do + for name, mode, size, time in walkdir(usedpath) do if name ~= "." and name ~= ".." then local full = path .. name - local mode = attributes(full,'mode') + if mode == nil then + mode = attributes(full,'mode') + end if mode == 'file' then if not patt or find(full,patt) then - action(full) + action(full,size,time) end elseif recurse and mode == "directory" then if dirs then @@ -134,10 +136,12 @@ local function glob_pattern_table(path,patt,recurse,result) local dirs local nofdirs = 0 local noffiles = #result - for name, a in walkdir(usedpath) do + for name, mode in walkdir(usedpath) do if name ~= "." and name ~= ".." then local full = path .. name - local mode = attributes(full,'mode') + if mode == nil then + mode = attributes(full,'mode') + end if mode == 'file' then if not patt or find(full,patt) then noffiles = noffiles + 1 @@ -193,7 +197,7 @@ local function collectpattern(path,patt,recurse,result) if not find(path,"/$") then path = path .. '/' end - for name in scanner, first do + for name in scanner, first do -- cna be optimized if name == "." then -- skip elseif name == ".." then @@ -321,11 +325,13 @@ local function globfiles(path,recurse,func,files) -- func == pattern or function end files = files or { } local noffiles = #files - for name in walkdir(path) do + for name, mode in walkdir(path) do if find(name,"^%.") then --- skip else - local mode = attributes(name,'mode') + if mode == nil then + mode = attributes(name,'mode') + end if mode == "directory" then if recurse then globfiles(path .. "/" .. name,recurse,func,files) @@ -350,11 +356,13 @@ local function globdirs(path,recurse,func,files) -- func == pattern or function end files = files or { } local noffiles = #files - for name in walkdir(path) do + for name, mode in walkdir(path) do if find(name,"^%.") then --- skip else - local mode = attributes(name,'mode') + if mode == nil then + mode = attributes(name,'mode') + end if mode == "directory" then if not func or func(name) then noffiles = noffiles + 1 @@ -597,8 +605,7 @@ local stack = { } function dir.push(newdir) local curdir = currentdir() insert(stack,curdir) - if newdir and newdir ~= "" then - chdir(newdir) + if newdir and newdir ~= "" and chdir(newdir) then return newdir else return curdir diff --git a/tex/context/base/mkiv/l-file.lua b/tex/context/base/mkiv/l-file.lua index 46b6847d3..1b039a438 100644 --- a/tex/context/base/mkiv/l-file.lua +++ b/tex/context/base/mkiv/l-file.lua @@ -73,13 +73,9 @@ local P, R, S, C, Cs, Cp, Cc, Ct = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpeg -- better this way: ------ tricky = S("/\\") * P(-1) local attributes = lfs.attributes function lfs.isdir(name) - -- if not lpegmatch(tricky,name) then - -- name = name .. "/." - -- end return attributes(name,"mode") == "directory" end @@ -336,43 +332,52 @@ end -- But after some testing Taco and I came up with the more robust -- variant: -function file.is_writable(name) - if not name then - -- error - elseif lfs.isdir(name) then - name = name .. "/m_t_x_t_e_s_t.tmp" - local f = io.open(name,"wb") - if f then - f:close() - os.remove(name) - return true - end - elseif lfs.isfile(name) then - local f = io.open(name,"ab") - if f then - f:close() - return true - end - else - local f = io.open(name,"ab") - if f then - f:close() - os.remove(name) - return true +if lfs.isreadablefile and lfs.iswritablefile then + + file.is_readable = lfs.isreadablefile + file.is_writable = lfs.iswritablefile + +else + + function file.is_writable(name) + if not name then + -- error + elseif lfs.isdir(name) then + name = name .. "/m_t_x_t_e_s_t.tmp" + local f = io.open(name,"wb") + if f then + f:close() + os.remove(name) + return true + end + elseif lfs.isfile(name) then + local f = io.open(name,"ab") + if f then + f:close() + return true + end + else + local f = io.open(name,"ab") + if f then + f:close() + os.remove(name) + return true + end end + return false end - return false -end -local readable = P("r") * Cc(true) + local readable = P("r") * Cc(true) -function file.is_readable(name) - if name then - local a = attributes(name) - return a and lpegmatch(readable,a.permissions) or false - else - return false + function file.is_readable(name) + if name then + local a = attributes(name) + return a and lpegmatch(readable,a.permissions) or false + else + return false + end end + end file.isreadable = file.is_readable -- depricated diff --git a/tex/context/base/mkiv/l-lua.lua b/tex/context/base/mkiv/l-lua.lua index ddd499022..5570e83dc 100644 --- a/tex/context/base/mkiv/l-lua.lua +++ b/tex/context/base/mkiv/l-lua.lua @@ -228,10 +228,10 @@ elseif not ffi.number then ffi.number = tonumber end -if not bit32 then -- and utf8 then - -- bit32 = load ( [[ -- replacement code with 5.3 syntax so that 5.2 doesn't bark on it ]] ) - bit32 = require("l-bit32") -end +-- if not bit32 then -- and utf8 then +-- -- bit32 = load ( [[ -- replacement code with 5.3 syntax so that 5.2 doesn't bark on it ]] ) +-- bit32 = require("l-bit32") +-- end -- We need this due a bug in luatex socket loading: @@ -248,3 +248,8 @@ end -- if not loaded["socket.smtp"] then loaded["socket.smtp"] = socket.smtp end -- if not loaded["socket.tp"] then loaded["socket.tp"] = socket.tp end -- if not loaded["socket.url"] then loaded["socket.url"] = socket.url end + +if LUAVERSION > 5.3 then + -- collectgarbage("collect") + -- collectgarbage("generational") -- crashes on unix +end diff --git a/tex/context/base/mkiv/l-os.lua b/tex/context/base/mkiv/l-os.lua index cf469f79d..aa04e254d 100644 --- a/tex/context/base/mkiv/l-os.lua +++ b/tex/context/base/mkiv/l-os.lua @@ -227,25 +227,12 @@ local launchers = { } function os.launch(str) - execute(format(launchers[os.name] or launchers.unix,str)) + local command = format(launchers[os.name] or launchers.unix,str) + -- todo: pcall +-- print(command) + execute(command) end -if not os.times then -- ? - -- utime = user time - -- stime = system time - -- cutime = children user time - -- cstime = children system time - function os.times() - return { - utime = os.gettimeofday(), -- user - stime = 0, -- system - cutime = 0, -- children user - cstime = 0, -- children system - } - end -end - - local gettimeofday = os.gettimeofday or os.clock os.gettimeofday = gettimeofday diff --git a/tex/context/base/mkiv/l-table.lua b/tex/context/base/mkiv/l-table.lua index eae135139..192347b06 100644 --- a/tex/context/base/mkiv/l-table.lua +++ b/tex/context/base/mkiv/l-table.lua @@ -8,7 +8,7 @@ if not modules then modules = { } end modules ['l-table'] = { local type, next, tostring, tonumber, select = type, next, tostring, tonumber, select local table, string = table, string -local concat, sort, insert, remove = table.concat, table.sort, table.insert, table.remove +local concat, sort = table.concat, table.sort local format, lower, dump = string.format, string.lower, string.dump local getmetatable, setmetatable = getmetatable, setmetatable local lpegmatch, patterns = lpeg.match, lpeg.patterns @@ -26,7 +26,8 @@ function table.getn(t) end function table.strip(tab) - local lst, l = { }, 0 + local lst = { } + local l = 0 for i=1,#tab do local s = lpegmatch(stripper,tab[i]) or "" if s == "" then @@ -41,7 +42,8 @@ end function table.keys(t) if t then - local keys, k = { }, 0 + local keys = { } + local k = 0 for key in next, t do k = k + 1 keys[k] = key @@ -145,28 +147,30 @@ end local function sortedkeys(tab) if tab then - local srt, category, s = { }, 0, 0 -- 0=unknown 1=string, 2=number 3=mixed + local srt = { } + local category = 0 -- 0=unknown 1=string, 2=number 3=mixed + local s = 0 for key in next, tab do s = s + 1 srt[s] = key - if category == 3 then - -- no further check - elseif category == 1 then - if type(key) ~= "string" then - category = 3 - end - elseif category == 2 then - if type(key) ~= "number" then - category = 3 - end - else + if category ~= 3 then local tkey = type(key) - if tkey == "string" then - category = 1 - elseif tkey == "number" then - category = 2 + if category == 1 then + if tkey ~= "string" then + category = 3 + end + elseif category == 2 then + if tkey ~= "number" then + category = 3 + end else - category = 3 + if tkey == "string" then + category = 1 + elseif tkey == "number" then + category = 2 + else + category = 3 + end end end end @@ -185,7 +189,8 @@ end local function sortedhashonly(tab) if tab then - local srt, s = { }, 0 + local srt = { } + local s = 0 for key in next, tab do if type(key) == "string" then s = s + 1 @@ -203,7 +208,8 @@ end local function sortedindexonly(tab) if tab then - local srt, s = { }, 0 + local srt = { } + local s = 0 for key in next, tab do if type(key) == "number" then s = s + 1 @@ -221,7 +227,8 @@ end local function sortedhashkeys(tab,cmp) -- fast one if tab then - local srt, s = { }, 0 + local srt = { } + local s = 0 for key in next, tab do if key then s= s + 1 @@ -317,7 +324,9 @@ end -- end function table.merge(t, ...) -- first one is target - t = t or { } + if not t then + t = { } + end for i=1,select("#",...) do for k, v in next, (select(i,...)) do t[k] = v @@ -383,7 +392,8 @@ end -- end function table.imerged(...) - local tmp, ntmp = { }, 0 + local tmp = { } + local ntmp = 0 for i=1,select("#",...) do local nst = select(i,...) for j=1,#nst do @@ -420,7 +430,9 @@ end -- todo : copy without metatable local function copy(t,tables) -- taken from lua wiki, slightly adapted - tables = tables or { } + if not tables then + tables = { } + end local tcopy = { } if not tables[t] then tables[t] = tcopy @@ -471,7 +483,8 @@ function table.tohash(t,value) end function table.fromhash(t) - local hsh, h = { }, 0 + local hsh = { } + local h = 0 for k, v in next, t do if v then h = h + 1 @@ -669,7 +682,8 @@ local function do_serialize(root,name,depth,level,indexed) end -- we could check for k (index) being number (cardinal) if root and next(root) ~= nil then - local first, last = nil, 0 + local first = nil + local last = 0 if compact then last = #root for k=1,last do @@ -960,7 +974,8 @@ end -- number : [number] = { } function table.serialize(root,name,specification) - local t, n = { }, 0 + local t = { } + local n = 0 local function flush(s) n = n + 1 t[n] = s @@ -984,13 +999,15 @@ function table.tofile(filename,root,name,specification) local f = io.open(filename,'w') if f then if maxtab > 1 then - local t, n = { }, 0 + local t = { } + local n = 0 local function flush(s) n = n + 1 t[n] = s if n > maxtab then f:write(concat(t,"\n"),"\n") -- hm, write(sometable) should be nice - t, n = { }, 0 -- we could recycle t if needed + t = { } -- we could recycle t if needed + n = 0 end end serialize(flush,root,name,specification) @@ -1008,12 +1025,12 @@ end local function flattened(t,f,depth) -- also handles { nil, 1, nil, 2 } if f == nil then - f = { } + f = { } depth = 0xFFFF elseif tonumber(f) then -- assume that only two arguments are given depth = f - f = { } + f = { } elseif not depth then depth = 0xFFFF end @@ -1101,8 +1118,12 @@ local function are_equal(a,b,n,m) -- indexed if a == b then return true elseif a and b and #a == #b then - n = n or 1 - m = m or #a + if not n then + n = 1 + end + if not m then + m = #a + end for i=n,m do local ai, bi = a[i], b[i] if ai==bi then @@ -1215,7 +1236,8 @@ end function table.reversed(t) if t then - local tt, tn = { }, #t + local tt = { } + local tn = #t if tn > 0 then local ttn = 0 for i=tn,1,-1 do @@ -1332,8 +1354,8 @@ end function table.unique(old) local hash = { } - local new = { } - local n = 0 + local new = { } + local n = 0 for i=1,#old do local oi = old[i] if not hash[oi] then @@ -1354,12 +1376,14 @@ end function table.values(t,s) -- optional sort flag if t then - local values, keys, v = { }, { }, 0 + local values = { } + local keys = { } + local v = 0 for key, value in next, t do if not keys[value] then v = v + 1 values[v] = value - keys[k] = key + keys[k] = key end end if s then diff --git a/tex/context/base/mkiv/lang-dis.lua b/tex/context/base/mkiv/lang-dis.lua index 5603d1193..90e84f65d 100644 --- a/tex/context/base/mkiv/lang-dis.lua +++ b/tex/context/base/mkiv/lang-dis.lua @@ -180,7 +180,6 @@ end -- experiment: for now not in not in export mode! local flatten = languages.flatten -local getlist = nodes.getlist nodes.handlers.flattenline = flatten diff --git a/tex/context/base/mkiv/lang-txt.lua b/tex/context/base/mkiv/lang-txt.lua index d287f7e6d..daf8f787e 100644 --- a/tex/context/base/mkiv/lang-txt.lua +++ b/tex/context/base/mkiv/lang-txt.lua @@ -64,6 +64,8 @@ local languages = languages languages.data = languages.data or utilities.storage.allocate { } local data = languages.data +local hairspace = utf.char(0x200A) + data.labels={ ["btx"]={ ["In"]={ @@ -627,6 +629,18 @@ data.labels={ }, }, ["texts"]={ + ["following:singular"]={ + ["labels"]={ + ["en"]="f.", + ["fr"]=hairspace .. "sq", + }, + }, + ["following:plural"]={ + ["labels"]={ + ["en"]="ff.", + ["fr"]=hairspace .. "sqq", + }, + }, ["and"]={ ["labels"]={ ["af"]="", diff --git a/tex/context/base/mkiv/lpdf-ano.lua b/tex/context/base/mkiv/lpdf-ano.lua index bf9d6926f..49bf973c9 100644 --- a/tex/context/base/mkiv/lpdf-ano.lua +++ b/tex/context/base/mkiv/lpdf-ano.lua @@ -157,7 +157,9 @@ directives.register("references.border",function(v) local c = m and m[v] local v = c and attributes.colors.value(c) if v then - local r, g, b = v[3], v[4], v[5] + local r = v[3] + local g = v[4] + local b = v[5] -- if r == g and g == b then -- pdf_border_color = pdfarray { r } -- reduced, not not ... bugged viewers -- else @@ -466,13 +468,15 @@ local pagedestinations = setmetatableindex(function(t,k) -- not the same as the return v end) -local function flushdestination(width,height,depth,names,view) - local r = pdfpagereference(texgetcount("realpageno")) +local function flushdestination(specification) + local names = specification.names + local view = specification.view + local r = pdfpagereference(texgetcount("realpageno")) if (references.innermethod ~= v_name) and (view == defaultview or not view or view == "") then r = pagedestinations[r] else local action = view and destinationactions[view] or defaultaction - r = pdfdelayedobject(action(r,width,height,depth,offset)) + r = pdfdelayedobject(action(r,specification.width,specification.height,specification.depth,offset)) end for n=1,#names do local name = names[n] @@ -554,7 +558,14 @@ function nodeinjections.destination(width,height,depth,names,view) end end if doview then - return new_latelua(function() flushdestination(width,height,depth,names,view) end) + return new_latelua { + action = flushdestination, + width = width, + height = height, + depth = depth, + names = names, + view = view, + } end end @@ -766,24 +777,26 @@ setmetatableindex(hashed,function(t,k) return v end) -local function finishreference(width,height,depth,prerolled) -- %0.2f looks okay enough (no scaling anyway) - local annot = hashed[f_annot(prerolled,pdfrectangle(width,height,depth))] +local function finishreference(specification) -- %0.2f looks okay enough (no scaling anyway) + local annot = hashed[f_annot(specification.prerolled,pdfrectangle(specification.width,specification.height,specification.depth))] nofused = nofused + 1 return pdfregisterannotation(annot) end -local function finishannotation(width,height,depth,prerolled,r) +local function finishannotation(specification) + local prerolled = specification.prerolled + local objref = specification.objref if type(prerolled) == "function" then prerolled = prerolled() end - local annot = f_annot(prerolled,pdfrectangle(width,height,depth)) - if r then - pdfdelayedobject(annot,r) + local annot = f_annot(prerolled,pdfrectangle(specification.width,specification.height,specification.depth)) + if objref then + pdfdelayedobject(annot,objref) else - r = pdfdelayedobject(annot) + objref = pdfdelayedobject(annot) end nofspecial = nofspecial + 1 - return pdfregisterannotation(r) + return pdfregisterannotation(objref) end function nodeinjections.reference(width,height,depth,prerolled) @@ -791,17 +804,30 @@ function nodeinjections.reference(width,height,depth,prerolled) if trace_references then report_references("link: width %p, height %p, depth %p, prerolled %a",width,height,depth,prerolled) end - return new_latelua(function() finishreference(width,height,depth,prerolled) end) + return new_latelua { + action = finishreference, + width = width, + height = height, + depth = depth, + prerolled = prerolled, + } end end -function nodeinjections.annotation(width,height,depth,prerolled,r) +function nodeinjections.annotation(width,height,depth,prerolled,objref) if prerolled then if trace_references then report_references("special: width %p, height %p, depth %p, prerolled %a",width,height,depth, type(prerolled) == "string" and prerolled or "-") end - return new_latelua(function() finishannotation(width,height,depth,prerolled,r or false) end) + return new_latelua { + action = finishannotation, + width = width, + height = height, + depth = depth, + prerolled = prerolled, + objref = objref or false, + } end end @@ -1202,7 +1228,8 @@ end local function build(levels,start,parent,method,nested) local startlevel = levels[start].level local noflevels = #levels - local i, n = start, 0 + local i = start + local n = 0 local child, entry, m, prev, first, last, f, l while i and i <= noflevels do local current = levels[i] diff --git a/tex/context/base/mkiv/lpdf-col.lua b/tex/context/base/mkiv/lpdf-col.lua index 1645a72ed..9ba64abba 100644 --- a/tex/context/base/mkiv/lpdf-col.lua +++ b/tex/context/base/mkiv/lpdf-col.lua @@ -342,7 +342,9 @@ local function registersomeindexcolor(name,noffractions,names,p,colorspace,range colorspace, pdfreference(n), } - local vector, set, n = { }, { }, #values + local vector = { } + local set = { } + local n = #values for i=255,0,-1 do for j=1,n do set[j] = format("%02X",round(values[j]*i)) @@ -427,7 +429,8 @@ function codeinjections.setfigurecolorspace(data,figure) local ref = indexcolorref(color) if ref then figure.colorspace = ref - data.used.color = color + data.used.color = color + data.used.colorref = ref end end end @@ -519,13 +522,21 @@ local function lpdfcolor(model,ca,default) -- todo: use gray when no color local s = cv[2] return f_gray(s,s) elseif model == 3 then - local r, g, b = cv[3], cv[4], cv[5] + local r = cv[3] + local g = cv[4] + local b = cv[5] return f_rgb(r,g,b,r,g,b) elseif model == 4 then - local c, m, y, k = cv[6],cv[7],cv[8],cv[9] + local c = cv[6] + local m = cv[7] + local y = cv[8] + local k = cv[9] return f_cmyk(c,m,y,k,c,m,y,k) else - local n,f,d,p = cv[10],cv[11],cv[12],cv[13] + local n = cv[10] + local f = cv[11] + local d = cv[12] + local p = cv[13] if type(p) == "string" then p = gsub(p,","," ") -- brr misuse of spot end diff --git a/tex/context/base/mkiv/lpdf-emb.lua b/tex/context/base/mkiv/lpdf-emb.lua new file mode 100644 index 000000000..27fb2dc9a --- /dev/null +++ b/tex/context/base/mkiv/lpdf-emb.lua @@ -0,0 +1,1839 @@ +if not modules then modules = { } end modules ['lpdf-ini'] = { + version = 1.001, + comment = "companion to lpdf-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- vkgoeswild: Pink Floyd - Shine on You Crazy Diamond - piano cover + +-- At some point I wanted to have access to the shapes so that we could use them in +-- metapost. So, after looking at the cff and ttf specifications, I decided to write +-- parsers. At somepoint we needed a cff parser anyway in order to calculate the +-- dimensions. Then variable fonts came around and a option was added to recreate +-- streams of operators and a logical next step was to do all inclusion that way. It +-- was only then that I found out that some of the juggling also happens in the the +-- backend, but spread over places, so I could have saved myself some time +-- deciphering the specifications. Anyway, here we go. + +local next, type, unpack = next, type, unpack +local char, byte, gsub, sub, match, rep, gmatch = string.char, string.byte, string.gsub, string.sub, string.match, string.rep, string.gmatch +local formatters = string.formatters +local format = string.format +local concat, sortedhash, sort = table.concat, table.sortedhash, table.sort +local utfchar = utf.char +local random, round, max, abs, ceiling = math.random, math.round, math.max, math.abs, math.ceiling +local extract, lshift, rshift, band, bor = bit32.extract, bit32.lshift, bit32.rshift, bit32.band, bit32.bor +local idiv = number.idiv +local setmetatableindex = table.setmetatableindex + +local pdfnull = lpdf.null +local pdfdictionary = lpdf.dictionary +local pdfarray = lpdf.array +local pdfconstant = lpdf.constant +local pdfstring = lpdf.string +local pdfreference = lpdf.reference +local pdfreserveobject = lpdf.reserveobject +local pdfflushobject = lpdf.flushobject +local pdfflushstreamobject = lpdf.flushstreamobject + +local fontstreams = fonts.hashes.streams + +local report_fonts = logs.reporter("backend","fonts") +local trace_fonts = false +local trace_detail = false + +trackers.register("backend.pdf.fonts",function(v) trace_fonts = v end) + +local readers = fonts.handlers.otf.readers +local getinfo = readers.getinfo + +local setposition = utilities.files.setposition +local readstring = utilities.files.readstring +local openfile = utilities.files.open +local closefile = utilities.files.close + +-- needs checking: signed vs unsigned + +local tocardinal1 = char + +local function tocardinal2(n) + return char(extract(n,8,8),extract(n,0,8)) +end + +local function tocardinal3(n) + return char(extract(n,16,8),extract(n,8,8),extract(n,0,8)) +end + +local function tocardinal4(n) + return char(extract(n,24,8),extract(n,16,8),extract(n,8,8),extract(n,0,8)) +end + +local function tointeger2(n) + return char(extract(n,8,8),extract(n,0,8)) +end + +local function tointeger3(n) + return char(extract(n,16,8),extract(n,8,8),extract(n,0,8)) +end + +local function tointeger4(n) + return char(extract(n,24,8),extract(n,16,8),extract(n,8,8),extract(n,0,8)) +end + +local function tocardinal8(n) + local l = idiv(n,0x100000000) + local r = n % 0x100000000 + return char(extract(l,24,8),extract(l,16,8),extract(l,8,8),extract(l,0,8), + extract(r,24,8),extract(r,16,8),extract(r,8,8),extract(r,0,8)) +end + +-- A couple of shared helpers. + +local tounicodedictionary, widtharray, collectindices, subsetname, includecidset, tocidsetdictionary + +do + + -- Because we supply tounicodes ourselves we only use bfchar mappings (as in the + -- backend). In fact, we can now no longer pass the tounicodes to the frontend but + -- pick them up from the descriptions. + + local f_mapping = formatters["<%04X> <%s>"] + + local tounicode = fonts.mappings.tounicode + +local tounicode_template = [[ +%%!PS-Adobe-3.0 Resource-CMap +%%%%DocumentNeededResources: ProcSet (CIDInit) +%%%%IncludeResource: ProcSet (CIDInit) +%%%%BeginResource: CMap (TeX-%s-0) +%%%%Title: (TeX-%s-0 TeX %s 0)| +%%%%Version: 1.000 +%%%%EndComments +/CIDInit /ProcSet findresource begin + 12 dict begin + begincmap + /CIDSystemInfo + << /Registry (TeX) /Ordering (%s) /Supplement 0 >> + def + /CMapName + /TeX-Identity-%s + def + /CMapType + 2 + def + 1 begincodespacerange + <0000> <FFFF> + endcodespacerange + %i beginbfchar + +%s + + endbfchar + endcmap + CMapName currentdict /CMap defineresource pop + end +end +%%%%EndResource +%%%%EOF]] + + tounicodedictionary = function(details,indices,maxindex,name) + local mapping = { } + local length = 0 + if maxindex > 0 then + for index=1,maxindex do + local data = indices[index] + if data then + length = length + 1 + local unicode = data.unicode + if unicode then + unicode = tounicode(unicode) + else + unicode = "FFFD" + end + mapping[length] = f_mapping(index,unicode) + end + end + end + local name = gsub(name,"%+","-") -- like luatex does + local blob = format(tounicode_template,name,name,name,name,name,length,concat(mapping,"\n")) + return blob + end + + widtharray = function(details,indices,maxindex,units) + local widths = pdfarray() + local length = 0 + local factor = 10000 / units + if maxindex > 0 then + local lastindex = -1 + local sublist = nil + for index=1,maxindex do + local data = indices[index] + if data then + local width = data.width -- hm, is inaccurate for cff, so take from elsewhere + if width then + -- width = round(width * 10000 / units) / 10 + width = round(width * factor) / 10 + else + width = 0 + end + if index == lastindex + 1 then + sublist[#sublist+1] = width + else + if sublist then + length = length + 1 + widths[length] = sublist + end + sublist = pdfarray { width } + length = length + 1 + widths[length] = index + end + lastindex = index + end + end + length = length + 1 + widths[length] = sublist + end + return widths + end + + collectindices = function(descriptions,indices) + local minindex = 0xFFFF + local maxindex = 0 + local reverse = { } + -- todo: already at definition time trigger copying streams + -- and add extra indices ... first i need a good example of + -- a clash + -- for unicode, data in next, descriptions do + -- local i = data.index or unicode + -- if reverse[i] then + -- print("CLASH") + -- else + -- reverse[i] = data + -- end + -- end + for unicode, data in next, descriptions do + reverse[data.index or unicode] = data + end + for index in next, indices do + if index > maxindex then + maxindex = index + end + if index < minindex then + minindex = index + end + indices[index] = reverse[index] + end + if minindex > maxindex then + minindex = maxindex + end + return indices, minindex, maxindex + end + + includecidset = false + + tocidsetdictionary = function(indices,min,max) + if includecidset then + local b = { } + local m = idiv(max+7,8) + for i=0,max do + b[i] = 0 + end + for i=min,max do + if indices[i] then + local bi = idiv(i,8) + local ni = i % 8 + b[bi] = bor(b[bi],lshift(1,7-ni)) + end + end + b = char(unpack(b,0,#b)) + return pdfreference(pdfflushstreamobject(b)) + end + end + + -- Actually we can use the same as we only embed once. + + -- subsetname = function(name) + -- return "CONTEXT" .. name + -- end + + local prefixes = { } -- todo: set fixed one + + subsetname = function(name) + local prefix + while true do + prefix = utfchar(random(65,90),random(65,90),random(65,90),random(65,90),random(65,90),random(65,90)) + if not prefixes[prefix] then + prefixes[prefix] = true + break + end + end + return prefix .. "+" .. name + end + +end + +-- Map file mess. + +local loadmapfile, loadmapline, getmapentry do + + -- We only need to pick up the filename and optionally the enc file + -- as we only use them for old school virtual math fonts. We might as + -- we drop this completely. + + local find, match, splitlines = string.find, string.match, string.splitlines + + + local mappings = { } + + loadmapline = function(n) + local name, fullname, encfile, pfbfile = match(n,"(%S+)%s+(%S+).-<(.-%.enc).-<(.-%.pfb)") + if name then + mappings[name] = { fullname, encfile, pfbfile } + end + end + + loadmapfile = function(n) + local okay, data = resolvers.loadbinfile(n,"map") + if okay and data then + data = splitlines(data) + for i=1,#data do + local d = data[i] + if d ~= "" and not find(d,"^[#%%]") then + loadmapline(d) + end + end + end + end + + getmapentry = function(n) + local n = file.nameonly(n) + local m = mappings[n] + if m then + local encfile = m[2] + local encoding = fonts.encodings.load(encfile) + if not encoding then + return + end + local pfbfile = resolvers.find_file(m[3],"pfb") + if not pfbfile or pfbfile == "" then + return + end + return encoding, pfbfile, encfile + end + end + +end + +-- The three writers: opentype, truetype and type1. + +local mainwriters = { } + +do + + -- advh = os2.ascender - os2.descender + -- tsb = default_advh - os2.ascender + + -- truetype has the following tables: + + -- head : mandate + -- hhea : mandate + -- vhea : mandate + -- hmtx : mandate + -- maxp : mandate + -- glyf : mandate + -- loca : mandate + -- + -- cvt : if needed (but we flatten) + -- fpgm : if needed (but we flatten) + -- prep : if needed (but we flatten) + -- PCLT : if needed (but we flatten) + -- + -- name : not needed for T2: backend does that + -- post : not needed for T2: backend does that + -- OS/2 : not needed for T2: backend does that + -- cmap : not needed for T2: backend does that + + local streams = utilities.streams + local openstring = streams.openstring + local readcardinal2 = streams.readcardinal2 + ----- readcardinal4 = streams.readcardinal4 + + local otfreaders = fonts.handlers.otf.readers + + local function readcardinal4(f) -- this needs to be sorted out + local a = readcardinal2(f) + local b = readcardinal2(f) + if a and b then + return a * 0x10000 + b + end + end + + -- -- -- + + local tablereaders = { } + local tablewriters = { } + local tablecreators = { } + local tableloaders = { } + + local openfontfile, closefontfile, makefontfile, makemetadata do + + local details = { + details = true, + platformnames = true, + platformextras = true, + } + + -- .022 sec on luatex manual, neglectable: + + -- local function checksum(data) + -- local s = openstring(data) + -- local n = 0 + -- local d = #data + -- while true do + -- local c = readcardinal4(s) + -- if c then + -- n = (n + c) % 0x100000000 + -- else + -- break + -- end + -- end + -- return n + -- end + + local function checksum(data) + local s = openstring(data) + local n = 0 + local d = #data + while true do + local a = readcardinal2(s) + local b = readcardinal2(s) + if b then + n = (n + a * 0x10000 + b) % 0x100000000 + else + break + end + end + return n + end + + openfontfile = function(details) + return { + offset = 0, + order = { }, + used = { }, + details = details, + streams = details.streams, + } + end + + closefontfile = function(fontfile) + for k, v in next, fontfile do + fontfile[k] = nil -- so it can be collected asap + end + end + + local metakeys = { + "uniqueid", "version", + "copyright", "license", "licenseurl", + "manufacturer", "vendorurl", + "family", "subfamily", + "typographicfamily", "typographicsubfamily", + "fullname", "postscriptname", + } + + local template = [[ +<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> + <x:xmpmeta xmlns:x="adobe:ns:meta/"> + <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> + <rdf:Description rdf:about="" xmlns:pdfx="http://ns.adobe.com/pdfx/1.3/"> + +%s + + </rdf:Description> + </rdf:RDF> + </x:xmpmeta> +<?xpacket end="w"?>]] + + makemetadata = function(fontfile) + local names = fontfile.streams.names + local list = { } + local f_name = formatters["<pdfx:%s>%s</pdfx:%s>"] + for i=1,#metakeys do + local m = metakeys[i] + local n = names[m] + if n then + list[#list+1] = f_name(m,n,m) + end + end + return format(template,concat(list,"\n")) + end + + makefontfile = function(fontfile) + local order = fontfile.order + local used = fontfile.used + local count = 0 + for i=1,#order do + local tag = order[i] + local data = fontfile[tag] + if data and #data > 0 then + count = count + 1 + else + fontfile[tag] = false + end + end + local offset = 12 + (count * 16) + local headof = 0 + local list = { + "" -- placeholder + } + local i = 1 + local k = 0 + while i <= count do + i = lshift(i,1) + k = k + 1 + end + local searchrange = lshift(i,3) + local entryselector = k - 1 + local rangeshift = lshift(count,4) - lshift(i,3) + local index = { + tocardinal4(0x00010000), -- tables.version + tocardinal2(count), + tocardinal2(searchrange), + tocardinal2(entryselector), + tocardinal2(rangeshift), + } + -- + local ni = #index + local nl = #list + for i=1,#order do + local tag = order[i] + local data = fontfile[tag] + if data then + local csum = checksum(data) + local dlength = #data + local length = idiv(dlength+3,4) * 4 + local padding = length - dlength + nl = nl + 1 ; list[nl] = data + for i=1,padding do + nl = nl + 1 ; list[nl] = "\0" + end + if #tag == 3 then + tag = tag .. " " + end + ni = ni + 1 ; index[ni] = tag -- must be 4 chars + ni = ni + 1 ; index[ni] = tocardinal4(csum) + ni = ni + 1 ; index[ni] = tocardinal4(offset) + ni = ni + 1 ; index[ni] = tocardinal4(dlength) + used[i] = offset -- not used + if tag == "head" then + headof = offset + end + offset = offset + length + end + end + list[1] = concat(index) + local off = #list[1] + headof + 1 + 8 + list = concat(list) + local csum = (0xB1B0AFBA - checksum(list)) % 0x100000000 + list = sub(list,1,off-1) .. tocardinal4(csum) .. sub(list,off+4,#list) + return list + end + + local function register(fontfile,name) + local u = fontfile.used + local o = fontfile.order + if not u[name] then + o[#o+1] = name + u[name] = true + end + end + + local function create(fontfile,name) + local t = { } + fontfile[name] = t + return t + end + + local function write(fontfile,name) + local t = fontfile[name] + if not t then + return + end + register(fontfile,name) + if type(t) == "table" then + if t[0] then + fontfile[name] = concat(t,"",0,#t) + elseif #t > 0 then + fontfile[name] = concat(t) + else + fontfile[name] = false + end + end + end + + tablewriters.head = function(fontfile) + register(fontfile,"head") + local t = fontfile.streams.fontheader + fontfile.head = concat { + tocardinal4(t.version), + tocardinal4(t.fontversionnumber), + tocardinal4(t.checksum), + tocardinal4(t.magic), + tocardinal2(t.flags), + tocardinal2(t.units), + tocardinal8(t.created), + tocardinal8(t.modified), + tocardinal2(t.xmin), + tocardinal2(t.ymin), + tocardinal2(t.xmax), + tocardinal2(t.ymax), + tocardinal2(t.macstyle), + tocardinal2(t.smallpixels), + tocardinal2(t.directionhint), + tocardinal2(t.indextolocformat), + tocardinal2(t.glyphformat), + } + end + + tablewriters.hhea = function(fontfile) + register(fontfile,"hhea") + local t = fontfile.streams.horizontalheader + local n = t and fontfile.nofglyphs or 0 + fontfile.hhea = concat { + tocardinal4(t.version), + tocardinal2(t.ascender), + tocardinal2(t.descender), + tocardinal2(t.linegap), + tocardinal2(t.maxadvancewidth), + tocardinal2(t.minleftsidebearing), + tocardinal2(t.minrightsidebearing), + tocardinal2(t.maxextent), + tocardinal2(t.caretsloperise), + tocardinal2(t.caretsloperun), + tocardinal2(t.caretoffset), + tocardinal2(t.reserved_1), + tocardinal2(t.reserved_2), + tocardinal2(t.reserved_3), + tocardinal2(t.reserved_4), + tocardinal2(t.metricdataformat), + tocardinal2(n) -- t.nofmetrics + } + end + + tablewriters.vhea = function(fontfile) + local t = fontfile.streams.verticalheader + local n = t and fontfile.nofglyphs or 0 + register(fontfile,"vhea") + fontfile.vhea = concat { + tocardinal4(t.version), + tocardinal2(t.ascender), + tocardinal2(t.descender), + tocardinal2(t.linegap), + tocardinal2(t.maxadvanceheight), + tocardinal2(t.mintopsidebearing), + tocardinal2(t.minbottomsidebearing), + tocardinal2(t.maxextent), + tocardinal2(t.caretsloperise), + tocardinal2(t.caretsloperun), + tocardinal2(t.caretoffset), + tocardinal2(t.reserved_1), + tocardinal2(t.reserved_2), + tocardinal2(t.reserved_3), + tocardinal2(t.reserved_4), + tocardinal2(t.metricdataformat), + tocardinal2(n) -- t.nofmetrics + } + end + + tablewriters.maxp = function(fontfile) + register(fontfile,"maxp") + local t = fontfile.streams.maximumprofile + local n = fontfile.nofglyphs + -- if fontfile.streams.cffinfo then + -- error + -- end + fontfile.maxp = concat { + tocardinal4(0x00010000), + tocardinal2(n), + tocardinal2(t.points), + tocardinal2(t.contours), + tocardinal2(t.compositepoints), + tocardinal2(t.compositecontours), + tocardinal2(t.zones), + tocardinal2(t.twilightpoints), + tocardinal2(t.storage), + tocardinal2(t.functiondefs), + tocardinal2(t.instructiondefs), + tocardinal2(t.stackelements), + tocardinal2(t.sizeofinstructions), + tocardinal2(t.componentelements), + tocardinal2(t.componentdepth), + } + end + + tablecreators.loca = function(fontfile) return create(fontfile,"loca") end + tablewriters .loca = function(fontfile) return write (fontfile,"loca") end + + tablecreators.glyf = function(fontfile) return create(fontfile,"glyf") end + tablewriters .glyf = function(fontfile) return write (fontfile,"glyf") end + + tablecreators.hmtx = function(fontfile) return create(fontfile,"hmtx") end + tablewriters .hmtx = function(fontfile) return write (fontfile,"hmtx") end + + tablecreators.vmtx = function(fontfile) return create(fontfile,"vmtx") end + tablewriters .vmtx = function(fontfile) return write (fontfile,"vmtx") end + + tableloaders .cmap = function(fontfile) return read (fontfile,"cmap") end + tablewriters .cmap = function(fontfile) return write (fontfile,"cmap") end + + tableloaders .name = function(fontfile) return read (fontfile,"name") end + tablewriters .name = function(fontfile) return write (fontfile,"name") end + + tableloaders .post = function(fontfile) return read (fontfile,"post") end + tablewriters .post = function(fontfile) return write (fontfile,"post") end + + end + + mainwriters["truetype"] = function(details) + -- + local fontfile = openfontfile(details) + local basefontname = details.basefontname + local streams = details.streams + local blobs = streams.streams + local fontheader = streams.fontheader + local horizontalheader = streams.horizontalheader + local verticalheader = streams.verticalheader + local maximumprofile = streams.maximumprofile + local names = streams.names + local descriptions = details.rawdata.descriptions + local metadata = details.rawdata.metadata + local indices = details.indices + local metabbox = { fontheader.xmin, fontheader.ymin, fontheader.xmax, fontheader.ymax } + local indices, + minindex, + maxindex = collectindices(descriptions,indices) + local glyphstreams = tablecreators.glyf(fontfile) + local locations = tablecreators.loca(fontfile) + local horizontals = tablecreators.hmtx(fontfile) + local verticals = tablecreators.vmtx(fontfile) + -- + local zero2 = tocardinal2(0) + local zero4 = tocardinal4(0) + -- + local horizontal = horizontalheader.nofmetrics > 0 + local vertical = verticalheader.nofmetrics > 0 + -- + local streamoffset = 0 + local lastoffset = zero4 + local g, h, v = 0, 0, 0 + -- + -- todo: locate notdef + -- + if minindex > 0 then + local blob = blobs[0] + if blob and #blob > 0 then + locations[0] = lastoffset + g = g + 1 ; glyphstreams[g] = blob + h = h + 1 ; horizontals [h] = zero4 + if vertical then + v = v + 1 ; verticals[v] = zero4 + end + streamoffset = streamoffset + #blob + lastoffset = tocardinal4(streamoffset) + else + print("missing .notdef") + end + -- todo: use a rep for h/v + for index=1,minindex-1 do + locations[index] = lastoffset + h = h + 1 ; horizontals[h] = zero4 + if vertical then + v = v + 1 ; verticals[v] = zero4 + end + end + end + for index=minindex,maxindex do + locations[index] = lastoffset + local data = indices[index] + if data then + local blob = blobs[index] -- we assume padding + if blob and #blob > 0 then + g = g + 1 ; glyphstreams[g] = blob + h = h + 1 ; horizontals [h] = tocardinal2(data.width or 0) + h = h + 1 ; horizontals [h] = tocardinal2(data.boundingbox[1]) + if vertical then + v = v + 1 ; verticals[v] = tocardinal2(data.height or 0) + v = v + 1 ; verticals[v] = tocardinal2(data.boundingbox[3]) + end + streamoffset = streamoffset + #blob + lastoffset = tocardinal4(streamoffset) + else + h = h + 1 ; horizontals[h] = zero4 + if vertical then + v = v + 1 ; verticals[v] = zero4 + end + print("missing blob for index",index) + end + else + h = h + 1 ; horizontals[h] = zero4 + if vertical then + v = v + 1 ; verticals[v] = zero4 + end + end + end + locations[maxindex+1] = lastoffset -- cf spec + -- + local nofglyphs = maxindex + 1 -- include zero + -- + fontheader.checksum = 0 + fontheader.indextolocformat = 1 + maximumprofile.nofglyphs = nofglyphs + -- + fontfile.format = "tff" + fontfile.basefontname = basefontname + fontfile.nofglyphs = nofglyphs + -- + tablewriters.head(fontfile) + tablewriters.hhea(fontfile) + if vertical then + tablewriters.vhea(fontfile) + end + tablewriters.maxp(fontfile) + + tablewriters.loca(fontfile) + tablewriters.glyf(fontfile) + + tablewriters.hmtx(fontfile) + if vertical then + tablewriters.vmtx(fontfile) + end + -- + local fontdata = makefontfile(fontfile) + local fontmeta = makemetadata(fontfile) + -- + fontfile = closefontfile(fontfile) + -- + local units = metadata.units + local basefont = pdfconstant(basefontname) + local widths = widtharray(details,indices,maxindex,units) + local object = details.objectnumber + local tounicode = tounicodedictionary(details,indices,maxindex,basefontname) + local tocidset = tocidsetdictionary(indices,minindex,maxindex) + local metabbox = metadata.boundingbox or { 0, 0, 0, 0 } + local fontbbox = pdfarray { unpack(metabbox) } + local ascender = metadata.ascender + local descender = metadata.descender + local capheight = metadata.capheight or fontbbox[4] + local stemv = metadata.weightclass + local italicangle = metadata.italicangle + local xheight = metadata.xheight or fontbbox[4] + -- + if stemv then + stemv = (stemv/65)^2 + 50 + end + -- + local function scale(n) + if n then + return round((n) * 10000 / units) / 10 + else + return 0 + end + end + -- + local reserved = pdfreserveobject() + local child = pdfdictionary { + Type = pdfconstant("Font"), + Subtype = pdfconstant("CIDFontType2"), + BaseFont = basefont, + FontDescriptor = pdfreference(reserved), + W = pdfreference(pdfflushobject(widths)), + CIDToGIDMap = pdfconstant("Identity"), + CIDSystemInfo = pdfdictionary { + Registry = pdfstring("Adobe"), + Ordering = pdfstring("Identity"), + Supplement = 0, + } + } + local descendants = pdfarray { + pdfreference(pdfflushobject(child)), + } + local descriptor = pdfdictionary { + Type = pdfconstant("FontDescriptor"), + FontName = basefont, + Flags = 4, + FontBBox = fontbbox, + Ascent = scale(ascender), + Descent = scale(descender), + ItalicAngle = round(italicangle or 0), + CapHeight = scale(capheight), + StemV = scale(stemv), + XHeight = scale(xheight), + FontFile2 = pdfreference(pdfflushstreamobject(fontdata)), + CIDSet = tocidset, + Metadata = fontmeta and pdfreference(pdfflushstreamobject(fontmeta)) or nil, + } + local parent = pdfdictionary { + Type = pdfconstant("Font"), + Subtype = pdfconstant("Type0"), + Encoding = pdfconstant(details.properties.writingmode == "vertical" and "Identity-V" or "Identity-H"), + BaseFont = basefont, + DescendantFonts = descendants, + ToUnicode = pdfreference(pdfflushstreamobject(tounicode)), + } + pdfflushobject(reserved,descriptor) + pdfflushobject(object,parent) + -- + -- if trace_detail then + -- local name = "temp.ttf" + -- report_fonts("saving %a",name) + -- io.savedata(name,fontdata) + -- inspect(fonts.handlers.otf.readers.loadfont(name)) + -- end + -- + end + + do + -- todo : cff2 + + local details = { + details = true, + platformnames = true, + platformextras = true, + } + + tablecreators.cff = function(fontfile) + fontfile.charstrings = { } + fontfile.charmappings = { } + fontfile.cffstrings = { } + fontfile.cffhash = { } + return fontfile.charstrings , fontfile.charmappings + end + + local todictnumber, todictreal, todictinteger, todictoffset do + + local maxnum = 0x7FFFFFFF + local minnum = - 0x7FFFFFFF - 1 + local epsilon = 1.0e-5 + + local int2tag = "\28" + local int4tag = "\29" + local realtag = "\30" + + todictinteger = function(n) + if not n then + return char(band(139,0xFF)) + elseif n >= -107 and n <= 107 then + return char(band(n + 139,0xFF)) + elseif n >= 108 and n <= 1131 then + n = 0xF700 + n - 108 + return char(band(rshift(n,8),0xFF),band(n,0xFF)) + elseif n >= -1131 and n <= -108 then + n = 0xFB00 - n - 108 + return char(band(rshift(n,8),0xFF),band(n,0xFF)) + elseif n >= -32768 and n <= 32767 then + -- return int2tag .. tointeger2(n) + return char(28,extract(n,8,8),extract(n,0,8)) + else + -- return int4tag .. tointeger4(n) + return char(29,extract(n,24,8),extract(n,16,8),extract(n,8,8),extract(n,0,8)) + end + end + + -- -- not called that often + -- + -- local encoder = readers.cffencoder + -- + -- todictinteger = function(n) + -- if not n then + -- return encoder[0] + -- elseif n >= -1131 and n <= 1131 then + -- return encoder[n] + -- elseif n >= -32768 and n <= 32767 then + -- -- return int2tag .. tointeger2(n) + -- return char(28,extract(n,8,8),extract(n,0,8)) + -- else + -- -- return int4tag .. tointeger4(n) + -- return char(29,extract(n,24,8),extract(n,16,8),extract(n,8,8),extract(n,0,8)) + -- end + -- end + + todictoffset = function(n) + return int4tag .. tointeger4(n) + end + + local e = false + local z = byte("0") + local dp = 10 + local ep = 11 + local em = 12 + local mn = 14 + local es = 15 + + local fg = formatters["%g"] + + todictreal = function(v) + local s = fg(v) + local t = { [0] = realtag } + local n = 0 + for s in gmatch(s,".") do + if s == "e" or s == "E" then + e = true + elseif s == "+" then + -- skip + elseif s == "-" then + n = n + 1 + if e then + t[n] = em + e = false + else + t[n] = mn + end + else + if e then + n = n + 1 + t[n] = ep + e = false + end + n = n + 1 + if s == "." then + t[n] = dp + else + t[n] = byte(s) - z + end + end + end + n = n + 1 + t[n] = es + if (n % 2) ~= 0 then + n = n + 1 + t[n] = es + end + local j = 0 + for i=1,n,2 do + j = j + 1 + t[j] = char(t[i]*0x10+t[i+1]) + end + t = concat(t,"",0,j) + return t + end + + todictnumber = function(n) + if not n or n == 0 then + return todictinteger(0) + elseif (n > maxnum or n < minnum or (abs(n - round(n)) > epsilon)) then + return todictreal(n) + else + return todictinteger(n) + end + end + + end + + local todictkey = char + + local function todictstring(fontfile,value) + if not value then + value = "" + end + local s = fontfile.cffstrings + local h = fontfile.cffhash + local n = h[value] + if not n then + n = #s + 1 + s[n] = value + h[value] = n + end + return todictinteger(390+n) + end + + local function todictboolean(b) + return todictinteger(b and 1 or 0) + end + + local function todictdeltas(t) + local r = { } + for i=1,#t do + r[i] = todictnumber(t[i]-(t[i-1] or 0)) + end + return concat(r) + end + + local function todictarray(t) + local r = { } + for i=1,#t do + r[i] = todictnumber(t[i]) + end + return concat(r) + end + + local function writestring(target,source,offset,what) + target[#target+1] = source + -- report_fonts("string : %-11s %06i # %05i",what,offset,#source) + return offset + #source + end + + local function writetable(target,source,offset,what) + source = concat(source) + target[#target+1] = source + -- report_fonts("table : %-11s %06i # %05i",what,offset,#source) + return offset + #source + end + + local function writeindex(target,source,offset,what) + local n = #source + local t = #target + t = t + 1 ; target[t] = tocardinal2(n) + if n > 0 then + local data = concat(source) + local size = #data -- assume the worst + local offsetsize, tocardinal + if size < 0xFF then + offsetsize, tocardinal = 1, tocardinal1 + elseif size < 0xFFFF then + offsetsize, tocardinal = 2, tocardinal2 + elseif size < 0xFFFFFF then + offsetsize, tocardinal = 3, tocardinal3 + elseif size < 0xFFFFFFFF then + offsetsize, tocardinal = 4, tocardinal4 + end + -- report_fonts("index : %-11s %06i # %05i (%i entries with offset size %i)",what,offset,#data,n,offsetsize) + offset = offset + 2 + 1 + (n + 1) * offsetsize + size + -- bytes per offset + t = t + 1 ; target[t] = tocardinal1(offsetsize) + -- list of offsets (one larger for length calculation) + local offset = 1 -- mandate + t = t + 1 ; target[t] = tocardinal(offset) + for i=1,n do + offset = offset + #source[i] + t = t + 1 ; target[t] = tocardinal(offset) + end + t = t + 1 ; target[t] = data + else + -- report_fonts("index : %-11s %06i # %05i (no entries)",what,offset,0) + offset = offset + 2 + end + -- print("offset",offset,#concat(target)) + return offset + end + + tablewriters.cff = function(fontfile) + -- + local streams = fontfile.streams + local cffinfo = streams.cffinfo or { } + local names = streams.names or { } + local fontheader = streams.fontheader or { } + local basefontname = fontfile.basefontname + -- + local offset = 0 + local dictof = 0 + local target = { } + -- + local charstrings = fontfile.charstrings + local nofglyphs = #charstrings + 1 + local fontmatrix = { 0.001, 0, 0, 0.001, 0, 0 } -- todo + local fontbbox = fontfile.fontbbox + local defaultwidth = cffinfo.defaultwidth or 0 + local nominalwidth = cffinfo.nominalwidth or 0 + local bluevalues = cffinfo.bluevalues + local otherblues = cffinfo.otherblues + local familyblues = cffinfo.familyblues + local familyotherblues = cffinfo.familyotherblues + local bluescale = cffinfo.bluescale + local blueshift = cffinfo.blueshift + local bluefuzz = cffinfo.bluefuzz + local stdhw = cffinfo.stdhw + local stdvw = cffinfo.stdvw + -- +-- bluescale = 0.039625 +-- blueshift = 7 +-- bluefuzz = 1 +-- defaultwidth = 500 +-- nominalwidth = 696 +-- stdhw = { 28, 36, 42, 48, 60 } +-- stdvw = { 40, 60, 66, 72, 76, 80, 88, 94 } + if defaultwidth == 0 then defaultwidth = nil end + if nomimalwidth == 0 then nominalwidth = nil end + if bluevalues then bluevalues = todictarray(bluevalues) end + if otherblues then otherblues = todictarray(otherblues) end + if familyblues then familyblues = todictarray(familyblues) end + if familyotherblues then familyotherblues = todictarray(familyotherblues) end + if bluescale then bluescale = todictnumber(bluescale) end + if blueshift then blueshift = todictnumber(blueshift) end + if bluefuzz then bluefuzz = todictnumber(bluefuzz) end +-- if stdhw then stdhw = todictarray(stdhw) end +-- if stdvw then stdvw = todictarray(stdvw) end +if stdhw then stdhw = todictdeltas(stdhw) end +if stdvw then stdvw = todictdeltas(stdvw) end + -- + local fontversion = todictstring(fontfile,fontheader.fontversion or "uknown version") + local familyname = todictstring(fontfile,cffinfo.familyname or names.family or basefontname) + local fullname = todictstring(fontfile,cffinfo.fullname or basefontname) + local weight = todictstring(fontfile,cffinfo.weight or "Normal") + local fontbbox = todictarray(fontbbox) + local strokewidth = todictnumber(cffinfo.strokewidth) + local monospaced = todictboolean(cffinfo.monospaced) + local italicangle = todictnumber(cffinfo.italicangle) + local underlineposition = todictnumber(cffinfo.underlineposition) + local underlinethickness = todictnumber(cffinfo.underlinethickness) + local charstringtype = todictnumber(2) + local fontmatrix = todictarray(fontmatrix) + local ros = todictstring(fontfile,"Adobe") -- registry + .. todictstring(fontfile,"Identity") -- identity + .. todictnumber(0) -- supplement + local cidcount = todictnumber(fontfile.nofglyphs) + local fontname = todictstring(fontfile,basefontname) + local fdarrayoffset = todictoffset(0) + local fdselectoffset = todictoffset(0) + local charstringoffset = todictoffset(0) + local charsetoffset = todictoffset(0) + local privateoffset = todictoffset(0) + -- + local defaultwidthx = todictnumber(defaultwidth) + local nominalwidthx = todictnumber(nominalwidth) + local private = "" + .. (defaultwidthx and (defaultwidthx .. todictkey(20)) or "") + .. (nominalwidthx and (nominalwidthx .. todictkey(21)) or "") + .. (bluevalues and (bluevalues .. todictkey(6)) or "") + .. (otherblues and (otherblues .. todictkey(7)) or "") + .. (familyblues and (familyblues .. todictkey(8)) or "") + .. (familyotherblues and (familyotherblues .. todictkey(9)) or "") + .. (bluescale and (bluescale .. todictkey(12,9)) or "") + .. (blueshift and (blueshift .. todictkey(12,10)) or "") + .. (bluefuzz and (bluefuzz .. todictkey(12,11)) or "") + .. (stdhw and (stdhw .. todictkey(12,12)) or "") + .. (stdvw and (stdvw .. todictkey(12,13)) or "") + local privatesize = todictnumber(#private) + local privatespec = privatesize .. privateoffset + -- + -- header (fixed @ 1) + -- + local header = + tocardinal1(1) -- major + .. tocardinal1(0) -- minor + .. tocardinal1(4) -- header size + .. tocardinal1(4) -- offset size + -- + offset = writestring(target,header,offset,"header") + -- + -- name index (fixed @ 2) (has to be sorted) + -- + local names = { + basefontname, + } + -- + offset = writeindex(target,names,offset,"names") + -- + -- topdict index (fixed @ 3) + -- + local topvars = + charstringoffset .. todictkey(17) + .. charsetoffset .. todictkey(15) + .. fdarrayoffset .. todictkey(12,36) + .. fdselectoffset .. todictkey(12,37) + .. privatespec .. todictkey(18) + -- + local topdict = { + ros .. todictkey(12,30) -- first + .. cidcount .. todictkey(12,34) + .. familyname .. todictkey( 3) + .. fullname .. todictkey( 2) + .. weight .. todictkey( 4) + .. fontbbox .. todictkey( 5) + .. monospaced .. todictkey(12, 1) + .. italicangle .. todictkey(12, 2) + .. underlineposition .. todictkey(12, 3) + .. underlinethickness .. todictkey(12, 4) + .. charstringtype .. todictkey(12, 6) + .. fontmatrix .. todictkey(12, 7) + .. strokewidth .. todictkey(12, 8) + .. topvars + } + -- + offset = writeindex(target,topdict,offset,"topdict") + dictof = #target + -- + -- string index (fixed @ 4) + -- + offset = writeindex(target,fontfile.cffstrings,offset,"strings") + -- + -- global subroutine index (fixed @ 5) + -- + offset = writeindex(target,{},offset,"globals") + -- + -- Encoding (cff1) + -- + -- offset = writeindex(target,{},offset,"encoding") + -- + -- Charsets + -- + charsetoffset = todictoffset(offset) + offset = writetable(target,fontfile.charmappings,offset,"charsets") + -- + -- fdselect + -- + local fdselect = + tocardinal1(3) -- format + .. tocardinal2(1) -- n of ranges + -- entry 1 + .. tocardinal2(0) -- first gid + .. tocardinal1(0) -- fd index + -- entry 2 +-- .. tocardinal2(fontfile.sparsemax-1) -- sentinel + .. tocardinal2(fontfile.sparsemax) -- sentinel + -- + fdselectoffset = todictoffset(offset) + offset = writestring(target,fdselect,offset,"fdselect") + -- + -- charstrings + -- + charstringoffset = todictoffset(offset) + offset = writeindex(target,charstrings,offset,"charstrings") + -- + -- font dict + -- + -- offset = writeindex(target,{},offset,"fontdict") + -- + -- private + -- + privateoffset = todictoffset(offset) + privatespec = privatesize .. privateoffset + offset = writestring(target,private,offset,"private") + -- + local fdarray = { + fontname .. todictkey(12,38) + .. privatespec .. todictkey(18) + } + fdarrayoffset = todictoffset(offset) + offset = writeindex(target,fdarray,offset,"fdarray") + -- + topdict = target[dictof] + topdict = sub(topdict,1,#topdict-#topvars) + topvars = + charstringoffset .. todictkey(17) + .. charsetoffset .. todictkey(15) + .. fdarrayoffset .. todictkey(12,36) + .. fdselectoffset .. todictkey(12,37) + .. privatespec .. todictkey(18) + target[dictof] = topdict .. topvars + -- + target = concat(target) + -- if trace_detail then + -- local name = "temp.cff" + -- report_fonts("saving %a",name) + -- io.savedata(name,target) + -- inspect(fonts.handlers.otf.readers.cffcheck(name)) + -- end + return target + end + + end + + -- todo: check widths (missing a decimal) + + mainwriters["opentype"] = function(details) + -- + local fontfile = openfontfile(details) + local basefontname = details.basefontname + local streams = details.streams + local blobs = streams.streams + local fontheader = streams.fontheader + local maximumprofile = streams.maximumprofile + local names = streams.names + local descriptions = details.rawdata.descriptions + local metadata = details.rawdata.metadata + local indices = details.indices + local metabbox = { fontheader.xmin, fontheader.ymin, fontheader.xmax, fontheader.ymax } + local indices, + minindex, + maxindex = collectindices(descriptions,indices) + local streamoffset = 0 + local glyphstreams, + charmappings = tablecreators.cff(fontfile) + -- + local zero2 = tocardinal2(0) + local zero4 = tocardinal4(0) + -- + -- we need to locate notdef (or store its unicode someplace) + -- + local blob = blobs[0] or "\14" + local sparsemax = 1 + local lastoffset = zero4 + glyphstreams[sparsemax] = blob + charmappings[sparsemax] = tocardinal1(0) -- format 0 + streamoffset = streamoffset + #blob + lastoffset = tocardinal4(streamoffset) + if minindex == 0 then + minindex = 1 + end + for index=minindex,maxindex do + if indices[index] then + local blob = blobs[index] or "\14" + sparsemax = sparsemax + 1 + glyphstreams[sparsemax] = blob + charmappings[sparsemax] = tocardinal2(index) + streamoffset = streamoffset + #blob + lastoffset = tocardinal4(streamoffset) + end + end + -- + fontfile.nofglyphs = maxindex + 1 + fontfile.sparsemax = sparsemax + fontfile.format = "cff" + fontfile.basefontname = basefontname + fontfile.fontbbox = metabbox + -- + local fontdata = tablewriters.cff(fontfile) + local fontmeta = makemetadata(fontfile) + -- + fontfile = closefontfile(fontfile) + -- + local units = fontheader.units or metadata.units + local basefont = pdfconstant(basefontname) + local widths = widtharray(details,indices,maxindex,units) + local object = details.objectnumber + local tounicode = tounicodedictionary(details,indices,maxindex,basefontname) + local tocidset = tocidsetdictionary(indices,minindex,maxindex) + local fontbbox = pdfarray { unpack(metabbox) } + local ascender = metadata.ascender or 0 + local descender = metadata.descender or 0 + local capheight = metadata.capheight or fontbbox[4] + local stemv = metadata.weightclass + local italicangle = metadata.italicangle + local xheight = metadata.xheight or fontbbox[4] + if stemv then + stemv = (stemv/65)^2 + 50 + else +-- stemv = 2 + end + -- + local function scale(n) + if n then + return round((n) * 10000 / units) / 10 + else + return 0 + end + end + -- + local reserved = pdfreserveobject() + local child = pdfdictionary { + Type = pdfconstant("Font"), + Subtype = pdfconstant("CIDFontType0"), + BaseFont = basefont, + FontDescriptor = pdfreference(reserved), + W = pdfreference(pdfflushobject(widths)), + CIDSystemInfo = pdfdictionary { + Registry = pdfstring("Adobe"), + Ordering = pdfstring("Identity"), + Supplement = 0, + } + } + local descendants = pdfarray { + pdfreference(pdfflushobject(child)), + } + local fontstream = pdfdictionary { + Subtype = pdfconstant("CIDFontType0C"), + } + local descriptor = pdfdictionary { + Type = pdfconstant("FontDescriptor"), + FontName = basefont, + Flags = 4, + FontBBox = fontbbox, + Ascent = scale(ascender), + Descent = scale(descender), + ItalicAngle = round(italicangle or 0), + CapHeight = scale(capheight), + StemV = scale(stemv), + XHeight = scale(xheight), + CIDSet = tocidset, + FontFile3 = pdfreference(pdfflushstreamobject(fontdata,fontstream())), + Metadata = fontmeta and pdfreference(pdfflushstreamobject(fontmeta)) or nil, + } + local parent = pdfdictionary { + Type = pdfconstant("Font"), + Subtype = pdfconstant("Type0"), + Encoding = pdfconstant(details.properties.writingmode == "vertical" and "Identity-V" or "Identity-H"), + BaseFont = basefont, + DescendantFonts = descendants, + ToUnicode = pdfreference(pdfflushstreamobject(tounicode)), + } + pdfflushobject(reserved,descriptor) + pdfflushobject(object,parent) + end + + mainwriters["type1"] = function(details) + local s = details.streams + local m = details.rawdata.metadata + if m then + local h = s.horizontalheader + local c = s.cffinfo + local n = s.names + h.ascender = m.ascender or h.ascender + h.descender = m.descender or h.descender + n.copyright = m.copyright or n.copyright + n.family = m.familyname or n.familyname + n.fullname = m.fullname or n.fullname + n.fontname = m.fontname or n.fontname + n.subfamily = m.subfamilyname or n.subfamilyname + n.version = m.version or n.version + setmetatableindex(h,m) + setmetatableindex(c,m) + setmetatableindex(n,m) + end + mainwriters["opentype"](details) + end + + -- todo: map pdf glyphs onto companion type 3 font .. can be set of small + -- ones. maybe only private codes with proper tounicode + + local methods = { } + + function methods.pk(filename) + local resolution = 600 + local widthfactor = resolution / 72 + local scalefactor = 72 / resolution / 10 + local pkfullname = resolvers.findpk(basedfontname,resolution) + if not pkfullname or pkfullname == "" then + return + end + local readers = fonts.handlers.tfm.readers + local result = readers.loadpk(pkfullname) + if not result or result.error then + return + end + return result.glyphs, widthfactor / 65536, scalefactor, readers.pktopdf + end + + mainwriters["type3"] = function(details) + local properties = details.properties + local basefontname = details.basefontname or properties.name + local askedmethod = "pk" + local method = methods[askedmethod] + if not method then + return + end + local glyphs, widthfactor, scalefactor, glyphtopdf = method(basedfontname) + if not glyphs then + return + end + local parameters = details.parameters + local object = details.objectnumber + local factor = parameters.factor -- normally 1 + local f_name = formatters["I%05i"] + local fontmatrix = pdfarray { scalefactor, 0, 0, scalefactor, 0, 0 } + local indices, + minindex, + maxindex = collectindices(details.fontdata.characters,details.indices) + local widths = pdfarray() + local differences = pdfarray() + local charprocs = pdfdictionary() + local basefont = pdfconstant(basefontname) + local llx, lly, urx, ury = 0, 0, 0, 0 + for i=1,maxindex-minindex+1 do + widths[i] = 0 + end + local d = 0 + local lastindex = -0xFFFF + for index, data in sortedhash(indices) do + local name = f_name(index) + local glyph = glyphs[index] + if glyph then + local width = widthfactor * data.width + local stream, lx, ly, ux, uy = glyphtopdf(glyph,width) + if stream then + if index - 1 ~= lastindex then + d = d + 1 ; differences[d] = index + end + lastindex = index + d = d + 1 ; differences[d] = pdfconstant(name) + charprocs[name] = pdfreference(pdfflushstreamobject(stream)) + widths[index-minindex+1] = width + if lx < llx then llx = lx end + if ux > urx then urx = ux end + if ly < lly then lly = ly end + if uy > ury then ury = uy end + end + end + end + local fontbbox = pdfarray { llx, lly, urx, ury } + local encoding = pdfdictionary { + Type = pdfconstant("Encoding"), + Differences = differences, + } + local tounicode = tounicodedictionary(details,indices,maxindex,basefontname) + local descriptor = pdfdictionary { + Type = pdfconstant("FontDescriptor"), + FontName = basefont, + Flags = 4, + FontBBox = fontbbox, + -- Ascent = scale(ascender), + -- Descent = scale(descender), + -- ItalicAngle = round(italicangle or 0), + -- CapHeight = scale(capheight), + -- StemV = scale(stemv), + -- XHeight = scale(xheight), + -- Metadata = fontmeta and pdfreference(pdfflushstreamobject(fontmeta)) or nil, + } + local parent = pdfdictionary { + Type = pdfconstant("Font"), + Subtype = pdfconstant("Type3"), + Name = basefont, + FontBBox = fontbbox, + FontMatrix = fontmatrix, + CharProcs = pdfreference(pdfflushobject(charprocs)), + Encoding = pdfreference(pdfflushobject(encoding)), + FirstChar = minindex, + LastChar = maxindex, + Widths = pdfreference(pdfflushobject(widths)), + FontDescriptor = pdfreference(pdfflushobject(descriptor)), + Resources = lpdf.procset(true), + ToUnicode = pdfreference(pdfflushstreamobject(tounicode)), + } + pdfflushobject(reserved,descriptor) + pdfflushobject(object,parent) + end + +end + +-- writingmode + +local usedfonts = fonts.hashes.identifiers -- for now +local noffonts = 0 + +-- The main injector. + +-- here we need to test for sharing otherwise we reserve too many +-- objects + +local getstreamhash = fonts.handlers.otf.getstreamhash +local loadstreamdata = fonts.handlers.otf.loadstreamdata + +-- we can actually now number upwards (so not use fontid in /F) + +local objects = setmetatableindex(function(t,k) + local v + if type(k) == "number" then + local h = getstreamhash(k) + v = rawget(t,h) + if not v then + v = pdfreserveobject() + t[h] = v + end + if trace_fonts then + report_fonts("font id %i bound to hash %s and object %i",k,h,v) + end + else + report_fonts("fatal error, hash %s asked but not used",k,h,v) + v = pdfreserveobject() + t[k] = v + end + return v +end) + +local n = 0 + +local names = setmetatableindex(function(t,k) + local v + if type(k) == "number" then + local h = getstreamhash(k) + v = rawget(t,h) + if not v then + n = n + 1 + v = n + t[h] = v + end + if trace_fonts then + report_fonts("font id %i bound to hash %s and name %i",k,h,n) + end + end + t[k] = v + return v +end) + +function lpdf.flushfonts() + + local mainfonts = { } + + statistics.starttiming(objects) + + for fontid, used in sortedhash(lpdf.usedcharacters) do + + -- for a bitmap we need a different hash unless we stick to a fixed high + -- resolution which makes much sense + + local hash = getstreamhash(fontid) + if hash then + local parent = mainfonts[hash] + if not parent then + local fontdata = usedfonts[fontid] + local rawdata = fontdata.shared and fontdata.shared.rawdata + local resources = fontdata.resources + local properties = fontdata.properties -- writingmode and type3 + local parameters = fontdata.parameters -- used in type3 + if not rawdata then + -- we have a virtual font that loaded directly ... at some point i will + -- sort this out (in readanddefine we need to do a bit more) .. the problem + -- is that we have a hybrid font then + for xfontid, xfontdata in next, fonts.hashes.identifiers do + if fontid ~= xfontid then + local xhash = getstreamhash(xfontid) + if hash == xhash then + rawdata = xfontdata.shared and xfontdata.shared.rawdata + if rawdata then + resources = xfontdata.resources + properties = xfontdata.properties + parameters = xfontdata.parameters + break + end + end + end + end + end + if rawdata then + parent = { + hash = hash, + fontdata = fontdata, + filename = resources.filename or properties.filename or "unset", + indices = { }, + rawdata = rawdata, + properties = properties, -- we assume consistency + parameters = parameters, -- we assume consistency + streams = { }, + objectnumber = objects[hash], + basefontname = subsetname(properties.psname or properties.name or "unset"), + name = names[hash], + } + mainfonts[hash] = parent + noffonts = noffonts + 1 + end + end + if parent then + local indices = parent.indices + for k in next, used do + indices[k] = true + end + end + end + end + + for hash, details in sortedhash(mainfonts) do + if next(details.indices) then + local filename = details.filename + if trace_fonts then + report_fonts("embedding %a hashed as %a",filename,hash) + end + local properties = details.properties + local bitmap = properties.usedbitmap + if bitmap then + local format = "type3" + local writer = mainwriters[format] + if writer then + if trace_fonts then + report_fonts("using main writer %a",format) + end + writer(details) + end + else + local format = properties.format + local writer = mainwriters[format] + if not writer then + -- at some point we should do this in the frontend but + -- luatex does it anyway then + local encoding, pfbfile, encfile = getmapentry(filename) + if encoding and pfbfile then + filename = pfbfile + format = "type1" + -- + -- another (temp) hack + local size = details.fontdata.parameters.size + local factor = details.fontdata.parameters.factor + local descriptions = { } + local characters = details.fontdata.characters + -- + local names, _, _, metadata = fonts.constructors.handlers.pfb.loadvector(pfbfile) + local reverse = table.swapped(names) + local vector = encoding.vector + local indices = details.indices + local remapped = { } + local factor = number.dimenfactors.bp * size / 65536 + for k, v in next, indices do + local name = vector[k] + local index = reverse[name] or 0 + local width = factor * (characters[k].width or 0) + descriptions[k] = { + width = width, + index = index, + name = name, + } + remapped[index] = true + end + details.indices = remapped + -- + details.rawdata.descriptions = descriptions + details.filename = filename + details.rawdata.metadata = { } + -- + properties.filename = filename + properties.format = format + writer = mainwriters[format] + end + end + if writer then + if trace_fonts then + report_fonts("using main writer %a",format) + end + -- better move this test to the writers .. cleaner + local streams = loadstreamdata(details.fontdata) + if streams and streams.fontheader and streams.names then + details.streams = streams + writer(details) + details.streams = { } + elseif trace_fonts then + -- can be ok for e.g. emoji + report_fonts("no streams in %a",filename) + end + -- free some memory + else -- if trace_fonts then + report_fonts("no %a writer for %a",format,filename) + end + end + end + mainfonts[details.hash] = false -- done + end + + statistics.stoptiming(objects) + +end + +statistics.register("font embedding time",function() + if noffonts > 0 then + return format("%s seconds, %s fonts", statistics.elapsedtime(objects),noffonts) + end +end) + +updaters.register("backend.update.pdf",function() + fonts.constructors.addtounicode = false +end) + +-- this is temporary + +local done = false + +updaters.register("backend.update.pdf",function() + if not done then + function pdf.getfontobjnum (k) return objects[k] end + function pdf.getfontname (k) return names [k] end + function pdf.includechar () end -- maybe, when we need it + function pdf.includefont () end -- maybe, when we need it + function pdf.includecharlist () end -- maybe, when we need it + function pdf.setomitcidset (v) includecidset = not v end + function pdf.setomitcharset () end -- we don't need that in lmtx + function pdf.setsuppressoptionalinfo() end -- we don't need that in lmtx + function pdf.mapfile (n) loadmapfile(n) end + function pdf.mapline (n) loadmapline(n) end + -- this will change + lpdf.registerdocumentfinalizer(lpdf.flushfonts,1,"wrapping up fonts") + done = true + end +end) diff --git a/tex/context/base/mkiv/lpdf-epa.lua b/tex/context/base/mkiv/lpdf-epa.lua index 570d73881..01c4e237f 100644 --- a/tex/context/base/mkiv/lpdf-epa.lua +++ b/tex/context/base/mkiv/lpdf-epa.lua @@ -295,6 +295,12 @@ function codeinjections.mergereferences(specification) if annotation.Subtype == "Link" then local a = annotation.A if not a then + local d = annotation.Dest + if d then + annotation.A = { S = "GoTo", D = d } -- no need for a dict + end + end + if not a then report_link("missing link annotation") else local x, y, w, h = getdimensions(annotation,llx,lly,xscale,yscale,width,height,report_link) diff --git a/tex/context/base/mkiv/lpdf-img.lua b/tex/context/base/mkiv/lpdf-img.lua new file mode 100644 index 000000000..aa91f9f22 --- /dev/null +++ b/tex/context/base/mkiv/lpdf-img.lua @@ -0,0 +1,1206 @@ +if not modules then modules = { } end modules ['lpdf-img'] = { + version = 1.001, + comment = "companion to lpdf-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- This started as an experiment but has potential for some (cached) optimizations. +-- At some point we can also use it for fonts. For small images performance is ok +-- with pure lua but for bigger images we can use some helpers. Normally in a +-- typesetting workflow non-interlaced images are used. One should convert +-- interlaced images to more efficient non-interlaced ones (ok, we can cache +-- them if needed). +-- +-- The \LUA\ code is slightly optimized so we could have done with less lines if +-- we wanted but best gain a little. The idea is that we collect striped (in stages) +-- so that we can play with substitutions. + +local type = type +local concat, move = table.concat, table.move +local ceil = math.ceil +local char, find = string.char, string.find +local idiv = number.idiv +local band, rshift = bit32.band, bit32.rshift + +local loaddata = io.loaddata +local setmetatableindex = table.setmetatableindex + +local streams = utilities.streams +local openstring = streams.openstring +local readstring = streams.readstring +local readbytetable = streams.readbytetable + +local tobytetable = string.bytetable + +local lpdf = lpdf or { } +local pdfdictionary = lpdf.dictionary +local pdfarray = lpdf.array +local pdfconstant = lpdf.constant +local pdfstring = lpdf.string +local pdfflushstreamobject = lpdf.flushstreamobject +local pdfreference = lpdf.reference + +local pdfmajorversion = lpdf.majorversion +local pdfminorversion = lpdf.minorversion + +local createimage = images.create + +local zlibcompress = flate and flate.zip_compress or zlib.compress +local zlibdecompress = zlib.decompress -- todo + +local trace = false + +local report_jpg = logs.reporter("graphics","jpg") +local report_jp2 = logs.reporter("graphics","jp2") +local report_png = logs.reporter("graphics","png") + +trackers.register("graphics.backend", function(v) trace = v end) + +local injectors = { } +lpdf.injectors = injectors + +local chars = setmetatableindex(function(t,k) -- share this one + local v = (k <= 0 and "\000") or (k >= 255 and "\255") or char(k) + t[k] = v + return v +end) + +do + + function injectors.jpg(specification) + if specification.error then + return + end + local filename = specification.filename + if not filename then + return + end + local colorspace = specification.colorspace or jpg_gray + local decodearray = nil + ----- procset = colorspace == 0 and "image b" or "image c" + if colorspace == 1 then + colorspace = "DeviceGray" + elseif colorspace == 2 then + colorspace = "DeviceRGB" + elseif colorspace == 3 then + colorspace = "DeviceCMYK" + decodearray = pdfarray { 1, 0, 1, 0, 1, 0, 1, 0 } + end + -- todo: set filename + local xsize = specification.xsize + local ysize = specification.ysize + local colordepth = specification.colordepth + local content = loaddata(filename) + local xobject = pdfdictionary { + Type = pdfconstant("XObject"), + Subtype = pdfconstant("Image"), + -- BBox = pdfarray { 0, 0, xsize, ysize }, + Width = xsize, + Height = ysize, + BitsPerComponent = colordepth, + Filter = pdfconstant("DCTDecode"), + ColorSpace = pdfconstant(colorspace), + Decode = decodearray, + Length = #content, -- specification.length + } + specification.attr + if trace then + report_jpg("%s: width %i, height %i, colordepth %i, size %i",filename,xsize,ysize,colordepth,#content) + end + return createimage { + bbox = { 0, 0, specification.width/xsize, specification.height/ysize }, -- mandate + transform = specification.transform, + nolength = true, + nobbox = true, + notype = true, + stream = content, + attr = xobject(), + } + end + +end + +do + + function injectors.jp2(specification) + if specification.error then + return + end + local filename = specification.filename + if not filename then + return + end + -- todo: set filename + local xsize = specification.xsize + local ysize = specification.ysize + local content = loaddata(filename) + local xobject = pdfdictionary { + Type = pdfconstant("XObject"), + Subtype = pdfconstant("Image"), + BBox = pdfarray { 0, 0, xsize, ysize }, + Width = xsize, + Height = ysize, + Filter = pdfconstant("JPXDecode"), + Length = #content, -- specification.length + } + specification.attr + if trace then + report_jp2("%s: width %i, height %i, size %i",filename,xsize,ysize,#content) + end + return createimage { + bbox = { 0, 0, specification.width/xsize, specification.height/ysize }, -- mandate + transform = specification.transform, + nolength = true, + nobbox = true, + notype = true, + stream = content, + attr = xobject(), + } + end + +end + +do + + -- We don't like interlaced files. You can deinterlace them beforehand because otherwise + -- each run you add runtime. Actually, even masked images can best be converted to PDF + -- beforehand. + + -- The amount of code is larger that I like and looks somewhat redundant but we sort of + -- optimize a few combinations that happen often. + + local pngapplyfilter = pnge and pnge.applyfilter + local pngsplitmask = pnge and pnge.splitmask + local pnginterlace = pnge and pnge.interlace + local pngexpand = pnge and pnge.expand + + local filtermask, decodemask, decodestrip, transpose, expand + + local newindex = lua.newindex + local newtable = lua.newtable + + local function newoutput(size) + if newindex then + return newindex(size,0) + end + local t = newtable and newtable(size,0) or { } + for i=1,size do + t[i] = 0 + end + return t + end + + local function convert(t) + if type(t) == "table" then + for i=1,#t do + local ti = t[i] + if ti ~= "" then -- soon gone + t[i] = chars[ti] + end + end + return concat(t) + else + return t + end + end + + local function zero(t,k) + return 0 + end + + local function applyfilter(t,xsize,ysize,bpp) + local len = xsize * bpp + 1 + local n = 1 + local m = len - 1 + for i=1,ysize do + local filter = t[n] + t[n] = "" + if filter == 0 then + elseif filter == 1 then + for j=n+bpp+1,n+m do + t[j] = (t[j] + t[j-bpp]) % 256 + end + elseif filter == 2 then + for j=n+1,n+m do + t[j] = (t[j] + t[j-len]) % 256 + end + elseif filter == 3 then + for j=n+1,n+bpp do + t[j] = (t[j] + idiv(t[j-len],2)) % 256 + end + for j=n+bpp+1,n+m do + t[j] = (t[j] + idiv(t[j-bpp] + t[j-len],2)) % 256 + end + elseif filter == 4 then + for j=n+1,n+bpp do + local p = j - len + local b = t[p] + if b > 0 then + t[j] = (t[j] + b) % 256 + end + end + for j=n+bpp+1,n+m do + local p = j - len + local a = t[j-bpp] + local b = t[p] + local c = t[p-bpp] + local pa = b - c + local pb = a - c + local pc = pa + pb + if pa < 0 then pa = - pa end + if pb < 0 then pb = - pb end + if pc < 0 then pc = - pc end + t[j] = (t[j] + ((pa <= pb and pa <= pc and a) or (pb <= pc and b) or c)) % 256 + end + end + n = n + len + end + return t + end + + local filtermask_l = function (content,xsize,ysize,colordepth,colorspace,hasfilter) + local mask = { } + local bytes = colordepth == 16 and 2 or 1 + local bpp = colorspace == "DeviceRGB" and 3 or 1 + local length = #content + local size = ysize * xsize * ((bpp+1)*bytes + (hasfilter and 1 or 0)) + local n = 1 + local l = 1 + if bytes == 2 then + if bpp == 1 then + for i=1,ysize do + if hasfilter then + content[n] = "" ; n = n + 1 + end + for j=1,xsize do + content[n] = chars[content[n]] ; n = n + 1 + content[n] = chars[content[n]] ; n = n + 1 + mask[l] = chars[content[n]] ; l = l + 1 + content[n] = "" ; n = n + 1 + mask[l] = chars[content[n]] ; l = l + 1 + content[n] = "" ; n = n + 1 + end + end + elseif bpp == 3 then + for i=1,ysize do + if hasfilter then + content[n] = "" ; n = n + 1 + end + for j=1,xsize do + content[n] = chars[content[n]] ; n = n + 1 + content[n] = chars[content[n]] ; n = n + 1 + content[n] = chars[content[n]] ; n = n + 1 + content[n] = chars[content[n]] ; n = n + 1 + content[n] = chars[content[n]] ; n = n + 1 + content[n] = chars[content[n]] ; n = n + 1 + mask[l] = chars[content[n]] ; l = l + 1 + content[n] = "" ; n = n + 1 + mask[l] = chars[content[n]] ; l = l + 1 + content[n] = "" ; n = n + 1 + end + end + else + return "", "" + end + else + if bpp == 1 then + for i=1,ysize do + if hasfilter then + content[n] = "" ; n = n + 1 + end + for j=1,xsize do + content[n] = chars[content[n]] ; n = n + 1 + mask[l] = chars[content[n]] ; l = l + 1 + content[n] = "" ; n = n + 1 + end + end + elseif bpp == 3 then + for i=1,ysize do + if hasfilter then + content[n] = "" ; n = n + 1 + end + for j=1,xsize do + content[n] = chars[content[n]] ; n = n + 1 + content[n] = chars[content[n]] ; n = n + 1 + content[n] = chars[content[n]] ; n = n + 1 + mask[l] = chars[content[n]] ; l = l + 1 + content[n] = "" ; n = n + 1 + end + end + else + return "", "" + end + end + return concat(content), concat(mask) + end + + local decodemask_l = function(content,xsize,ysize,colordepth,colorspace) + local bytes = colordepth == 16 and 2 or 1 + local bpp = colorspace == "DeviceRGB" and 3 or 1 + local slice = bytes*(bpp+1) + local length = #content + local size = ysize * xsize * ((bpp+1)*bytes + 1) -- assume filter + content = openstring(content) + content = readbytetable(content,length) + setmetatableindex(content,zero) + applyfilter(content,xsize,ysize,slice) + content, mask = filtermask(content,xsize,ysize,colordepth,colorspace,true) + return content, mask + end + + local filtermask_c = function(content,xsize,ysize,colordepth,colorspace) + local bytes = colordepth == 16 and 2 or 1 + local bpp = colorspace == "DeviceRGB" and 3 or 1 + return pngsplitmask(content,xsize,ysize,bpp,bytes) + end + + local decodemask_c = function(content,xsize,ysize,colordepth,colorspace) + local mask = true + local filter = false + local bytes = colordepth == 16 and 2 or 1 + local bpp = colorspace == "DeviceRGB" and 3 or 1 + local slice = bytes * (bpp + 1) -- always a mask + content = pngapplyfilter(content,xsize,ysize,slice) + return pngsplitmask(content,xsize,ysize,bpp,bytes,mask,filter) + end + + local function decodestrip_l(s,nx,ny,slice) + local input = readbytetable(s,ny*(nx*slice+1)) + setmetatableindex(input,zero) + applyfilter(input,nx,ny,slice) + return input, true + end + + local function decodestrip_c(s,nx,ny,slice) + local input = readstring(s,ny*(nx*slice+1)) + input = pngapplyfilter(input,nx,ny,slice) + return input, false + end + + local xstart = { 0, 4, 0, 2, 0, 1, 0 } + local ystart = { 0, 0, 4, 0, 2, 0, 1 } + local xstep = { 8, 8, 4, 4, 2, 2, 1 } + local ystep = { 8, 8, 8, 4, 4, 2, 2 } + + local xblock = { 8, 4, 4, 2, 2, 1, 1 } + local yblock = { 8, 8, 4, 4, 2, 2, 1 } + + local function transpose_l(xsize,ysize,slice,pass,input,output,filter) + local xstart = xstart[pass] + local xstep = xstep[pass] + local ystart = ystart[pass] + local ystep = ystep[pass] + local nx = idiv(xsize + xstep - xstart - 1,xstep) + local ny = idiv(ysize + ystep - ystart - 1,ystep) + local offset = filter and 1 or 0 + local xstep = xstep * slice + local xstart = xstart * slice + local xsize = xsize * slice + local target = ystart * xsize + xstart + 1 + local ystep = ystep * xsize + local start = 1 + local plus = nx * xstep + local step = plus - xstep + if not output then + output = newoutput(xsize*(parts or slice)*ysize) + end + if slice == 1 then + for j=0,ny-1 do + start = start + offset + local target = target + j * ystep + for target=target,target+step,xstep do + output[target] = input[start] + start = start + slice + end + end + elseif slice == 2 then + for j=0,ny-1 do + start = start + offset + local target = target + j * ystep + for target=target,target+step,xstep do + output[target] = input[start] + output[target+1] = input[start+1] + start = start + slice + end + end + elseif slice == 3 then + for j=0,ny-1 do + start = start + offset + local target = target + j * ystep + for target=target,target+step,xstep do + output[target] = input[start] + output[target+1] = input[start+1] + output[target+2] = input[start+2] + start = start + slice + end + end + elseif slice == 4 then + for j=0,ny-1 do + start = start + offset + local target = target + j * ystep + for target=target,target+step,xstep do + output[target] = input[start] + output[target+1] = input[start+1] + output[target+2] = input[start+2] + output[target+3] = input[start+3] + start = start + slice + end + end + else + local delta = slice - 1 + for j=0,ny-1 do + start = start + offset + local target = target + j * ystep + for target=target,target+step,xstep do + move(input,start,start+delta,target,output) + start = start + slice + end + end + end + return output; + end + + local transpose_c = pnginterlace + + -- print(band(rshift(v,4),0x03),extract(v,4,2)) + -- print(band(rshift(v,6),0x03),extract(v,6,2)) + + local function expand_l(t,xsize,ysize,parts,run,factor,filter) + local size = ysize * xsize + 1 -- a bit of overshoot, needs testing, probably a few bytes us ok + local xline = filter and (run+1) or run + local f = filter and 1 or 0 + local l = xline - 1 + local n = 1 + local o = newoutput(size) + local k = 0 + if factor then + if parts == 4 then + for i=1,ysize do + for j=n+f,n+l do + local v = t[j] + if v == 0 then + k = k + 2 + else + k = k + 1 ; o[k] = extract4(v,4) * 0x11 + k = k + 1 ; o[k] = extract4(v,0) * 0x11 + end + end + k = i * xsize + n = n + xline + end + elseif parts == 2 then + for i=1,ysize do + for j=n+f,n+l do + local v = t[j] + if v == 0 then + k = k + 4 + else + k = k + 1 ; o[k] = extract2(v,6) * 0x55 + k = k + 1 ; o[k] = extract2(v,4) * 0x55 + k = k + 1 ; o[k] = extract2(v,2) * 0x55 + k = k + 1 ; o[k] = extract2(v,0) * 0x55 + end + end + k = i * xsize + n = n + xline + end + else + for i=1,ysize do + for j=n+f,n+l do + local v = t[j] + if v == 0 then + k = k + 8 + else + k = k + 1 ; if band(v,0x80) ~= 0 then o[k] = 0xFF end -- o[k] = extract1(v,7) * 0xFF + k = k + 1 ; if band(v,0x40) ~= 0 then o[k] = 0xFF end -- o[k] = extract1(v,6) * 0xFF + k = k + 1 ; if band(v,0x20) ~= 0 then o[k] = 0xFF end -- o[k] = extract1(v,5) * 0xFF + k = k + 1 ; if band(v,0x10) ~= 0 then o[k] = 0xFF end -- o[k] = extract1(v,4) * 0xFF + k = k + 1 ; if band(v,0x08) ~= 0 then o[k] = 0xFF end -- o[k] = extract1(v,3) * 0xFF + k = k + 1 ; if band(v,0x04) ~= 0 then o[k] = 0xFF end -- o[k] = extract1(v,2) * 0xFF + k = k + 1 ; if band(v,0x02) ~= 0 then o[k] = 0xFF end -- o[k] = extract1(v,1) * 0xFF + k = k + 1 ; if band(v,0x01) ~= 0 then o[k] = 0xFF end -- o[k] = extract1(v,0) * 0xFF + end + end + k = i * xsize + n = n + xline + end + end + else + if parts == 4 then + for i=1,ysize do + for j=n+f,n+l do + local v = t[j] + if v == 0 then + k = k + 2 + else + k = k + 1 ; o[k] = extract4(v,4) + k = k + 1 ; o[k] = extract4(v,0) + end + end + k = i * xsize + n = n + xline + end + elseif parts == 2 then + for i=1,ysize do + for j=n+f,n+l do + local v = t[j] + if v == 0 then + k = k + 4 + else + k = k + 1 ; o[k] = extract2(v,6) + k = k + 1 ; o[k] = extract2(v,4) + k = k + 1 ; o[k] = extract2(v,2) + k = k + 1 ; o[k] = extract2(v,0) + end + end + k = i * xsize + n = n + xline + end + else + for i=1,ysize do + for j=n+f,n+l do + local v = t[j] + if v == 0 then + k = k + 8 + else + k = k + 1 ; if band(v,0x80) ~= 0 then o[k] = 1 end -- o[k] = extract1(v,7) + k = k + 1 ; if band(v,0x40) ~= 0 then o[k] = 1 end -- o[k] = extract1(v,6) + k = k + 1 ; if band(v,0x20) ~= 0 then o[k] = 1 end -- o[k] = extract1(v,5) + k = k + 1 ; if band(v,0x10) ~= 0 then o[k] = 1 end -- o[k] = extract1(v,4) + k = k + 1 ; if band(v,0x08) ~= 0 then o[k] = 1 end -- o[k] = extract1(v,3) + k = k + 1 ; if band(v,0x04) ~= 0 then o[k] = 1 end -- o[k] = extract1(v,2) + k = k + 1 ; if band(v,0x02) ~= 0 then o[k] = 1 end -- o[k] = extract1(v,1) + k = k + 1 ; if band(v,0x01) ~= 0 then o[k] = 1 end -- o[k] = extract1(v,0) + end + end + k = i * xsize + n = n + xline + end + end + end + for i=size,xsize * ysize +1,-1 do + o[i] = nil + end + return o, false + end + + local expand_c = pngexpand + + local function analyze(colordepth,colorspace,palette,mask) + -- return bytes, parts, factor + if palette then + if colordepth == 16 then + return 2, false, false + elseif colordepth == 8 then + return 1, false, false + elseif colordepth == 4 then + return 1, 4, false + elseif colordepth == 2 then + return 1, 2, false + elseif colordepth == 1 then + return 1, 1, false + end + elseif colorspace == "DeviceGray" then + if colordepth == 16 then + return mask and 4 or 2, false, false + elseif colordepth == 8 then + return mask and 2 or 1, false, false + elseif colordepth == 4 then + return 1, 4, true + elseif colordepth == 2 then + return 1, 2, true + elseif colordepth == 1 then + return 1, 1, true + end + else + if colordepth == 16 then + return mask and 8 or 6, false, false + elseif colordepth == 8 then + return mask and 4 or 3, false, false + elseif colordepth == 4 then + return 3, 4, true + elseif colordepth == 2 then + return 3, 2, true + elseif colordepth == 1 then + return 3, 1, true + end + end + return false, false, false + end + + -- 1 6 4 6 2 6 4 6 + -- 7 7 7 7 7 7 7 7 + -- 5 6 5 6 5 6 5 6 + -- 7 7 7 7 7 7 7 7 + -- 3 6 4 6 3 6 4 6 + -- 7 7 7 7 7 7 7 7 + -- 5 6 5 6 5 6 5 6 + -- 7 7 7 7 7 7 7 7 + + local function deinterlace(content,xsize,ysize,colordepth,colorspace,palette,mask) + local slice, parts, factor = analyze(colordepth,colorspace,palette,mask) + if slice then + content = openstring(zlibdecompress(content)) + local filter = false + local output = false + for pass=1,7 do + local xstart = xstart[pass] + local xstep = xstep[pass] + local ystart = ystart[pass] + local ystep = ystep[pass] + local nx = idiv(xsize + xstep - xstart - 1,xstep) + local ny = idiv(ysize + ystep - ystart - 1,ystep) + if nx > 0 and ny > 0 then + local input, filter + if parts then + local nxx = ceil(nx*parts/8) + input, filter = decodestrip(content,nxx,ny,slice) + input, filter = expand(input,nx,ny,parts,nxx,factor,filter) + else + input, filter = decodestrip(content,nx,ny,slice) + end + output = transpose(xsize,ysize,slice,pass,input,output,filter) + end + -- if pass == 3 then + -- break -- still looks ok, could be nice for a preroll + -- end + end + return output, parts and 8 or false + end + end + + -- 1 (palette used), 2 (color used), and 4 (alpha channel used) + + -- paeth: + -- + -- p = a + b - c + -- pa = abs(p - a) => a + b - c - a => b - c + -- pb = abs(p - b) => a + b - c - b => a - c + -- pc = abs(p - c) => a + b - c - c => a + b - c - c => a - c + b - c => pa + pb + + local function full(t,k) local v = "\xFF" t[k] = v return v end + + local function expandvector(transparent) + local s = openstring(transparent) + local n = #transparent + local r = { } + for i=0,n-1 do + r[i] = readstring(s,1) -- readchar + end + setmetatableindex(r,full) + return r + end + + local function createmask_l(content,palette,transparent,xsize,ysize,colordepth,colorspace) + if palette then + local r = expandvector(transparent) + local size = xsize*ysize + local len = ceil(xsize*colordepth/8) + 1 + local o = newoutput(xsize*ysize) + local u = setmetatableindex(zero) + content = zlibdecompress(content) + content = openstring(content) + for i=0,ysize-1 do + local t = readbytetable(content,len) + local k = i * xsize + local filter = t[1] + if filter == 0 then + elseif filter == 1 then + for j=3,len do + t[j] = (t[j] + t[j-1]) % 256 + end + elseif filter == 2 then + for j=2,len do + t[j] = (t[j] + u[j]) % 256 + end + elseif filter == 3 then + local j = 2 + t[j] = (t[j] + idiv(u[j],2)) % 256 + for j=3,len do + t[j] = (t[j] + idiv(t[j-1] + u[j],2)) % 256 + end + elseif filter == 4 then + local j = 2 + local p = j - len + local b = t[p] + if b < 0 then + b = - b + end + if b > 0 then + t[j] = (t[j] + b) % 256 + end + for j=3,len do + local p = j - len + local a = t[j-1] + local b = t[p] + local c = t[p-1] + local pa = b - c + local pb = a - c + local pc = pa + pb + if pa < 0 then pa = - pa end + if pb < 0 then pb = - pb end + if pc < 0 then pc = - pc end + t[j] = (t[j] + ((pa <= pb and pa <= pc and a) or (pb <= pc and b) or c)) % 256 + end + end + if colordepth == 8 then + for j=2,len do + local v = t[j] + k = k + 1 ; o[k] = r[v] + end + elseif colordepth == 4 then + for j=2,len do + local v = t[j] + k = k + 1 ; o[k] = r[extract4(v,4)] + k = k + 1 ; o[k] = r[extract4(v,0)] + end + elseif colordepth == 2 then + for j=2,len do + local v = t[j] + k = k + 1 ; o[k] = r[extract2(v,6)] + k = k + 1 ; o[k] = r[extract2(v,4)] + k = k + 1 ; o[k] = r[extract2(v,2)] + k = k + 1 ; o[k] = r[extract2(v,0)] + end + else + for j=2,len do + local v = t[j] + k = k + 1 ; o[k] = r[extract1(v,7)] + k = k + 1 ; o[k] = r[extract1(v,6)] + k = k + 1 ; o[k] = r[extract1(v,5)] + k = k + 1 ; o[k] = r[extract1(v,4)] + k = k + 1 ; o[k] = r[extract1(v,3)] + k = k + 1 ; o[k] = r[extract1(v,2)] + k = k + 1 ; o[k] = r[extract1(v,1)] + k = k + 1 ; o[k] = r[extract1(v,0)] + end + end + u = t + end + return concat(o,"",1,size) + end + end + + local function createmask_c(content,palette,transparent,xsize,ysize,colordepth,colorspace) + if palette then + local r = expandvector(transparent) + local size = xsize*ysize + local len = ceil(xsize*colordepth/8) + local o = newoutput(size) + content = zlibdecompress(content) + content = pngapplyfilter(content,len,ysize,1) -- nostrip (saves copy) + content = openstring(content) + for i=0,ysize-1 do + local t = readbytetable(content,len) + local k = i * xsize + if colordepth == 8 then + for j=1,len do + local v = t[j] + k = k + 1 ; o[k] = r[v] + end + elseif colordepth == 4 then + for j=1,len do + local v = t[j] + k = k + 1 ; o[k] = r[extract4(v,4)] + k = k + 1 ; o[k] = r[extract4(v,0)] + end + elseif colordepth == 2 then + for j=1,len do + local v = t[j] + k = k + 1 ; o[k] = r[extract2(v,6)] + k = k + 1 ; o[k] = r[extract2(v,4)] + k = k + 1 ; o[k] = r[extract2(v,2)] + k = k + 1 ; o[k] = r[extract2(v,0)] + end + else + for j=1,len do + local v = t[j] + k = k + 1 ; o[k] = r[extract1(v,7)] + k = k + 1 ; o[k] = r[extract1(v,6)] + k = k + 1 ; o[k] = r[extract1(v,5)] + k = k + 1 ; o[k] = r[extract1(v,4)] + k = k + 1 ; o[k] = r[extract1(v,3)] + k = k + 1 ; o[k] = r[extract1(v,2)] + k = k + 1 ; o[k] = r[extract1(v,1)] + k = k + 1 ; o[k] = r[extract1(v,0)] + end + end + end + return concat(o,"",1,size) + end + end + + local function switch(v) + if v then + filtermask = filtermask_l + decodemask = decodemask_l + decodestrip = decodestrip_l + transpose = transpose_l + expand = expand_l + createmask = createmask_l + else + filtermask = filtermask_c + decodemask = decodemask_c + decodestrip = decodestrip_c + transpose = transpose_c + expand = expand_c + createmask = createmask_c + end + end + + if pngapplyfilter then + switch(false) + directives.register("graphics.png.purelua",switch) + else + switch(true) + end + + local alwaysdecode = false + + -- directives.register("graphics.png.decode", function(v) + -- alwaysdecode = v + -- end) + + function injectors.png(specification) +-- inspect(specification) + if specification.error then + return + end + local filename = specification.filename + if not filename then + return + end + local colorspace = specification.colorspace + if not colorspace then + return + end + local interlace = specification.interlace or 0 + if interlace == 1 then + interlace = true + elseif interlace == 0 then + interlace = false + else + report_png("unknown interlacing %i",interlace) + return + end + local tables = specification.tables + if not tables then + return + end + local idat = tables.idat + if not idat then + return + end + local pngfile = io.open(filename,"rb") -- todo: in-mem too + if not pngfile then + return + end + local content = idat(pngfile,true) + tables.idat = false + -- + -- if tables.gama then + -- report_png("ignoring gamma correction") + -- end + -- + local xsize = specification.xsize + local ysize = specification.ysize + local colordepth = specification.colordepth or 8 + local mask = false + local transparent = false + local palette = false + local colors = 1 + if colorspace == 0 then -- gray | image b + colorspace = "DeviceGray" + transparent = true + elseif colorspace == 2 then -- rgb | image c + colorspace = "DeviceRGB" + colors = 3 + transparent = true + elseif colorspace == 3 then -- palette | image c+i + colorspace = "DeviceRGB" + palette = true + transparent = true + elseif colorspace == 4 then -- gray | alpha | image b + colorspace = "DeviceGray" + mask = true + elseif colorspace == 6 then -- rgb | alpha | image c + colorspace = "DeviceRGB" + colors = 3 + mask = true + else + report_png("unknown colorspace %i",colorspace) + return + end + -- + if transparent then + local trns = tables.trns + if trns then + transparent = trns(pngfile,true) + if transparent == "" then + transparent = false + end + tables.trns = false + else + transparent = false + end + end + -- + local decode = alwaysdecode + local major = pdfmajorversion() + local minor = pdfminorversion() + if major > 1 then + -- we're okay + elseif minor < 5 and colordepth == 16 then + report_png("16 bit colordepth not supported in pdf < 1.5") + return + elseif minor < 4 and (mask or transparent) then + report_png("alpha channels not supported in pdf < 1.4") + return + elseif minor < 2 then + report_png("you'd better use a version > 1.2") + return + -- decode = true + end + -- + -- todo: compresslevel (or delegate) + -- + if palette then + local plte = tables.plte + if plte then + palette = plte(pngfile,true) + if palette == "" then + palette = false + end + tables.plte = false + else + palette = false + end + end + -- + if interlace then + local r, p = deinterlace(content,xsize,ysize,colordepth,colorspace,palette,mask) + if not r then + return + end + if p then + colordepth = p + end + if mask then + if not (colordepth == 8 or colordepth == 16) then + report_png("mask can't be split from the image") + return + end -- get rid of bpp: + content, mask = filtermask(r,xsize,ysize,colordepth,colorspace,false) + else + content = convert(r) -- can be in deinterlace if needed + end + content = zlibcompress(content,3) + decode = true + elseif mask then + if not (colordepth == 8 or colordepth == 16) then + report_png("mask can't be split from the image") + return + end + content = zlibdecompress(content) + content, mask = decodemask(content,xsize,ysize,colordepth,colorspace) + content = zlibcompress(content,3) + decode = true -- we don't copy the filter byte + elseif transparent then + -- in test suite + if palette then + mask = createmask(content,palette,transparent,xsize,ysize,colordepth,colorspace) + else + pallette = false + end + elseif decode then + -- this one needs checking + local bytes = analyze(colordepth,colorspace) + if bytes then + content = zlibdecompress(content) + content = applyfilter(content,xsize,ysize,bytes) + content = zlibcompress(content,3) + else + return + end + else + -- print("PASS ON") + end + if palette then + palette = pdfarray { + pdfconstant("Indexed"), + pdfconstant("DeviceRGB"), + idiv(#palette,3), + pdfreference(pdfflushstreamobject(palette)), + } + end + pngfile:close() + local xobject = pdfdictionary { + Type = pdfconstant("XObject"), + Subtype = pdfconstant("Image"), + -- BBox = pdfarray { 0, 0, xsize, ysize }, + Width = xsize, + Height = ysize, + BitsPerComponent = colordepth, + Filter = pdfconstant("FlateDecode"), + ColorSpace = palette or pdfconstant(colorspace), + Length = #content, + } + specification.attr + if mask then + local d = pdfdictionary { + Type = pdfconstant("XObject"), + Subtype = pdfconstant("Image"), + Width = xsize, + Height = ysize, + BitsPerComponent = palette and 8 or colordepth, + ColorSpace = pdfconstant("DeviceGray"), + } + xobject.SMask = pdfreference(pdfflushstreamobject(mask,d())) + end + if not decode then + xobject.DecodeParms = pdfdictionary { + Colors = colors, + Columns = xsize, + BitsPerComponent = colordepth, + Predictor = 15, + } + end + if trace then + report_png("%s: width %i, height %i, colordepth: %i, size: %i, palette %l, mask: %l, transparent %l, decode %l",filename,xsize,ysize,colordepth,#content,palette,mask,transparent,decode) + end + if specification.colorref then + xobject.ColorSpace = pdfreference(specification.colorref) + end + return createimage { + bbox = { 0, 0, specification.width/xsize, specification.height/ysize }, -- mandate + transform = specification.transform, + nolength = true, + nobbox = true, + notype = true, + stream = content, + attr = xobject(), + } + end + +end + +do + + local function pack(specification,what) + local t = { } + local n = 0 + local s = specification.colorspace + local d = specification.data + local x = specification.xsize + local y = specification.ysize + if what == "mask" then + d = specification.mask + s = 1 + end + if s == 1 then + for i=1,y do + local r = d[i] + for j=1,x do + n = n + 1 ; t[n] = chars[r[j]] + end + end + elseif s == 2 then + for i=1,y do + local r = d[i] + for j=1,x do + local c = r[j] + n = n + 1 ; t[n] = chars[c[1]] + n = n + 1 ; t[n] = chars[c[2]] + n = n + 1 ; t[n] = chars[c[3]] + end + end + elseif s == 3 then + for i=1,y do + local r = d[i] + for j=1,x do + local c = r[j] + n = n + 1 ; t[n] = chars[c[1]] + n = n + 1 ; t[n] = chars[c[2]] + n = n + 1 ; t[n] = chars[c[3]] + n = n + 1 ; t[n] = chars[c[4]] + end + end + end + return concat(t) + end + + function injectors.bitmap(specification) + local data = specification.data + if not data then + return + end + local xsize = specification.xsize or 0 + local ysize = specification.ysize or 0 + if xsize == 0 or ysize == 0 then + return + end + local colorspace = specification.colorspace or 1 + if colorspace == 1 then + colorspace = "DeviceGray" + elseif colorspace == 2 then + colorspace = "DeviceRGB" + elseif colorspace == 3 then + colorspace = "DeviceCMYK" + end + local colordepth = (specification.colordepth or 2) == 16 or 8 + local content = pack(specification,"data") + local mask = specification.mask + local xobject = pdfdictionary { + Type = pdfconstant("XObject"), + Subtype = pdfconstant("Image"), + BBox = pdfarray { 0, 0, xsize, ysize }, + Width = xsize, + Height = ysize, + BitsPerComponent = colordepth, + ColorSpace = pdfconstant(colorspace), + Length = #content, -- specification.length + } + if mask then + local d = pdfdictionary { + Type = pdfconstant("XObject"), + Subtype = pdfconstant("Image"), + Width = xsize, + Height = ysize, + BitsPerComponent = colordepth, + ColorSpace = pdfconstant("DeviceGray"), + } + xobject.SMask = pdfreference(pdfflushstreamobject(pack(specification,"mask"),d())) + end + return createimage { + bbox = { 0, 0, specification.width/xsize, specification.height/ysize }, -- mandate + -- nolength = true, + nobbox = true, + notype = true, + stream = content, + attr = xobject(), + } + end + +end + +-- local function validcompression(data) +-- local d = utilities.streams.openstring(data) +-- local b1 = utilities.streams.readbyte(d) +-- local b2 = utilities.streams.readbyte(d) +-- print(b1,b2) +-- if (b1 * 256 + b2) % 31 ~= 0 then +-- return false, "no zlib compressed file" +-- end +-- local method = band(b1,15) +-- if method ~= 8 then +-- return false, "method 8 expected" +-- end +-- local detail = band(rshift(b1,4),15) +-- if detail > 7 then +-- return false, "window 32 expected" +-- end +-- local preset = band(rshift(b2,5),1) +-- if preset ~= 0 then +-- return false, "unexpected preset dictionary" +-- end +-- return true +-- end diff --git a/tex/context/base/mkiv/lpdf-ini.lua b/tex/context/base/mkiv/lpdf-ini.lua index 19f2d7504..050b1fa84 100644 --- a/tex/context/base/mkiv/lpdf-ini.lua +++ b/tex/context/base/mkiv/lpdf-ini.lua @@ -18,6 +18,7 @@ local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns local formatters = string.formatters local isboolean = string.is_boolean local rshift = bit32.rshift +local osdate, ostime = os.date, os.time local report_objects = logs.reporter("backend","objects") local report_finalizing = logs.reporter("backend","finalizing") @@ -50,199 +51,137 @@ local pdfbackend = { backends.pdf = pdfbackend -lpdf = lpdf or { } -local lpdf = lpdf -lpdf.flags = lpdf.flags or { } -- will be filled later - -local pdfsetinfo = pdf.setinfo -local pdfsetcatalog = pdf.setcatalog ------ pdfsetnames = pdf.setnames ------ pdfsettrailer = pdf.settrailer -local pdfsettrailerid = pdf.settrailerid - -local pdfsetpageresources = pdf.setpageresources -local pdfsetpageattributes = pdf.setpageattributes -local pdfsetpagesattributes = pdf.setpagesattributes - -local pdfreserveobject = pdf.reserveobj -local pdfimmediateobject = pdf.immediateobj -local pdfdeferredobject = pdf.obj -local pdfreferenceobject = pdf.refobj - -local pdfgetfontname = pdf.getfontname -local pdfgetfontobjnum = pdf.getfontobjnum -local pdfgetxformname = pdf.getxformname -local pdfincludeimage = pdf.includeimage -local pdfincludechar = pdf.includechar -local pdfgetpagereference = pdf.getpageref or pdf.pageref -- tex.pdfpageref is obsolete -local pdfsetfontattributes = pdf.setfontattributes - -local setmajorversion = pdf.setmajorversion -local setminorversion = pdf.setminorversion -local getmajorversion = pdf.getmajorversion -local getminorversion = pdf.getminorversion - -local setcompresslevel = pdf.setcompresslevel -local setobjectcompresslevel = pdf.setobjcompresslevel -local getcompresslevel = pdf.getcompresslevel -local getobjectcompresslevel = pdf.getobjcompresslevel - -local setsuppressoptionalinfo = pdf.setsuppressoptionalinfo -local setomitcidset = pdf.setomitcidset -local setomitcharset = pdf.setomitcharset or function() end - -local function pdfdisablecommand(command) - pdf[command] = function() --- report_blocked("'pdf.%s' is not supported",command) - end -end - -pdfdisablecommand("setinfo") -pdfdisablecommand("setcatalog") -pdfdisablecommand("setnames") -pdfdisablecommand("settrailer") -pdfdisablecommand("settrailerid") -pdfdisablecommand("setomitcidset") -pdfdisablecommand("setomitcharset") -pdfdisablecommand("setpageresources") -pdfdisablecommand("setpageattributes") -pdfdisablecommand("setpagesattributes") -pdfdisablecommand("registerannot") -pdfdisablecommand("reserveobj") - -pdf.disablecommand = pdfdisablecommand - -updaters.register("backend.update.lpdf",function() - - pdfsetinfo = pdf.setinfo - pdfsetcatalog = pdf.setcatalog - pdfsettrailerid = pdf.settrailerid - - pdfreserveobject = pdf.reserveobj - pdfimmediateobject = pdf.immediateobj - pdfdeferredobject = pdf.obj - pdfreferenceobject = pdf.refobj - pdfsetfontattributes = pdf.setfontattributes - - pdfgetfontname = pdf.getfontname - pdfgetfontobjnum = pdf.getfontobjnum - pdfgetxformname = pdf.getxformname - pdfincludeimage = pdf.includeimage - pdfincludechar = pdf.includechar - pdfgetpagereference = pdf.getpageref - - setmajorversion = pdf.setmajorversion - setminorversion = pdf.setminorversion - getmajorversion = pdf.getmajorversion - getminorversion = pdf.getminorversion - - setcompresslevel = pdf.setcompresslevel - setobjectcompresslevel = pdf.setobjcompresslevel - getcompresslevel = pdf.getcompresslevel - getobjectcompresslevel = pdf.getobjcompresslevel - - pdfsetpageresources = pdf.setpageresources - pdfsetpageattributes = pdf.setpageattributes - pdfsetpagesattributes = pdf.setpagesattributes - - setsuppressoptionalinfo = pdf.setsuppressoptionalinfo - setomitcidset = pdf.setomitcidset - setomitcharset = pdf.setomitcharset - - pdfdisablecommand("setinfo") - pdfdisablecommand("setcatalog") - pdfdisablecommand("settrailerid") - - pdfdisablecommand("reserveobj") - pdfdisablecommand("getfontname") - pdfdisablecommand("getfontobjnum") -end) +lpdf = lpdf or { } +local lpdf = lpdf +lpdf.flags = lpdf.flags or { } -- will be filled later local trace_finalizers = false trackers.register("backend.finalizers", function(v) trace_finalizers = v end) local trace_resources = false trackers.register("backend.resources", function(v) trace_resources = v end) local trace_objects = false trackers.register("backend.objects", function(v) trace_objects = v end) local trace_detail = false trackers.register("backend.detail", function(v) trace_detail = v end) -function lpdf.settrailerid(id) - pdfsettrailerid(id) -end +do -function lpdf.setversion(major,minor) - setmajorversion(major or 1) - setminorversion(minor or 7) -end + local pdfsetmajorversion, pdfsetminorversion, pdfgetmajorversion, pdfgetminorversion + local pdfsetcompresslevel, pdfsetobjectcompresslevel, pdfgetcompresslevel, pdfgetobjectcompresslevel + local pdfsetsuppressoptionalinfo, pdfsetomitcidset, pdfsetomitcharset -function lpdf.getversion(major,minor) - return getmajorversion(), getminorversion() -end + updaters.register("backend.update.lpdf",function() + pdfsetmajorversion = pdf.setmajorversion + pdfsetminorversion = pdf.setminorversion + pdfgetmajorversion = pdf.getmajorversion + pdfgetminorversion = pdf.getminorversion + + pdfsetcompresslevel = pdf.setcompresslevel + pdfsetobjectcompresslevel = pdf.setobjcompresslevel + pdfgetcompresslevel = pdf.getcompresslevel + pdfgetobjectcompresslevel = pdf.getobjcompresslevel + + pdfsetsuppressoptionalinfo = pdf.setsuppressoptionalinfo + pdfsetomitcidset = pdf.setomitcidset + pdfsetomitcharset = pdf.setomitcharset + end) -function lpdf.majorversion() return getmajorversion() end -function lpdf.minorversion() return getminorversion() end + function lpdf.setversion(major,minor) + pdfsetmajorversion(major or 1) + pdfsetminorversion(minor or 7) + end -function lpdf.getfontname (id) return pdfgetfontname (id) end -function lpdf.getfontobjnumber(id) return pdfgetfontobjnum(id) end + function lpdf.getversion(major,minor) + return pdfgetmajorversion(), pdfgetminorversion() + end -function lpdf.getxformname(id) return pdfgetxformname(id) end -function lpdf.includeimage(id) return pdfincludeimage(id) end + function lpdf.majorversion() return pdfgetmajorversion() end + function lpdf.minorversion() return pdfgetminorversion() end -function lpdf.includechar (f,c) pdfincludechar(f,c) end -function lpdf.includecharlist(f,c) pdfincludechar(f,c) end -- can be disabled + local frozen = false + local clevel = 3 + local olevel = 1 -local frozen = false -local clevel = 3 -local olevel = 1 + function lpdf.setcompression(level,objectlevel,freeze) + if not frozen then + if pdfsetcompresslevel then + pdfsetcompresslevel(level or 3) + pdfsetobjectcompresslevel(objectlevel or level or 3) + else + clevel = level + olevel = objectlevel + end + frozen = freeze + end + end -function lpdf.setcompression(level,objectlevel,freeze) - if not frozen then - if setcompresslevel then - setcompresslevel(level or 3) - setobjectcompresslevel(objectlevel or level or 3) + function lpdf.getcompression() + if pdfgetcompresslevel then + return pdfgetcompresslevel(), pdfgetobjectcompresslevel() else - clevel = level - olevel = objectlevel + return clevel, olevel end - frozen = freeze end -end -function lpdf.getcompression() - if getcompresslevel then - return getcompresslevel(), getobjectcompresslevel() - else - return clevel, olevel + function lpdf.compresslevel() + if pdfgetcompresslevel then + return pdfgetcompresslevel() + else + return clevel + end end -end -function lpdf.compresslevel() - if getcompresslevel then - return getcompresslevel() - else - return clevel + function lpdf.objectcompresslevel() + if pdfgetobjectcompresslevel then + return pdfgetobjectcompresslevel() + else + return olevel + end end -end -function lpdf.objectcompresslevel() - if getobjectcompresslevel then - return getobjectcompresslevel() - else - return olevel + function lpdf.setsuppressoptionalinfo(n) + if pdfsetsuppressoptionalinfo then + pdfsetsuppressoptionalinfo(n) -- todo + end end -end -function lpdf.setsuppressoptionalinfo(n) - if setsuppressoptionalinfo then - setsuppressoptionalinfo(n) -- todo + function lpdf.setomitcidset(v) + return pdfsetomitcidset(v) + end + + function lpdf.setomitcharset(v) + return pdfsetomitcharset(v) end -end -function lpdf.setomitcidset(v) - return setomitcidset(v) end -function lpdf.setomitcharset(v) - return setomitcharset(v) +do + + local pdfgetxformname, pdfincludeimage + + updaters.register("backend.update.lpdf",function() + pdfgetxformname = pdf.getxformname + pdfincludeimage = pdf.includeimage + end) + + function lpdf.getxformname(id) return pdfgetxformname(id) end + function lpdf.includeimage(id) return pdfincludeimage(id) end + end + local pdfsetpageresources, pdfsetpageattributes, pdfsetpagesattributes + local pdfreserveobject, pdfimmediateobject, pdfdeferredobject, pdfreferenceobject + local pdfgetpagereference + + updaters.register("backend.update.lpdf",function() + pdfreserveobject = pdf.reserveobj + pdfimmediateobject = pdf.immediateobj + pdfdeferredobject = pdf.obj + pdfreferenceobject = pdf.refobj + + pdfgetpagereference = pdf.getpageref + + pdfsetpageresources = pdf.setpageresources + pdfsetpageattributes = pdf.setpageattributes + pdfsetpagesattributes = pdf.setpagesattributes + end) + local jobpositions = job.positions local getpos = jobpositions.getpos @@ -254,28 +193,19 @@ jobpositions.registerhandlers { do - local pdfgetmatrix = pdf.getmatrix - local pdfhasmatrix = pdf.hasmatrix - local pdfprint = pdf.print + local pdfgetmatrix, pdfhasmatrix, pdfprint - -- todo + updaters.register("backend.update.lpdf",function() + pdfgetmatrix = pdf.getmatrix + pdfhasmatrix = pdf.hasmatrix + pdfprint = pdf.print + end) function lpdf.print(...) return pdfprint(...) end - pdfbackend.codeinjections.print = lpdf.print - - updaters.register("backend.update.lpdf",function() - pdfprint = pdf.print - end) - - -- todo - - updaters.register("backend.update.lpdf",function() - pdfhasmatrix = pdf.hasmatrix - pdfgetmatrix = pdf.getmatrix - end) + pdfbackend.codeinjections.print = lpdf.print -- will go -- local function transform(llx,lly,urx,ury,rx,sx,sy,ry) -- local x1 = llx * rx + lly * sy @@ -524,7 +454,9 @@ do tostring_d = function(t,contentonly,key) if next(t) then - local r, n, e = { }, 0 + local r = { } + local n = 0 + local e for k, v in next, t do if k == "__extra__" then e = v @@ -1176,6 +1108,18 @@ callbacks.register("finish_pdffile", lpdf.finalizedocument) do + local pdfsetinfo, pdfsetcatalog, pdfsettrailerid -- pdfsetnames pdfsettrailer + + updaters.register("backend.update.lpdf",function() + pdfsetinfo = pdf.setinfo + pdfsetcatalog = pdf.setcatalog + pdfsettrailerid = pdf.settrailerid + end) + + function lpdf.settrailerid(id) + pdfsettrailerid(id) + end + -- some minimal tracing, handy for checking the order local function trace_set(what,key) @@ -1390,7 +1334,8 @@ end -- in strc-bkm: lpdf.registerdocumentfinalizer(function() structures.bookmarks.place() end,1) function lpdf.rotationcm(a) - local s, c = sind(a), cosd(a) + local s = sind(a) + local c = cosd(a) return format("%.6F %.6F %.6F %.6F 0 0 cm",c,s,-s,c) end @@ -1439,8 +1384,13 @@ do lpdf.settime(tonumber(resolvers.variable("start_time")) or tonumber(resolvers.variable("SOURCE_DATE_EPOCH"))) -- bah function lpdf.pdftimestamp(str) - local Y, M, D, h, m, s, Zs, Zh, Zm = match(str,"^(%d%d%d%d)%-(%d%d)%-(%d%d)T(%d%d):(%d%d):(%d%d)([%+%-])(%d%d):(%d%d)$") - return Y and format("D:%s%s%s%s%s%s%s%s'%s'",Y,M,D,h,m,s,Zs,Zh,Zm) + local t = type(str) + if t == "string" then + local Y, M, D, h, m, s, Zs, Zh, Zm = match(str,"^(%d%d%d%d)%-(%d%d)%-(%d%d)T(%d%d):(%d%d):(%d%d)([%+%-])(%d%d):(%d%d)$") + return Y and format("D:%s%s%s%s%s%s%s%s'%s'",Y,M,D,h,m,s,Zs,Zh,Zm) + else + return osdate("D:%Y%m%d%H%M%S",t == "number" and str or ostime()) -- maybe "!D..." : universal time + end end function lpdf.id(date) @@ -1680,23 +1630,30 @@ end do - local pdf_includechar = pdf.includechar - local pdf_includefont = pdf.includefont - local pdf_setmapfile = pdf.mapfile - local pdf_setmapline = pdf.mapline + local pdfincludechar, pdfincludecharlist, pdfincludefont + local pdfgetfontname, pdfgetfontobjnum + local pdfsetmapfile, pdfsetmapline updaters.register("backend.update.lpdf",function() - pdf_includechar = pdf.includechar - pdf_includefont = pdf.includefont - pdf_setmapfile = pdf.mapfile - pdf_setmapline = pdf.mapline + pdfincludechar = pdf.includechar + pdfincludefont = pdf.includefont + pdfincludecharlist = pdf.includecharlist + pdfgetfontname = pdf.getfontname + pdfgetfontobjnum = pdf.getfontobjnum + pdfsetmapfile = pdf.mapfile + pdfsetmapline = pdf.mapline end) - function lpdf.includechar(...) pdf_includechar(...) end - function lpdf.includefont(...) pdf_includefont(...) end + function lpdf.includechar(f,c) pdfincludechar(f,c) end + function lpdf.includefont(...) pdfincludefont(...) end + + function lpdf.includecharlist(f,c) pdfincludecharlist(f,c) end -- can be disabled + + function lpdf.getfontname (id) return pdfgetfontname (id) end + function lpdf.getfontobjnumber(id) return pdfgetfontobjnum(id) end - function lpdf.setmapfile(...) pdf_setmapfile(...) end - function lpdf.setmapline(...) pdf_setmapline(...) end + function lpdf.setmapfile(...) pdfsetmapfile(...) end + function lpdf.setmapline(...) pdfsetmapline(...) end end diff --git a/tex/context/base/mkiv/lpdf-mis.lua b/tex/context/base/mkiv/lpdf-mis.lua index 1d2e07310..77f11918b 100644 --- a/tex/context/base/mkiv/lpdf-mis.lua +++ b/tex/context/base/mkiv/lpdf-mis.lua @@ -268,7 +268,9 @@ local function flushjavascripts() local a = pdfarray() local pdf_javascript = pdfconstant("JavaScript") for i=1,#t do - local name, script = t[i][1], t[i][2] + local ti = t[i] + local name = ti[1] + local script = ti[2] local j = pdfdictionary { S = pdf_javascript, JS = pdfreference(pdfflushstreamobject(script)), diff --git a/tex/context/base/mkiv/lpdf-nod.lua b/tex/context/base/mkiv/lpdf-nod.lua index d5c1f6b46..8bcf18c62 100644 --- a/tex/context/base/mkiv/lpdf-nod.lua +++ b/tex/context/base/mkiv/lpdf-nod.lua @@ -6,7 +6,7 @@ if not modules then modules = { } end modules ['lpdf-nod'] = { license = "see context related readme files" } -if CONTEXTLMTXMODE then +if CONTEXTLMTXMODE > 1 then return end diff --git a/tex/context/base/mkiv/lpdf-pde.lua b/tex/context/base/mkiv/lpdf-pde.lua index 9d14f8f5e..c1680137d 100644 --- a/tex/context/base/mkiv/lpdf-pde.lua +++ b/tex/context/base/mkiv/lpdf-pde.lua @@ -1003,7 +1003,15 @@ if img then do return openpdf(str,userpassword,ownerpassword,true) end - local function querypdf(pdfdoc,pagenumber) + local sizes = { + crop = "CropBox", + media = "MediaBox", + bleed = "BleedBox", + art = "ArtBox", + trim = "TrimBox", + } + + local function querypdf(pdfdoc,pagenumber,size) if pdfdoc then if not pagenumber then pagenumber = 1 @@ -1011,9 +1019,9 @@ if img then do local root = pdfdoc.Catalog local page = pdfdoc.pages[pagenumber] if page then - -- todo + local sizetag = sizes[size or "crop"] or sizes.cro local mediabox = page.MediaBox or { 0, 0, 0, 0 } - local cropbox = page.CropBox or mediabox + local cropbox = page[sizetag] or mediabox return { filename = pdfdoc.filename, pagenumber = pagenumber, diff --git a/tex/context/base/mkiv/lpdf-wid.lua b/tex/context/base/mkiv/lpdf-wid.lua index a929ed2ce..a538a9ad2 100644 --- a/tex/context/base/mkiv/lpdf-wid.lua +++ b/tex/context/base/mkiv/lpdf-wid.lua @@ -268,6 +268,7 @@ function codeinjections.embedfile(specification) local usedname = specification.usedname local filetype = specification.filetype local compress = specification.compress + local mimetype = specification.mimetype or specification.mime if filename == "" then filename = nil end @@ -317,7 +318,6 @@ function codeinjections.embedfile(specification) filetype = name and (filename and file.suffix(filename)) or "txt" end savename = file.addsuffix(savename,filetype) -- type is mandate for proper working in viewer - local mimetype = specification.mimetype local a = pdfdictionary { Type = pdfconstant("EmbeddedFile"), Subtype = mimetype and mimetype ~= "" and pdfconstant(mimetype) or nil, @@ -327,17 +327,24 @@ function codeinjections.embedfile(specification) f = pdfflushstreamobject(data,a) specification.data = true -- signal that still data but already flushed else - local foundname = specification.foundname or filename + local foundname = specification.foundname or filename + local attributes = lfs.attributes(foundname) + if attributes then + a.Params = { + Size = attributes.size, + ModDate = lpdf.pdftimestamp(attributes.modification), + } + end f = pdfflushstreamfileobject(foundname,a,compress) end local d = pdfdictionary { - Type = pdfconstant("Filespec"), - F = pdfstring(savename), - -- UF = pdfstring(savename), - UF = pdfunicode(savename), - EF = pdfdictionary { F = pdfreference(f) }, - Desc = title ~= "" and pdfunicode(title) or nil, - -- AFRelationship = pdfconstant("Source"), -- some day maybe, not mandate + Type = pdfconstant("Filespec"), + F = pdfstring(savename), + -- UF = pdfstring(savename), + UF = pdfunicode(savename), + EF = pdfdictionary { F = pdfreference(f) }, + Desc = title ~= "" and pdfunicode(title) or nil, + AFRelationship = pdfconstant("Unspecified"), -- Supplement, Data, Source, Alternative, Data } local r = pdfreference(pdfflushobject(d)) filestreams[hash] = r diff --git a/tex/context/base/mkiv/luat-bas.mkiv b/tex/context/base/mkiv/luat-bas.mkiv index b972fc180..0add4ce69 100644 --- a/tex/context/base/mkiv/luat-bas.mkiv +++ b/tex/context/base/mkiv/luat-bas.mkiv @@ -13,6 +13,7 @@ \writestatus{loading}{ConTeXt Lua Macros / Basic Lua Libraries} +\registerctxluafile{l-bit32} {} % before sandbox \registerctxluafile{l-lua} {} % before sandbox \registerctxluafile{l-macro} {} \registerctxluafile{l-sandbox} {} diff --git a/tex/context/base/mkiv/luat-cnf.lua b/tex/context/base/mkiv/luat-cnf.lua index b6ee15083..5e3f026e9 100644 --- a/tex/context/base/mkiv/luat-cnf.lua +++ b/tex/context/base/mkiv/luat-cnf.lua @@ -30,6 +30,8 @@ texconfig.nest_size = 1000 texconfig.param_size = 25000 texconfig.save_size = 100000 texconfig.stack_size = 10000 +texconfig.function_size = 32768 +texconfig.properties_size = 65536 local stub = [[ @@ -154,6 +156,8 @@ function texconfig.init() end +CONTEXTLMTXMODE = %s + -- we provide a qualified path callback.register('find_format_file',function(name) @@ -176,6 +180,8 @@ local variablenames = { param_size = true, save_size = true, stack_size = true, + function_size = true, + properties_size = true, } local function makestub() @@ -212,7 +218,7 @@ local function makestub() t[#t+1] = format("texconfig.%s=%s",v,tv) end end - io.savedata(name,format("%s\n\n%s",concat(t,"\n"),format(stub,firsttable))) + io.savedata(name,format("%s\n\n%s",concat(t,"\n"),format(stub,firsttable,tostring(CONTEXTLMTXMODE) or 0))) logs.newline() end diff --git a/tex/context/base/mkiv/luat-cod.lua b/tex/context/base/mkiv/luat-cod.lua index 849530f72..c667f3ecc 100644 --- a/tex/context/base/mkiv/luat-cod.lua +++ b/tex/context/base/mkiv/luat-cod.lua @@ -30,6 +30,8 @@ texconfig.nest_size = 1000 texconfig.param_size = 25000 texconfig.save_size = 100000 texconfig.stack_size = 10000 +texconfig.function_size = 32768 +texconfig.properties_size = 65536 -- registering bytecode chunks @@ -142,7 +144,15 @@ if LUATEXVERION == nil then end if CONTEXTLMTXMODE == nil then - CONTEXTLMTXMODE = status.obj_ptr == nil and true or false + if status.obj_ptr == nil then + CONTEXTLMTXMODE = 2 + else + CONTEXTLMTXMODE = 0 + for i=1,#arg do if arg[i] == "--c:lmtx" then + CONTEXTLMTXMODE, pdf, img = 1, nil, nil + break + end end + end end if LUATEXFUNCTIONALITY == nil then diff --git a/tex/context/base/mkiv/luat-fmt.lua b/tex/context/base/mkiv/luat-fmt.lua index 2abc47094..586c5948e 100644 --- a/tex/context/base/mkiv/luat-fmt.lua +++ b/tex/context/base/mkiv/luat-fmt.lua @@ -19,9 +19,9 @@ local function primaryflags() if arguments.silent then flags[#flags+1] = "--interaction=batchmode" end - if arguments.jit then - flags[#flags+1] = "--jiton" - end + -- if arguments.jit then + -- flags[#flags+1] = "--jiton" + -- end return concat(flags," ") end @@ -51,6 +51,9 @@ local function secondaryflags() if arguments.strip then flags[#flags+1] = "--c:strip" end + if arguments.lmtx then + flags[#flags+1] = "--c:lmtx" + end return concat(flags," ") end @@ -76,6 +79,13 @@ local runners = { checkers = checkers, reporter = report_format, }, + luametatex = sandbox.registerrunner { + name = "make luametatex format", + program = "luametatex", + template = template, + checkers = checkers, + reporter = report_format, + }, luajittex = sandbox.registerrunner { name = "make luajittex format", program = "luajittex", diff --git a/tex/context/base/mkiv/luat-ini.lua b/tex/context/base/mkiv/luat-ini.lua index 87883b55d..ffd402c77 100644 --- a/tex/context/base/mkiv/luat-ini.lua +++ b/tex/context/base/mkiv/luat-ini.lua @@ -37,7 +37,7 @@ JITSUPPORTED = LUATEXENGINE == "luajittex" or jit INITEXMODE = status.ini_version -CONTEXTLMTXMODE = status.obj_ptr == nil and true or false +CONTEXTLMTXMODE = CONTEXTLMTXMODE or (status.obj_ptr == nil and 2 or 1) function os.setlocale() -- no need for a message diff --git a/tex/context/base/mkiv/luat-lib.mkiv b/tex/context/base/mkiv/luat-lib.mkiv index d5f6099ca..666032369 100644 --- a/tex/context/base/mkiv/luat-lib.mkiv +++ b/tex/context/base/mkiv/luat-lib.mkiv @@ -54,6 +54,10 @@ %registerctxluafile{util-soc-imp-ftp} {} %registerctxluafile{util-soc-imp-smtp} {} +\ifcase\contextlmtxmode\else + \registerctxluafile{util-zip}{} +\fi + \registerctxluafile{data-ini}{} \registerctxluafile{data-exp}{} \registerctxluafile{data-env}{} diff --git a/tex/context/base/mkiv/luat-run.lua b/tex/context/base/mkiv/luat-run.lua index 39384b7b1..ed4d5f5e7 100644 --- a/tex/context/base/mkiv/luat-run.lua +++ b/tex/context/base/mkiv/luat-run.lua @@ -9,6 +9,7 @@ if not modules then modules = { } end modules ['luat-run'] = { local next = next local format, find = string.format, string.find local insert, remove = table.insert, table.remove +local osexit = os.exit -- trace_job_status is also controlled by statistics.enable that is set via the directive system.nostatistics @@ -64,8 +65,9 @@ local function stop_run() end end if quit then - if status.setexitcode then - status.setexitcode(1) + local setexitcode = lua.setexitcode or status.setexitcode + if setexitcode then + setexitcode(1) if type(quit) == "table" then logs.newline() report_tex("quitting due to: %, t",quit) @@ -117,14 +119,18 @@ end -- For Taco ... -local sequencers = utilities.sequencers -local appendgroup = sequencers.appendgroup -local appendaction = sequencers.appendaction -local wrapupactions = sequencers.new { } +local sequencers = utilities.sequencers +local appendgroup = sequencers.appendgroup +local appendaction = sequencers.appendaction +local wrapupactions = sequencers.new { } +local cleanupactions = sequencers.new { } appendgroup(wrapupactions,"system") appendgroup(wrapupactions,"user") +appendgroup(cleanupactions,"system") +appendgroup(cleanupactions,"user") + local function wrapup_run() local runner = wrapupactions.runner if runner then @@ -132,10 +138,26 @@ local function wrapup_run() end end +local function cleanup_run() + local runner = cleanupactions.runner + if runner then + runner() + end +end + function luatex.wrapup(action) appendaction(wrapupactions,"user",action) end +function luatex.cleanup(action) + appendaction(cleanupactions,"user",action) +end + +function luatex.abort() + cleanup_run() + osexit(1) +end + appendaction(wrapupactions,"system",synctex.wrapup) -- this can be done later @@ -243,7 +265,7 @@ local function report_stop() end end -if not CONTEXTLMTXMODE then +if CONTEXTLMTXMODE < 2 then local types = { "data", diff --git a/tex/context/base/mkiv/lxml-aux.lua b/tex/context/base/mkiv/lxml-aux.lua index 78cf1d6bd..ed0f03fd8 100644 --- a/tex/context/base/mkiv/lxml-aux.lua +++ b/tex/context/base/mkiv/lxml-aux.lua @@ -134,10 +134,12 @@ end function xml.collect_tags(root, pattern, nonamespace) local collected = xmlapplylpath(root,pattern) if collected then - local t, n = { }, 0 + local t = { } + local n = 0 for c=1,#collected do - local e = collected[c] - local ns, tg = e.ns, e.tg + local e = collected[c] + local ns = e.ns + local tg = e.tg n = n + 1 if nonamespace then t[n] = tg @@ -226,7 +228,7 @@ function xml.delete(root,pattern) if trace_manipulations then report('deleting',pattern,c,e) end - local d = p.dt + local d = p.dt local ni = e.ni if ni <= #d then if false then @@ -313,8 +315,10 @@ local function inject_element(root,pattern,whatever,prepend) local element = root and xmltoelement(whatever,root) local collected = element and xmlapplylpath(root,pattern) local function inject_e(e) - local r = e.__p__ - local d, k, rri = r.dt, e.ni, r.ri + local r = e.__p__ + local d = r.dt + local k = e.ni + local rri = r.ri local edt = (rri and d[rri].dt) or (d and d[k] and d[k].dt) if edt then local be, af @@ -354,7 +358,8 @@ local function insert_element(root,pattern,whatever,before) -- todo: element als local collected = element and xmlapplylpath(root,pattern) local function insert_e(e) local r = e.__p__ - local d, k = r.dt, e.ni + local d = r.dt + local k = e.ni if not before then k = k + 1 end @@ -860,8 +865,10 @@ function xml.separate(x,pattern) report_xml("warning: xml.separate changes root") x = d end - local t, n = { "\n" }, 1 - local i, nd = 1, #d + local t = { "\n" } + local n = 1 + local i = 1 + local nd = #d while i <= nd do while i <= nd do local di = d[i] diff --git a/tex/context/base/mkiv/lxml-inf.lua b/tex/context/base/mkiv/lxml-inf.lua index 8d99d6270..6fb64c0fe 100644 --- a/tex/context/base/mkiv/lxml-inf.lua +++ b/tex/context/base/mkiv/lxml-inf.lua @@ -17,7 +17,8 @@ local getid = lxml.getid local status, stack local function get(e,d) - local ns, tg = e.ns, e.tg + local ns = e.ns + local tg = e.tg local name = tg if ns ~= "" then name = ns .. ":" .. tg end stack[d] = name diff --git a/tex/context/base/mkiv/lxml-lpt.lua b/tex/context/base/mkiv/lxml-lpt.lua index a80a33f42..392c1a401 100644 --- a/tex/context/base/mkiv/lxml-lpt.lua +++ b/tex/context/base/mkiv/lxml-lpt.lua @@ -166,7 +166,8 @@ apply_axis['self'] = function(list) end apply_axis['child'] = function(list) - local collected, c = { }, 0 + local collected = { } + local c = 0 for l=1,#list do local ll = list[l] local dt = ll.dt @@ -240,7 +241,8 @@ local function collect(list,collected,c) end apply_axis['descendant'] = function(list) - local collected, c = { }, 0 + local collected = { } + local c = 0 for l=1,#list do c = collect(list[l],collected,c) end @@ -283,7 +285,8 @@ local function collect(list,collected,c) end apply_axis['descendant-or-self'] = function(list) - local collected, c = { }, 0 + local collected = { } + local c = 0 for l=1,#list do local ll = list[l] if ll.special ~= true then -- catch double root @@ -296,7 +299,8 @@ apply_axis['descendant-or-self'] = function(list) end apply_axis['ancestor'] = function(list) - local collected, c = { }, 0 + local collected = { } + local c = 0 for l=1,#list do local ll = list[l] while ll do @@ -311,7 +315,8 @@ apply_axis['ancestor'] = function(list) end apply_axis['ancestor-or-self'] = function(list) - local collected, c = { }, 0 + local collected = { } + local c = 0 for l=1,#list do local ll = list[l] c = c + 1 @@ -328,7 +333,8 @@ apply_axis['ancestor-or-self'] = function(list) end apply_axis['parent'] = function(list) - local collected, c = { }, 0 + local collected = { } + local c = 0 for l=1,#list do local pl = list[l].__p__ if pl then @@ -367,7 +373,8 @@ apply_axis['following'] = function(list) -- incomplete end apply_axis['preceding'] = function(list) -- incomplete - -- local collected, c = { }, 0 + -- local collected = { } + -- local c = 0 -- for l=1,#list do -- local ll = list[l] -- local p = ll.__p__ @@ -386,7 +393,8 @@ apply_axis['preceding'] = function(list) -- incomplete end apply_axis['following-sibling'] = function(list) - local collected, c = { }, 0 + local collected = { } + local c = 0 for l=1,#list do local ll = list[l] local p = ll.__p__ @@ -403,7 +411,8 @@ apply_axis['following-sibling'] = function(list) end apply_axis['preceding-sibling'] = function(list) - local collected, c = { }, 0 + local collected = { } + local c = 0 for l=1,#list do local ll = list[l] local p = ll.__p__ @@ -420,7 +429,8 @@ apply_axis['preceding-sibling'] = function(list) end apply_axis['reverse-sibling'] = function(list) -- reverse preceding - local collected, c = { }, 0 + local collected = { } + local c = 0 for l=1,#list do local ll = list[l] local p = ll.__p__ @@ -447,7 +457,8 @@ local function apply_nodes(list,directive,nodes) -- ... currently ignored local maxn = #nodes if maxn == 3 then --optimized loop - local nns, ntg = nodes[2], nodes[3] + local nns = nodes[2] + local ntg = nodes[3] if not nns and not ntg then -- wildcard if directive then return list @@ -455,40 +466,47 @@ local function apply_nodes(list,directive,nodes) return { } end else - local collected, c, m, p = { }, 0, 0, nil + local collected = { } + local c = 0 + local m = 0 + local p = nil if not nns then -- only check tag for l=1,#list do - local ll = list[l] + local ll = list[l] local ltg = ll.tg if ltg then if directive then if ntg == ltg then - local llp = ll.__p__ ; if llp ~= p then p, m = llp, 1 else m = m + 1 end + local llp = ll.__p__ ; if llp ~= p then p = llp ; m = 1 else m = m + 1 end c = c + 1 - collected[c], ll.mi = ll, m + collected[c] = ll + ll.mi = m end elseif ntg ~= ltg then - local llp = ll.__p__ ; if llp ~= p then p, m = llp, 1 else m = m + 1 end + local llp = ll.__p__ ; if llp ~= p then p = llp ; m = 1 else m = m + 1 end c = c + 1 - collected[c], ll.mi = ll, m + collected[c] = ll + ll.mi = m end end end elseif not ntg then -- only check namespace for l=1,#list do - local ll = list[l] + local ll = list[l] local lns = ll.rn or ll.ns if lns then if directive then if lns == nns then - local llp = ll.__p__ ; if llp ~= p then p, m = llp, 1 else m = m + 1 end + local llp = ll.__p__ ; if llp ~= p then p = llp ; m = 1 else m = m + 1 end c = c + 1 - collected[c], ll.mi = ll, m + collected[c] = ll + ll.mi = m end elseif lns ~= nns then - local llp = ll.__p__ ; if llp ~= p then p, m = llp, 1 else m = m + 1 end + local llp = ll.__p__ ; if llp ~= p then p = llp ; m = 1 else m = m + 1 end c = c + 1 - collected[c], ll.mi = ll, m + collected[c] = ll + ll.mi = m end end end @@ -501,14 +519,16 @@ local function apply_nodes(list,directive,nodes) local ok = ltg == ntg and lns == nns if directive then if ok then - local llp = ll.__p__ ; if llp ~= p then p, m = llp, 1 else m = m + 1 end + local llp = ll.__p__ ; if llp ~= p then p = llp ; m = 1 else m = m + 1 end c = c + 1 - collected[c], ll.mi = ll, m + collected[c] = ll + ll.mi = m end elseif not ok then - local llp = ll.__p__ ; if llp ~= p then p, m = llp, 1 else m = m + 1 end + local llp = ll.__p__ ; if llp ~= p then p = llp ; m = 1 else m = m + 1 end c = c + 1 - collected[c], ll.mi = ll, m + collected[c] = ll + ll.mi = m end end end @@ -516,15 +536,19 @@ local function apply_nodes(list,directive,nodes) return collected end else - local collected, c, m, p = { }, 0, 0, nil + local collected = { } + local c = 0 + local m = 0 + local p = nil for l=1,#list do - local ll = list[l] + local ll = list[l] local ltg = ll.tg if ltg then local lns = ll.rn or ll.ns - local ok = false + local ok = false for n=1,maxn,3 do - local nns, ntg = nodes[n+1], nodes[n+2] + local nns = nodes[n+1] + local ntg = nodes[n+2] ok = (not ntg or ltg == ntg) and (not nns or lns == nns) if ok then break @@ -532,14 +556,16 @@ local function apply_nodes(list,directive,nodes) end if directive then if ok then - local llp = ll.__p__ ; if llp ~= p then p, m = llp, 1 else m = m + 1 end + local llp = ll.__p__ ; if llp ~= p then p = llp ; m = 1 else m = m + 1 end c = c + 1 - collected[c], ll.mi = ll, m + collected[c] = ll + ll.mi = m end elseif not ok then - local llp = ll.__p__ ; if llp ~= p then p, m = llp, 1 else m = m + 1 end + local llp = ll.__p__ ; if llp ~= p then p = llp ; m = 1 else m = m + 1 end c = c + 1 - collected[c], ll.mi = ll, m + collected[c] = ll + ll.mi = m end end end @@ -550,7 +576,8 @@ end local quit_expression = false local function apply_expression(list,expression,order) - local collected, c = { }, 0 + local collected = { } + local c = 0 quit_expression = false for l=1,#list do local ll = list[l] @@ -947,7 +974,8 @@ local function tagstostring(list) local t = { } for i=1, #list do local li = list[i] - local ns, tg = li.ns, li.tg + local ns = li.ns + local tg = li.tg if not ns or ns == "" then ns = "*" end if not tg or tg == "" then tg = "*" end t[i] = (tg == "@rt@" and "[root]") or format("%s:%s",ns,tg) @@ -1412,7 +1440,8 @@ expressions.name = function(e,n) -- ns + tg if n == 0 then found = type(e) == "table" and e elseif n < 0 then - local d, k = e.__p__.dt, e.ni + local d = e.__p__.dt + local k = e.ni for i=k-1,1,-1 do local di = d[i] if type(di) == "table" then @@ -1425,7 +1454,8 @@ expressions.name = function(e,n) -- ns + tg end end else - local d, k = e.__p__.dt, e.ni + local d = e.__p__.dt + local k = e.ni for i=k+1,#d,1 do local di = d[i] if type(di) == "table" then @@ -1439,7 +1469,8 @@ expressions.name = function(e,n) -- ns + tg end end if found then - local ns, tg = found.rn or found.ns or "", found.tg + local ns = found.rn or found.ns or "" + local tg = found.tg if ns ~= "" then return ns .. ":" .. tg else @@ -1459,7 +1490,8 @@ expressions.tag = function(e,n) -- only tg if n == 0 then found = (type(e) == "table") and e -- seems to fail elseif n < 0 then - local d, k = e.__p__.dt, e.ni + local d = e.__p__.dt + local k = e.ni for i=k-1,1,-1 do local di = d[i] if type(di) == "table" then @@ -1472,7 +1504,8 @@ expressions.tag = function(e,n) -- only tg end end else - local d, k = e.__p__.dt, e.ni + local d = e.__p__.dt + local k = e.ni for i=k+1,#d,1 do local di = d[i] if type(di) == "table" then diff --git a/tex/context/base/mkiv/math-ali.mkiv b/tex/context/base/mkiv/math-ali.mkiv index ecfac6887..592a3441c 100644 --- a/tex/context/base/mkiv/math-ali.mkiv +++ b/tex/context/base/mkiv/math-ali.mkiv @@ -968,9 +968,14 @@ {\c_math_eqalign_column\zerocount \rawprocesscommacommand[\mathmatrixparameter\c!align]\math_matrix_set_columns_step} +\newcount\c_math_eqalign_column_saved +\newcount\c_math_eqalign_first_saved + \unexpanded\def\math_matrix_start#1% {\begingroup \globalpushmacro\c_math_matrix_first + \c_math_eqalign_column_saved\c_math_eqalign_column + \c_math_eqalign_first_saved \c_math_eqalign_first \edef\currentmathmatrix{#1}% \dosingleempty\math_matrix_start_indeed} @@ -985,6 +990,8 @@ \def\math_matrix_stop {\math_matrix_stop_processing + \global\c_math_eqalign_first\c_math_eqalign_first_saved + \global\c_math_eqalign_column\c_math_eqalign_column_saved \globalpopmacro\c_math_matrix_first \endgroup} diff --git a/tex/context/base/mkiv/math-dim.lua b/tex/context/base/mkiv/math-dim.lua index 72b9d7e50..eb7adb53f 100644 --- a/tex/context/base/mkiv/math-dim.lua +++ b/tex/context/base/mkiv/math-dim.lua @@ -157,7 +157,8 @@ function mathematics.dimensions(dimens) -- beware, dimens get spoiled for variable, styles in next, defaults do local tt = { } for style, default in next, styles do - local one, two = default[1], default[2] + local one = default[1] + local two = default[2] local value = dimens[one] if value then tt[style] = value diff --git a/tex/context/base/mkiv/math-fbk.lua b/tex/context/base/mkiv/math-fbk.lua index 50c977178..963461de5 100644 --- a/tex/context/base/mkiv/math-fbk.lua +++ b/tex/context/base/mkiv/math-fbk.lua @@ -384,7 +384,8 @@ end virtualcharacters[0x203E] = function(data) local target = data.target - local height, depth = 0, 0 + local height = 0 + local depth = 0 -- local mathparameters = target.mathparameters -- if mathparameters then -- height = mathparameters.OverbarVerticalGap diff --git a/tex/context/base/mkiv/math-fen.mkiv b/tex/context/base/mkiv/math-fen.mkiv index 3a32f9fb8..6c6724bf5 100644 --- a/tex/context/base/mkiv/math-fen.mkiv +++ b/tex/context/base/mkiv/math-fen.mkiv @@ -490,31 +490,31 @@ \installmathfencepair \letteropenbrace \Lbrace \letterclosebrace \Rbrace % as we escape in mp textexts -\installmathfencepair . \Lnothing . \Rnothing -\installmathfencepair . \Rnothingmirrored . \Lnothingmirrored +\installmathfencepair . \Lnothing . \Rnothing +\installmathfencepair . \Rnothingmirrored . \Lnothingmirrored -\installmathfencepair [ \Lbracket ] \Rbracket -\installmathfencepair ] \Rbracketmirrored [ \Lbracketmirrored +\installmathfencepair [ \Lbracket ] \Rbracket +\installmathfencepair ] \Rbracketmirrored [ \Lbracketmirrored -\installmathfencepair ( \Lparenthesis ) \Rparenthesis -\installmathfencepair ) \Rparentmirrored ( \Lparentmirrored +\installmathfencepair ( \Lparenthesis ) \Rparenthesis +\installmathfencepair ) \Rparenthesismirrored ( \Lparenthesismirrored -\installmathfencepair < \Langle > \Rangle -\installmathfencepair > \Ranglemirrored < \Langlemirrored +\installmathfencepair < \Langle > \Rangle +\installmathfencepair > \Ranglemirrored < \Langlemirrored -\installmathfencepair / \Lsolidus / \Rsolidus -%installmathfencepair / \Rsolidusmirrored / \Lsolidusmirrored +\installmathfencepair / \Lsolidus / \Rsolidus +%installmathfencepair / \Rsolidusmirrored / \Lsolidusmirrored -\installmathfencepair | \Lbar | \Rbar -%installmathfencepair | \Rbarmirrored | \Lbarmirrored +\installmathfencepair | \Lbar | \Rbar +%installmathfencepair | \Rbarmirrored | \Lbarmirrored -\installmathfencepair ⌊ \Lfloor ⌋ \Rfloor -\installmathfencepair ⌋ \Rfloormirrored ⌊ \Lfloormirrored -\installmathfencepair ⌈ \Lceiling ⌉ \Rceiling -\installmathfencepair ⌉ \Rceilingmirrored ⌈ \Lceilingmirrored +\installmathfencepair ⌊ \Lfloor ⌋ \Rfloor +\installmathfencepair ⌋ \Rfloormirrored ⌊ \Lfloormirrored +\installmathfencepair ⌈ \Lceiling ⌉ \Rceiling +\installmathfencepair ⌉ \Rceilingmirrored ⌈ \Lceilingmirrored -\installmathfencepair ⟨ \Langle ⟩ \Rangle -\installmathfencepair ⟩ \Ranglemirrored ⟨ \Langlemirrored +\installmathfencepair ⟨ \Langle ⟩ \Rangle +\installmathfencepair ⟩ \Ranglemirrored ⟨ \Langlemirrored \installmathfencepair ⟪ \Ldoubleangle ⟫ \Rdoubleangle \installmathfencepair ⟫ \Rdoubleanglemirrored ⟪ \Ldoubleanglemirrored @@ -525,10 +525,10 @@ \installmathfencepair ⦀ \Ltriplebar ⦀ \Rtriplebar %installmathfencepair ⦀ \Rtriplebarmirrored ⦀ \Ltriplebarmirrored -% \installmathfencepair { \Lbrace } \Rbrace -% \installmathfencepair } \Rbracemirrored { \Lbracemirrored +% \installmathfencepair { \Lbrace } \Rbrace +% \installmathfencepair } \Rbracemirrored { \Lbracemirrored -\installmathfencepair ⦗ \Linterv ⦘ \Rinterv +\installmathfencepair ⦗ \Linterval ⦘ \Rinterval \appendtoks \ignorediscretionaries % so $\mtext{a|b}$ works, this is ok because it's an \hbox diff --git a/tex/context/base/mkiv/math-ini.lua b/tex/context/base/mkiv/math-ini.lua index 66c08a76a..7a8419702 100644 --- a/tex/context/base/mkiv/math-ini.lua +++ b/tex/context/base/mkiv/math-ini.lua @@ -289,7 +289,8 @@ function mathematics.define(family) local data = characters.data for unicode, character in sortedhash(data) do local symbol = character.mathsymbol - local mset, dset = true, true + local mset = true + local dset = true if symbol then local other = data[symbol] local class = other.mathclass diff --git a/tex/context/base/mkiv/math-ini.mkiv b/tex/context/base/mkiv/math-ini.mkiv index 50da1a400..3c27bbf07 100644 --- a/tex/context/base/mkiv/math-ini.mkiv +++ b/tex/context/base/mkiv/math-ini.mkiv @@ -268,8 +268,8 @@ \def\math_m_yes_text_openedup#1% {\setbox\scratchbox\hbox\bgroup - \normalstartimath \the\everyswitchmathematics\relax + \normalstartimath #1% \normalstopimath \egroup @@ -285,8 +285,8 @@ \endgroup} \def\math_m_yes_text_normal#1% - {\normalstartimath - \the\everyswitchmathematics\relax + {\the\everyswitchmathematics\relax + \normalstartimath #1% \normalstopimath \endgroup} @@ -436,6 +436,16 @@ % if there were many features we could have a feature pass over math nodes but it makes no % sense now so we have commands to deal with it +% \enabletrackers[math.alternates] +% \setupbodyfont[lucidaot] +% +% \startTEXpage +% \setupmathematics[stylealternative={reset}]$x+\mathcal A$\par +% \setupmathematics[stylealternative={reset,calligraphic}]$x+\mathcal A$\par +% \setupmathematics[stylealternative={reset,italic}]$x+\mathcal A$\par +% \setupmathematics[stylealternative={reset,calligraphic,italic}]$x+\mathcal A$ +% \stopTEXpage + \unexpanded\def\mathaltcalligraphic{\math_set_font_alternate{calligraphic}\cal} % set via goody file \unexpanded\def\mathaltitalic {\math_set_font_alternate{italic}} % set via goody file \unexpanded\def\mathslashedzero {\begingroup\math_set_font_alternate{zero}∅\endgroup} % set via goody file or automatic diff --git a/tex/context/base/mkiv/math-noa.lua b/tex/context/base/mkiv/math-noa.lua index 11baaf413..376767227 100644 --- a/tex/context/base/mkiv/math-noa.lua +++ b/tex/context/base/mkiv/math-noa.lua @@ -778,7 +778,8 @@ do if subtype == leftfence_code or subtype == rightfence_code then local a = getattr(pointer,a_mathsize) if a and a > 0 then - local method, size = div(a,100), a % 100 + local method = div(a,100) + local size = a % 100 setattr(pointer,a_mathsize,0) local delimiter = getfield(pointer,"delim") local chr = getchar(delimiter) @@ -1335,7 +1336,7 @@ do local resets = mathalternates.resets attribute = presets[tag] if not attribute then - attribute = 0 + attribute = 0 local alternates = mathalternates.alternates for s in gmatch(tag,"[^, ]+") do if s == v_reset then @@ -1409,13 +1410,15 @@ do alt = otf.getalternate(fontdata[fontid],char,what.feature,what.value) or false if alt == char then alt = false - elseif trace_alternates then - report_alternates("alternate %a, value %a, replacing glyph %U by glyph %U", - tostring(what.feature),tostring(what.value),getchar(pointer),alt) end hashes[i][char] = alt end if alt then + if trace_alternates then + local what = attributes[r] + report_alternates("alternate %a, value %a, replacing glyph %U by glyph %U", + tostring(what.feature),tostring(what.value),getchar(pointer),alt) + end setchar(pointer,alt) break end diff --git a/tex/context/base/mkiv/math-vfu.lua b/tex/context/base/mkiv/math-vfu.lua index f19e9d61b..ed6f69f41 100644 --- a/tex/context/base/mkiv/math-vfu.lua +++ b/tex/context/base/mkiv/math-vfu.lua @@ -405,23 +405,32 @@ local function jointhree(main,characters,id,size,unicode,u1,d12,u2,d23,u3) end local function stack(main,characters,id,size,unicode,u1,d12,u2) - local c1, c2 = characters[u1], characters[u2] - if c1 and c2 then - local w1, h1, d1 = c1.width, c1.height, c1.depth - local w2, h2, d2 = c2.width, c2.height, c2.depth - local mu = size/18 - characters[unicode] = { - width = w1, - height = h1 + h2 + d12, - depth = d1, - commands = { - { "slot", id, u1 }, - leftcommand[w1/2 + w2/2], - downcommand[-h1 + d2 -d12*mu], - { "slot", id, u2 }, - } - } + local c1 = characters[u1] + if not c1 then + return end + local c2 = characters[u2] + if not c2 then + return + end + local w1 = c1.width or 0 + local h1 = c1.height or 0 + local d1 = c1.depth or 0 + local w2 = c2.width or 0 + local h2 = c2.height or 0 + local d2 = c2.depth or 0 + local mu = size/18 + characters[unicode] = { + width = w1, + height = h1 + h2 + d12, + depth = d1, + commands = { + { "slot", id, u1 }, + leftcommand[w1/2 + w2/2], + downcommand[-h1 + d2 -d12*mu], + { "slot", id, u2 }, + } + } end local function repeated(main,characters,id,size,unicode,u,n,private,fraction) -- math-fbk.lua @@ -429,8 +438,8 @@ local function repeated(main,characters,id,size,unicode,u,n,private,fraction) -- if c then local width = c.width local italic = fraction*width -- c.italic or 0 -- larger ones have funny italics - local tc = { "slot", id, u } - local tr = leftcommand[italic] -- see hack elsewhere + local tc = { "slot", id, u } + local tr = leftcommand[italic] -- see hack elsewhere local commands = { } for i=1,n-1 do commands[#commands+1] = tc @@ -610,7 +619,8 @@ setmetatableindex(reverse, function(t,name) if trace_virtual then report_virtual("initializing math vector %a",name) end - local m, r = mathencodings[name], { } + local m = mathencodings[name] + local r = { } for u, i in next, m do r[i] = u end @@ -700,13 +710,17 @@ end vfmath.copy_glyph = copy_glyph function vfmath.define(specification,set,goodies) - local name = specification.name -- symbolic name - local size = specification.size -- given size - local loaded, fontlist, names, main = { }, { }, { }, nil - local start = (trace_virtual or trace_timings) and os.clock() - local okset, n = { }, 0 + local name = specification.name -- symbolic name + local size = specification.size -- given size + local loaded = { } + local fontlist = { } + local names = { } + local main = nil + local start = (trace_virtual or trace_timings) and os.clock() + local okset = { } + local n = 0 for s=1,#set do - local ss = set[s] + local ss = set[s] local ssname = ss.name if add_optional and ss.optional then if trace_virtual then @@ -850,11 +864,11 @@ function vfmath.define(specification,set,goodies) elseif add_optional and ss.optional then -- skip, redundant else - local newparameters = fs.parameters + local newparameters = fs.parameters local newmathparameters = fs.mathparameters if newmathparameters then if not parameters_done or ss.parameters then - mathparameters = newmathparameters + mathparameters = newmathparameters parameters_done = true end elseif not newparameters then @@ -889,7 +903,7 @@ function vfmath.define(specification,set,goodies) -- report_virtual("loading and virtualizing font %a at size %p, setting sy parameters",name,size) end if ss.overlay then - local fc = fs.characters + local fc = fs.characters local first = ss.first if first then local last = ss.last or first @@ -904,12 +918,14 @@ function vfmath.define(specification,set,goodies) else local vectorname = ss.vector if vectorname then - local offset = 0xFF000 - local vector = mathencodings[vectorname] - local rotcev = reverse[vectorname] + local offset = 0xFF000 + local vector = mathencodings[vectorname] + local rotcev = reverse[vectorname] local isextension = ss.extension if vector and rotcev then - local fc, fd, si = fs.characters, fs.descriptions, shared[s] + local fc = fs.characters + local fd = fs.descriptions + local si = shared[s] local skewchar = ss.skewchar for unicode, index in next, vector do local fci = fc[index] @@ -935,8 +951,8 @@ function vfmath.define(specification,set,goodies) ref = { { 'slot', s, index } } si[index] = ref end - local kerns = fci.kerns - local width = fci.width + local kerns = fci.kerns + local width = fci.width local italic = fci.italic if italic and italic > 0 then -- int_a^b diff --git a/tex/context/base/mkiv/meta-fnt.lua b/tex/context/base/mkiv/meta-fnt.lua index d2d642902..69212d08c 100644 --- a/tex/context/base/mkiv/meta-fnt.lua +++ b/tex/context/base/mkiv/meta-fnt.lua @@ -189,9 +189,9 @@ statistics.register("metapost font generation", function() if total > 0 then local time = statistics.elapsedtime(flusher) if total > 0 then - return format("%i glyphs, %.3f seconds runtime, %.1f glyphs/second", total, time, total/time) + return format("%i glyphs, %s seconds runtime, %.1f glyphs/second", total, time, total/tonumber(time)) else - return format("%i glyphs, %.3f seconds runtime", total, time) + return format("%i glyphs, %s seconds runtime", total, time) end end end) @@ -200,9 +200,9 @@ statistics.register("metapost font loading",function() if variants > 0 then local time = statistics.elapsedtime(metapost.fonts) if variants > 0 then - return format("%.3f seconds, %i instances, %.3f instances/second", time, variants, variants/time) + return format("%s seconds, %i instances, %.3f instances/second", time, variants, variants/tonumber(time)) else - return format("%.3f seconds, %i instances", time, variants) + return format("%s seconds, %i instances", time, variants) end end end) diff --git a/tex/context/base/mkiv/meta-pdf.lua b/tex/context/base/mkiv/meta-pdf.lua index a0bf16d90..5bcd161c0 100644 --- a/tex/context/base/mkiv/meta-pdf.lua +++ b/tex/context/base/mkiv/meta-pdf.lua @@ -6,6 +6,9 @@ if not modules then modules = { } end modules ['meta-pdf'] = { license = "see context related readme files" } +-- This module is not used in practice but we keep it around for historic +-- reasons. + -- Finally we used an optimized version. The test code can be found in -- meta-pdh.lua but since we no longer want to overload functione we use -- more locals now. This module keeps changing as it is also a testbed. @@ -96,16 +99,28 @@ local function flushpath(cmd) if #m_stack_path > 0 then local path = { } if m_stack_concat then - local sx, sy = m_stack_concat[1], m_stack_concat[4] - local rx, ry = m_stack_concat[2], m_stack_concat[3] - local tx, ty = m_stack_concat[5], m_stack_concat[6] + local sx = m_stack_concat[1] + local sy = m_stack_concat[4] + local rx = m_stack_concat[2] + local ry = m_stack_concat[3] + local tx = m_stack_concat[5] + local ty = m_stack_concat[6] local d = (sx*sy) - (rx*ry) for k=1,#m_stack_path do - local v = m_stack_path[k] - local px, py = v[1], v[2] ; v[1], v[2] = (sy*(px-tx)-ry*(py-ty))/d, (sx*(py-ty)-rx*(px-tx))/d -- mpconcat(v[1],v[2]) + local v = m_stack_path[k] + local px = v[1] + local py = v[2] + v[1] = (sy*(px-tx)-ry*(py-ty))/d + v[2] = (sx*(py-ty)-rx*(px-tx))/d if #v == 7 then - local px, py = v[3], v[4] ; v[3], v[4] = (sy*(px-tx)-ry*(py-ty))/d, (sx*(py-ty)-rx*(px-tx))/d -- mpconcat(v[3],v[4]) - local px, py = v[5], v[6] ; v[5], v[6] = (sy*(px-tx)-ry*(py-ty))/d, (sx*(py-ty)-rx*(px-tx))/d -- mpconcat(v[5],v[6]) + px = v[3] + py = v[4] + v[3] = (sy*(px-tx)-ry*(py-ty))/d + v[4] = (sx*(py-ty)-rx*(px-tx))/d + px = v[5] + py = v[6] + v[5] = (sy*(px-tx)-ry*(py-ty))/d + v[6] = (sx*(py-ty)-rx*(px-tx))/d end path[k] = concat(v," ") end @@ -158,7 +173,8 @@ function mps.lineto(x,y) end function mps.rlineto(x,y) - local dx, dy = 0, 0 + local dx = 0 + local dy = 0 local topofstack = #m_stack_path if topofstack > 0 then local msp = m_stack_path[topofstack] @@ -235,7 +251,8 @@ function mps.clip() end function mps.textext(font, scale, str) -- old parser - local dx, dy = 0, 0 + local dx = 0 + local dy = 0 if #m_stack_path > 0 then dx, dy = m_stack_path[1][1], m_stack_path[1][2] end @@ -330,9 +347,12 @@ handlers[50] = function() report_mptopdf("skipping special %s",50) end --end of not supported function mps.setrgbcolor(r,g,b) -- extra check - r, g, b = tonumber(r), tonumber(g), tonumber(b) -- needed when we use lpeg + r = tonumber(r) -- needed when we use lpeg + g = tonumber(g) -- needed when we use lpeg + b = tonumber(b) -- needed when we use lpeg if r == 0.0123 and g < 0.1 then - g, b = round(g*10000), round(b*10000) + g = round(g*10000) + b = round(b*10000) local s = specials[b] local h = round(s[#s]) local handler = handlers[h] @@ -342,7 +362,8 @@ function mps.setrgbcolor(r,g,b) -- extra check report_mptopdf("unknown special handler %s (1)",h) end elseif r == 0.123 and g < 0.1 then - g, b = round(g*1000), round(b*1000) + g = round(g*1000) + b = round(b*1000) local s = specials[b] local h = round(s[#s]) local handler = handlers[h] diff --git a/tex/context/base/mkiv/mlib-lua.lua b/tex/context/base/mkiv/mlib-lua.lua index 8074a6a4a..9b567da81 100644 --- a/tex/context/base/mkiv/mlib-lua.lua +++ b/tex/context/base/mkiv/mlib-lua.lua @@ -468,7 +468,6 @@ do runs = runs + 1 local f = cache[code] if not f then - -- f = loadstring(f_code(code)) f = loadstring(code .. " return mp._f_()") if f then cache[code] = f @@ -480,8 +479,10 @@ do end end if f then - local _buffer_, _n_ = buffer, n - buffer, n = { }, 0 + local _buffer_ = buffer + local _n_ = n + buffer = { } + n = 0 local result = f() if result then local t = type(result) @@ -493,17 +494,16 @@ do if trace then if #result == 0 then report_luarun("%i: no result",nesting) --- print(debug.traceback()) else report_luarun("%i: result: %s",nesting,result) end end - buffer, n = _buffer_, _n_ + buffer = _buffer_ + n = _n_ nesting = nesting - 1 return result elseif trace then report_luarun("%i: no result",nesting) --- print(debug.traceback()) end buffer, n = _buffer_, _n_ else @@ -1027,3 +1027,22 @@ do mp.mf_path_reset = mf_path_reset mp.pathreset = mf_path_reset end + +do + + -- if needed we can optimize the sub (cache last split) + + local utflen, utfsub = utf.len, utf.sub + + local mpnumeric = aux.numeric + local mpquoted = aux.quoted + + function mp.utflen(s) + mpnumeric(utflen(s)) + end + + function mp.utfsub(s,f,t) + mpquoted(utfsub(s,f,t or f)) + end + +end diff --git a/tex/context/base/mkiv/mlib-pdf.lua b/tex/context/base/mkiv/mlib-pdf.lua index b90821508..92fde5e13 100644 --- a/tex/context/base/mkiv/mlib-pdf.lua +++ b/tex/context/base/mkiv/mlib-pdf.lua @@ -380,27 +380,30 @@ function metapost.flush(specification,result) local figures = result.fig if figures then flusher = flusher or pdfflusher - local resetplugins = metapost.resetplugins or ignore -- before figure - local processplugins = metapost.processplugins or ignore -- each object + local resetplugins = metapost.resetplugins or ignore -- before figure + local processplugins = metapost.processplugins or ignore -- each object local synchronizeplugins = metapost.synchronizeplugins or ignore - local pluginactions = metapost.pluginactions or ignore -- before / after - local startfigure = flusher.startfigure - local stopfigure = flusher.stopfigure - local flushfigure = flusher.flushfigure - local textfigure = flusher.textfigure - local processspecial = flusher.processspecial or metapost.processspecial - metapost.comment = flusher.comment or nocomment + local pluginactions = metapost.pluginactions or ignore -- before / after + local startfigure = flusher.startfigure + local stopfigure = flusher.stopfigure + local flushfigure = flusher.flushfigure + local textfigure = flusher.textfigure + local processspecial = flusher.processspecial or metapost.processspecial + metapost.comment = flusher.comment or nocomment for index=1,#figures do - local figure = figures[index] + local figure = figures[index] local properties = pushproperties(figure) if askedfig == "direct" or askedfig == "all" or askedfig == properties.number then - local objects = getobjects(result,figure,index) - local result = { } - local miterlimit, linecap, linejoin, dashed = -1, -1, -1, false - local llx = properties.llx - local lly = properties.lly - local urx = properties.urx - local ury = properties.ury + local objects = getobjects(result,figure,index) + local result = { } + local miterlimit = -1 + local linecap = -1 + local linejoin = -1 + local dashed = false + local llx = properties.llx + local lly = properties.lly + local urx = properties.urx + local ury = properties.ury if urx < llx then -- invalid startfigure(properties.number,0,0,0,0,"invalid",figure) @@ -451,8 +454,11 @@ function metapost.flush(specification,result) setmetatable(object, { __index = original }) - local before, after = processplugins(object) - local evenodd, collect, both = false, false, false + local before, + after = processplugins(object) + local evenodd = false + local collect = false + local both = false local postscript = object.postscript if not object.istext then if postscript == "evenodd" then @@ -513,10 +519,11 @@ function metapost.flush(specification,result) dashed = false end end - local path = object.path -- newpath - local transformed, penwidth = false, 1 - local open = path and path[1].left_type and path[#path].right_type -- at this moment only "end_point" - local pen = object.pen + local path = object.path -- newpath + local transformed = false + local penwidth = 1 + local open = path and path[1].left_type and path[#path].right_type -- at this moment only "end_point" + local pen = object.pen if pen then if pen.type == "elliptical" then transformed, penwidth = pen_characteristics(original) -- boolean, value diff --git a/tex/context/base/mkiv/mlib-pps.lua b/tex/context/base/mkiv/mlib-pps.lua index 5ee375982..5708577fe 100644 --- a/tex/context/base/mkiv/mlib-pps.lua +++ b/tex/context/base/mkiv/mlib-pps.lua @@ -202,7 +202,8 @@ local function checkandconvert(ca,cb,model) ca = { cmyktorgb(ca[1],ca[2],ca[3],ca[4]) } cb = { cmyktorgb(cb[1],cb[2],cb[3],cb[4]) } elseif #ca == 1 then - local a, b = 1-ca[1], 1-cb[1] + local a = 1 - ca[1] + local b = 1 - cb[1] ca = { a, a, a } cb = { b, b, b } end @@ -334,14 +335,19 @@ function models.all(cr) local s = cr[1] return checked_color_pair(f_gray,s,s) elseif n == 3 then - local r, g, b = cr[1], cr[2], cr[3] + local r = cr[1] + local g = cr[2] + local b = cr[3] if r == g and g == b then return checked_color_pair(f_gray,r,r) else return checked_color_pair(f_rgb,r,g,b,r,g,b) end else - local c, m, y, k = cr[1], cr[2], cr[3], cr[4] + local c = cr[1] + local m = cr[2] + local y = cr[3] + local k = cr[4] if c == m and m == y and y == 0 then k = 1 - k return checked_color_pair(f_gray,k,k) @@ -353,10 +359,15 @@ function models.all(cr) local s = cr[1] return checked_color_pair(f_gray,s,s) elseif n == 3 then - local r, g, b = cr[1], cr[2], cr[3] + local r = cr[1] + local g = cr[2] + local b = cr[3] return checked_color_pair(f_rgb,r,g,b,r,g,b) else - local c, m, y, k = cr[1], cr[2], cr[3], cr[4] + local c = cr[1] + local m = cr[2] + local y = cr[3] + local k = cr[4] return checked_color_pair(f_cmyk,c,m,y,k,c,m,y,k) end end @@ -370,14 +381,19 @@ function models.rgb(cr) local s = cr[1] checked_color_pair(f_gray,s,s) elseif n == 3 then - local r, g, b = cr[1], cr[2], cr[3] + local r = cr[1] + local g = cr[2] + local b = cr[3] if r == g and g == b then return checked_color_pair(f_gray,r,r) else return checked_color_pair(f_rgb,r,g,b,r,g,b) end else - local c, m, y, k = cr[1], cr[2], cr[3], cr[4] + local c = cr[1] + local m = cr[2] + local y = cr[3] + local k = cr[4] if c == m and m == y and y == 0 then k = 1 - k return checked_color_pair(f_gray,k,k) @@ -390,11 +406,12 @@ function models.rgb(cr) local s = cr[1] return checked_color_pair(f_gray,s,s) else + local r = cr[1] + local g = cr[2] + local b = cr[3] local r, g, b if n == 3 then - r, g, b = cmyktorgb(cr[1],cr[2],cr[3],cr[4]) - else - r, g, b = cr[1], cr[2], cr[3] + r, g, b = cmyktorgb(r,g,b,cr[4]) end return checked_color_pair(f_rgb,r,g,b,r,g,b) end @@ -409,7 +426,9 @@ function models.cmyk(cr) local s = cr[1] return checked_color_pair(f_gray,s,s) elseif n == 3 then - local r, g, b = cr[1], cr[2], cr[3] + local r = cr[1] + local g = cr[2] + local b = cr[3] if r == g and g == b then return checked_color_pair(f_gray,r,r) else @@ -417,7 +436,10 @@ function models.cmyk(cr) return checked_color_pair(f_cmyk,c,m,y,k,c,m,y,k) end else - local c, m, y, k = cr[1], cr[2], cr[3], cr[4] + local c = cr[1] + local m = cr[2] + local y = cr[3] + local k = cr[4] if c == m and m == y and y == 0 then k = k - 1 return checked_color_pair(f_gray,k,k) @@ -429,18 +451,20 @@ function models.cmyk(cr) local s = cr[1] return checked_color_pair(f_gray,s,s) else - local c, m, y, k + local c = cr[1] + local m = cr[2] + local y = cr[3] + local k = cr[4] if n == 3 then - c, m, y, k = rgbtocmyk(cr[1],cr[2],cr[3]) - else - c, m, y, k = cr[1], cr[2], cr[3], cr[4] + c, m, y, k = rgbtocmyk(c,m,y) end return checked_color_pair(f_cmyk,c,m,y,k,c,m,y,k) end end function models.gray(cr) - local n, s = #cr, 0 + local n = #cr + local s = 0 if n == 0 then return checked_color_pair() elseif n == 4 then @@ -714,11 +738,16 @@ local basepoints = number.dimenfactors["bp"] local function cm(object) local op = object.path if op then - local first, second, fourth = op[1], op[2], op[4] + local first = op[1] + local second = op[2] + local fourth = op[4] if fourth then - local tx, ty = first.x_coord, first.y_coord - local sx, sy = second.x_coord - tx, fourth.y_coord - ty - local rx, ry = second.y_coord - ty, fourth.x_coord - tx + local tx = first.x_coord + local ty = first.y_coord + local sx = second.x_coord - tx + local sy = fourth.y_coord - ty + local rx = second.y_coord - ty + local ry = fourth.x_coord - tx if sx == 0 then sx = 0.00001 end if sy == 0 then sy = 0.00001 end return sx, rx, ry, sy, tx, ty @@ -1166,10 +1195,13 @@ end local function ps_process(object,prescript,before,after) local ps_label = prescript.ps_label if ps_label then - local op = object.path - local first, third = op[1], op[3] - local x, y = first.x_coord, first.y_coord - local w, h = third.x_coord - x, third.y_coord - y + local op = object.path + local first = op[1] + local third = op[3] + local x = first.x_coord + local y = first.y_coord + local w = third.x_coord - x + local h = third.y_coord - y local properties = metapost.properties x = x - properties.llx y = properties.ury - y @@ -1370,7 +1402,10 @@ local function gr_process(object,prescript,before,after) elseif gr_state == "start" then local gr_type = utilities.parsers.settings_to_set(prescript.gr_type) local path = object.path - local p1, p2, p3, p4 = path[1], path[2], path[3], path[4] + local p1 = path[1] + local p2 = path[2] + local p3 = path[3] + local p4 = path[4] local llx = min(p1.x_coord,p2.x_coord,p3.x_coord,p4.x_coord) local lly = min(p1.y_coord,p2.y_coord,p3.y_coord,p4.y_coord) local urx = max(p1.x_coord,p2.x_coord,p3.x_coord,p4.x_coord) diff --git a/tex/context/base/mkiv/mlib-run.lua b/tex/context/base/mkiv/mlib-run.lua index a3a833c4e..3365e3d42 100644 --- a/tex/context/base/mkiv/mlib-run.lua +++ b/tex/context/base/mkiv/mlib-run.lua @@ -131,7 +131,9 @@ function metapost.reporterror(result) if not result then report_metapost("error: no result object returned") elseif result.status > 0 then - local t, e, l = result.term, result.error, result.log + local t = result.term + local e = result.error + local l = result.log local report = metapost.texerrors and texerrormessage or report_metapost if t and t ~= "" then report("mp error: %s",striplines(t)) @@ -201,6 +203,7 @@ function metapost.load(name,method) make_text = metapost.maketext, extensions = 1, -- random_seed = seed, + utf8_mode = true, } report_metapost("initializing number mode %a",method) local result @@ -346,6 +349,13 @@ function metapost.pushformat(specification,f,m) -- was: instance, name, method return mpx end + +-- luatex.wrapup(function() +-- for k, mpx in next, mpxformats do +-- mpx:finish() +-- end +-- end) + function metapost.popformat() nofformats = nofformats - 1 end diff --git a/tex/context/base/mkiv/mtx-context-listing.tex b/tex/context/base/mkiv/mtx-context-listing.tex index 1053e80b9..285113850 100644 --- a/tex/context/base/mkiv/mtx-context-listing.tex +++ b/tex/context/base/mkiv/mtx-context-listing.tex @@ -116,10 +116,10 @@ -- forced end context.page() - context.setupfootertexts( -- return true: we need to keep this entry - { function() context.detokenize(pattern and filename or file.basename(filename)) return true end }, - { function() context.pagenumber() return true end } - ) +-- context.setupfootertexts( -- return true: we need to keep this entry +-- { function() context.detokenize(pattern and filename or file.basename(filename)) return true end }, +-- { function() context.pagenumber() return true end } +-- ) if scite then context.scitefile { filename } -- here { } elseif pretty then diff --git a/tex/context/base/mkiv/mult-fun.lua b/tex/context/base/mkiv/mult-fun.lua index 0776f36b4..71d612156 100644 --- a/tex/context/base/mkiv/mult-fun.lua +++ b/tex/context/base/mkiv/mult-fun.lua @@ -165,6 +165,8 @@ return { -- "inpath", "pointof", "leftof", "rightof", -- + "utflen", "utfsub", + -- "newhash", "disposehash", "inhash", "tohash", -- "isarray", "prefix", "isobject", diff --git a/tex/context/base/mkiv/mult-sys.mkiv b/tex/context/base/mkiv/mult-sys.mkiv index fdb2ea732..bd8fc80ff 100644 --- a/tex/context/base/mkiv/mult-sys.mkiv +++ b/tex/context/base/mkiv/mult-sys.mkiv @@ -239,39 +239,41 @@ \definesystemconstant {xml} \definesystemconstant {lua} -\definesystemconstant {next} -\definesystemconstant {pickup} -\definesystemconstant {forget} -\definesystemconstant {ascii} -\definesystemconstant {default} -\definesystemconstant {unknown} \definesystemconstant {action} +\definesystemconstant {ascii} +\definesystemconstant {chain} +\definesystemconstant {child} +\definesystemconstant {class} +\definesystemconstant {clone} \definesystemconstant {compare} -\definesystemconstant {do} -\definesystemconstant {dodo} \definesystemconstant {complex} -\definesystemconstant {simple} -\definesystemconstant {start} -\definesystemconstant {stop} -\definesystemconstant {dummy} -\definesystemconstant {local} -\definesystemconstant {global} +\definesystemconstant {counter} +\definesystemconstant {current} +\definesystemconstant {default} +\definesystemconstant {dodo} \definesystemconstant {done} +\definesystemconstant {do} +\definesystemconstant {dummy} \definesystemconstant {font} +\definesystemconstant {forget} +\definesystemconstant {global} +\definesystemconstant {handler} +\definesystemconstant {indeed} +\definesystemconstant {internal} \definesystemconstant {link} +\definesystemconstant {local} +\definesystemconstant {multi} +\definesystemconstant {next} \definesystemconstant {parent} -\definesystemconstant {child} -\definesystemconstant {clone} +\definesystemconstant {pickup} +\definesystemconstant {plural} \definesystemconstant {section} -\definesystemconstant {handler} -\definesystemconstant {counter} +\definesystemconstant {simple} \definesystemconstant {single} -\definesystemconstant {multi} -\definesystemconstant {indeed} -\definesystemconstant {internal} -\definesystemconstant {current} -\definesystemconstant {chain} -\definesystemconstant {class} +\definesystemconstant {singular} +\definesystemconstant {start} +\definesystemconstant {stop} +\definesystemconstant {unknown} % translating setups is asking for a mess so we keep them as-is: @@ -454,6 +456,8 @@ \definesystemconstant {left} \definesystemconstant {middle} \definesystemconstant {right} +\definesystemconstant {xoffset} +\definesystemconstant {yoffset} %D As the name of their define command states, the next set of constants is used in %D the message macro's. diff --git a/tex/context/base/mkiv/node-fnt.lua b/tex/context/base/mkiv/node-fnt.lua index 154853121..01d7e42e5 100644 --- a/tex/context/base/mkiv/node-fnt.lua +++ b/tex/context/base/mkiv/node-fnt.lua @@ -437,6 +437,8 @@ do local prevfont = nil local prevattr = nil local none = false + firstnone = nil + basefont = nil for n, char, font in nextchar, r do local attr = getattr(n) or 0 -- zero attribute is reserved for fonts in context if font ~= prevfont or attr ~= prevattr then @@ -446,6 +448,7 @@ do if fontmode == "none" then setnone(n) elseif fontmode == "base" then + -- so the replace gets an extra treatment ... so be it setbase(n) else setnode(n,font,attr) diff --git a/tex/context/base/mkiv/node-ini.lua b/tex/context/base/mkiv/node-ini.lua index 38d75cfb9..f910c7e01 100644 --- a/tex/context/base/mkiv/node-ini.lua +++ b/tex/context/base/mkiv/node-ini.lua @@ -364,7 +364,7 @@ dirvalues = allocate(swapped(dirvalues,dirvalues)) gluevalues = allocate(swapped(gluevalues,gluevalues)) literalvalues = allocate(swapped(literalvalues,literalvalues)) -if CONTEXTLMTXMODE then +if CONTEXTLMTXMODE > 1 then whatcodes.literal = 0x1 whatcodes[0x1] = "literal" whatcodes.latelua = 0x2 whatcodes[0x2] = "latelua" whatcodes.userdefined = 0x3 whatcodes[0x3] = "userdefined" diff --git a/tex/context/base/mkiv/node-met.lua b/tex/context/base/mkiv/node-met.lua index f5db4babd..574c71f60 100644 --- a/tex/context/base/mkiv/node-met.lua +++ b/tex/context/base/mkiv/node-met.lua @@ -136,103 +136,82 @@ nodes.is_zero_glue = node.is_zero_glue nodes.tonode = function(n) return n end nodes.tonut = function(n) return n end -local n_getid = node.getid -local n_getlist = node.getlist -local n_getnext = node.getnext -local n_getprev = node.getprev -local n_getchar = node.getchar -local n_getfont = node.getfont -local n_getsubtype = node.getsubtype -local n_getfield = node.getfield -local n_getattr = node.get_attribute -local n_getdisc = node.getdisc -local n_getleader = node.getleader - -local n_setfield = node.setfield -local n_setattr = n_setfield - -local n_setnext = node.setnext or -- always - function(c,n) - n_setfield(c,"next",n) - end -local n_setprev = node.setprev or -- always - function(c,p) - n_setfield(c,"prev",p) - end -local n_setlist = node.setlist or -- always - function(c,l) - n_setfield(c,"list",l) - end -local n_setlink = node.setlink or -- always - function(...) - -- not that fast but not used often anyway - local h = nil - for i=1,select("#",...) do - local n = select(i,...) - if not n then - -- go on - elseif h then - n_setfield(h,"next",n) - n_setfield(n,"prev",h) - else - h = n - end +-- These are never used in \CONTEXT, only as a gimmick in node operators +-- so we keep them around. + +local n_getfield = node.getfield +local n_getattr = node.get_attribute + +local n_setfield = node.setfield +local n_setattr = n_setfield + +nodes.getfield = n_getfield +nodes.setfield = n_setfield +nodes.getattr = n_getattr +nodes.setattr = n_setattr +nodes.takeattr = nodes.unset_attribute + +local function n_getid (n) return n_getfield(n,"id") end +local function n_getsubtype(n) return n_getfield(n,"subtype") end + +nodes.getid = n_getid +nodes.getsubtype = n_getsubtype + +local function n_getchar(n) return n_getfield(n,"char") end +local function n_setchar(n,c) return n_setfield(n,"char",c) end +local function n_getfont(n) return n_getfield(n,"font") end +local function n_setfont(n,f) return n_setfield(n,"font",f) end + +nodes.getchar = n_getchar +nodes.setchar = n_setchar +nodes.getfont = n_getfont +nodes.setfont = n_setfont + +local function n_getlist (n) return n_getfield(n,"list") end +local function n_setlist (n,l) return n_setfield(n,"list",l) end +local function n_getleader(n) return n_getfield(n,"leader") end +local function n_setleader(n,l) return n_setfield(n,"leader",l) end + +nodes.getlist = n_getlist +nodes.setlist = n_setlist +nodes.getleader = n_getleader +nodes.setleader = n_setleader + +local function n_getnext(n) return n_getfield(n,"next") end +local function n_setnext(n,nn) return n_setfield(n,"next",nn) end +local function n_getprev(n) return n_getfield(n,"prev") end +local function n_setprev(n,pp) return n_setfield(n,"prev",pp) end +local function n_getboth(n) return n_getfield(n,"prev"), n_getfield(n,"next") end +local function n_setboth(n,pp,nn) return n_setfield(n,"prev",pp), n_setfield(n,"next",nn) end + +nodes.getnext = n_getnext +nodes.setnext = n_setnext +nodes.getprev = n_getprev +nodes.setprev = n_setprev +nodes.getboth = n_getboth +nodes.setboth = n_setboth + +local function n_setlink(...) + -- not that fast but not used often anyway + local h = nil + for i=1,select("#",...) do + local n = select(i,...) + if not n then + -- go on + elseif h then + n_setfield(h,"next",n) + n_setfield(n,"prev",h) + else + h = n end - return h - end -local n_setboth = node.setboth or -- always - function(c,p,n) - n_setfield(c,"prev",p) - n_setfield(c,"next",n) - end - -nodes.setnext = n_setnext -nodes.setprev = n_setprev -nodes.setlink = n_setlink -nodes.setboth = n_setboth -nodes.setlist = n_setlist - -nodes.getfield = n_getfield -nodes.setfield = n_setfield -nodes.getattr = n_getattr -nodes.setattr = n_setattr -nodes.takeattr = nodes.unset_attribute - -nodes.getnext = n_getnext -nodes.getprev = n_getprev -nodes.getid = n_getid -nodes.getchar = n_getchar -nodes.getfont = n_getfont -nodes.getsubtype = n_getsubtype -nodes.getlist = n_getlist -nodes.getleader = n_getleader -nodes.getdisc = n_getdisc - -if not node.getwhd then - function node.getwhd(n) - return n_getfield(n,"width"), n_getfield(n,"height"), n_getfield(n,"depth") end + return h end -if not node.setwhd then - function node.setwhd(n,w,h,d) - n_setfield(n,"width",w or 0) - n_setfield(n,"height",h or 0) - n_setfield(n,"depth",d or 0) - end -end - -nodes.getwhd = node.getwhd -nodes.setwhd = node.setwhd - -nodes.is_char = node.is_char -nodes.ischar = node.is_char - -nodes.is_glyph = node.is_glyph -nodes.isglyph = node.is_glyph +nodes.setlink = n_setlink -nodes.getbox = node.getbox or tex.getbox -nodes.setbox = node.setbox or tex.setbox +nodes.getbox = node.getbox or tex.getbox +nodes.setbox = node.setbox or tex.setbox local n_flush_node = nodes.flush local n_copy_node = nodes.copy diff --git a/tex/context/base/mkiv/node-nut.lua b/tex/context/base/mkiv/node-nut.lua index 85220e25b..50e87e988 100644 --- a/tex/context/base/mkiv/node-nut.lua +++ b/tex/context/base/mkiv/node-nut.lua @@ -127,11 +127,11 @@ nodes.tonut = tonut -- function nuts.reportattr() -- inspect(hash) -- end --- + -- local function track(name) -- local n = 0 --- local f = nuts[name] --- function nuts[name](...) +-- local f = direct[name] +-- direct[name] = function(...) -- n = n + 1 -- if n % 1000 == 0 then -- print(name,n) @@ -139,7 +139,6 @@ nodes.tonut = tonut -- return f(...) -- end -- end --- -- track("getfield") -- helpers @@ -698,7 +697,7 @@ nuts.nestedtracedslide = nestedtracedslide -- this might move -local propertydata = direct.get_properties_table and direct.get_properties_table() +local propertydata = direct.get_properties_table(true) local getattr = nuts.getattr local setattr = nuts.setattr diff --git a/tex/context/base/mkiv/node-pro.lua b/tex/context/base/mkiv/node-pro.lua index b6b130588..606d5b8d7 100644 --- a/tex/context/base/mkiv/node-pro.lua +++ b/tex/context/base/mkiv/node-pro.lua @@ -14,6 +14,7 @@ local report_nodes = logs.reporter("nodes","processors") local nodes = nodes local tasks = nodes.tasks local nuts = nodes.nuts +local tonut = nodes.tonut nodes.processors = nodes.processors or { } local processors = nodes.processors @@ -25,7 +26,6 @@ local actions = tasks.actions("processors") do - local tonut = nuts.tonut local isglyph = nuts.isglyph local getnext = nuts.getnext @@ -178,9 +178,9 @@ do local texnest = tex.nest - local getlist = nodes.getlist - local setlist = nodes.setlist - local getsubtype = nodes.getsubtype + local getlist = nuts.getlist + local setlist = nuts.setlist + local getsubtype = nuts.getsubtype local linelist_code = nodes.listcodes.line @@ -191,12 +191,15 @@ do local whatever = texnest[texnest.ptr] if whatever then local line = whatever.tail - if line and getsubtype(line) == linelist_code then - local head = getlist(line) - if head then - local result = actions(head,groupcode,line) - if result and result ~= head then - setlist(line,result) + if line then + line = tonut(line) + if getsubtype(line) == linelist_code then + local head = getlist(line) + if head then + local result = actions(head,groupcode,line) + if result and result ~= head then + setlist(line,result) + end end end end diff --git a/tex/context/base/mkiv/node-ref.lua b/tex/context/base/mkiv/node-ref.lua index 107cadc46..e12bd95bd 100644 --- a/tex/context/base/mkiv/node-ref.lua +++ b/tex/context/base/mkiv/node-ref.lua @@ -755,7 +755,11 @@ local function makereference(width,height,depth,reference) -- height and depth a if trace_references then report_reference("resolving attribute %a",reference) end - local resolved, ht, dp, set, n = sr[1], sr[2], sr[3], sr[4], sr[5] + local resolved = sr[1] + local ht = sr[2] + local dp = sr[3] + local set = sr[4] + local n = sr[5] -- logs.report("temp","child: ht=%p dp=%p, parent: ht=%p dp=%p",ht,dp,height,depth) if ht then if height < ht then height = ht end @@ -844,7 +848,11 @@ local function makedestination(width,height,depth,reference) if trace_destinations then report_destination("resolving attribute %a",reference) end - local resolved, ht, dp, name, view = sr[1], sr[2], sr[3], sr[4], sr[5] -- sr[4] will change to just internal + local resolved = sr[1] + local ht = sr[2] + local dp = sr[3] + local name = sr[4] + local view = sr[5] if ht then if height < ht then height = ht end if depth < dp then depth = dp end diff --git a/tex/context/base/mkiv/node-res.lua b/tex/context/base/mkiv/node-res.lua index da8daa29b..5b4961683 100644 --- a/tex/context/base/mkiv/node-res.lua +++ b/tex/context/base/mkiv/node-res.lua @@ -172,7 +172,7 @@ local savepos = register_nut(new_nut(whatsit_code,whatsitcodes.savepos local user_node = new_nut(whatsit_code,whatsitcodes.userdefined) -if not CONTEXTLMTXMODE then +if CONTEXTLMTXMODE < 2 then setfield(user_node,"type",usercodes.number) end @@ -364,49 +364,37 @@ function nutpool.direction(dir,swap) return t end -function nutpool.rule(width,height,depth,direction) -- w/h/d == nil will let them adapt +function nutpool.rule(width,height,depth) -- w/h/d == nil will let them adapt local n = copy_nut(rule) if width or height or depth then setwhd(n,width,height,depth) end - if direction then - setdirection(n,direction) - end return n end -function nutpool.emptyrule(width,height,depth,direction) -- w/h/d == nil will let them adapt +function nutpool.emptyrule(width,height,depth) -- w/h/d == nil will let them adapt local n = copy_nut(emptyrule) if width or height or depth then setwhd(n,width,height,depth) end - if direction then - setdirection(n,direction) - end return n end -function nutpool.userrule(width,height,depth,direction) -- w/h/d == nil will let them adapt +function nutpool.userrule(width,height,depth) -- w/h/d == nil will let them adapt local n = copy_nut(userrule) if width or height or depth then setwhd(n,width,height,depth) end - if direction then - setdirection(n,direction) - end return n end -function nutpool.outlinerule(width,height,depth,line,direction) -- w/h/d == nil will let them adapt +function nutpool.outlinerule(width,height,depth,line) -- w/h/d == nil will let them adapt local n = copy_nut(outlinerule) if width or height or depth then setwhd(n,width,height,depth) end if line then - setfield(n,"transform",line) - end - if direction then - setdirection(n,direction) + if CONTEXTLMTXMODE > 1 then setdata(n,line) else setfield(n,"transform",line) end end return n end @@ -426,7 +414,7 @@ function nutpool.savepos() return copy_nut(savepos) end -if CONTEXTLMTXMODE then +if CONTEXTLMTXMODE > 1 then function nutpool.latelua(code) local n = copy_nut(latelua) @@ -438,14 +426,17 @@ else function nutpool.latelua(code) local n = copy_nut(latelua) + if type(code) == "table" then + local action = code.action + local specification = code.specification or code + code = function() action(specification) end + end setdata(n,code) return n end end -nutpool.lateluafunction = nutpool.latelua - function nutpool.leftmarginkern(glyph,width) local n = copy_nut(left_margin_kern) if not glyph then @@ -573,7 +564,7 @@ end local function usage() local t = { } for n, tag in gmatch(status.node_mem_usage,"(%d+) ([a-z_]+)") do - t[tag] = n + t[tag] = tonumber(n) or 0 end return t end diff --git a/tex/context/base/mkiv/node-rul.lua b/tex/context/base/mkiv/node-rul.lua index ea0e5c7a0..1df5bf32a 100644 --- a/tex/context/base/mkiv/node-rul.lua +++ b/tex/context/base/mkiv/node-rul.lua @@ -48,7 +48,9 @@ local setattrlist = nuts.setattrlist local setshift = nuts.setshift local getwidth = nuts.getwidth local setwidth = nuts.setwidth +local setoffsets = nuts.setoffsets local setfield = nuts.setfield +local getdata = nuts.getdata local isglyph = nuts.isglyph @@ -163,28 +165,23 @@ local ruleactions = { } rules .ruleactions = ruleactions nutrules.ruleactions = ruleactions -- convenient -local function mathradical(n,h,v) - ----- size = getfield(n,"index") - local font = getfield(n,"transform") +local function mathaction(n,h,v,what) + local font = CONTEXTLMTXMODE > 1 and getdata(n) or getfield(n,"transform") local actions = fontresources[font].mathruleactions if actions then - local action = actions.radicalaction + local action = actions[what] if action then action(n,h,v,font) end end end +local function mathradical(n,h,v) + mathaction(n,h,v,"radicalaction") +end + local function mathrule(n,h,v) - ----- size = getfield(n,"index") - local font = getfield(n,"transform") - local actions = fontresources[font].mathruleactions - if actions then - local action = actions.hruleaction - if action then - action(n,h,v,font) - end - end + mathaction(n,h,v,"hruleaction") end local function useraction(n,h,v) @@ -745,7 +742,7 @@ implement { actions = nodes.linefillers.enable } --- We add a bonus feature here: +-- We add a bonus feature here (experiment): interfaces.implement { name = "autorule", @@ -754,19 +751,22 @@ interfaces.implement { { "width", "dimension" }, { "height", "dimension" }, { "depth", "dimension" }, + { "xoffset", "dimension" }, + { "yoffset", "dimension" }, { "left", "dimension" }, { "right", "dimension" }, }, }, actions = function(t) - local l = t.left - local r = t.right local n = new_rule( t.width, t.height, t.depth ) setattrlist(n,true) + setoffsets(n,t.xoffset,t.yoffset) -- ,t.left, t.right + local l = t.left + local r = t.right if l then setfield(n,"left",l) end diff --git a/tex/context/base/mkiv/node-tsk.lua b/tex/context/base/mkiv/node-tsk.lua index 0378c14c6..ca7c7fee4 100644 --- a/tex/context/base/mkiv/node-tsk.lua +++ b/tex/context/base/mkiv/node-tsk.lua @@ -627,12 +627,11 @@ local tonode = nodes.nuts.tonode %localize% -return function(head,groupcode,line) - local nuthead = tonut(head) - local nutline = tonut(line) +-- we operate exclusively on nuts +return function(nuthead,groupcode,nutline) %actions% - return tonode(nuthead) + return nuthead end ]], diff --git a/tex/context/base/mkiv/pack-obj.lua b/tex/context/base/mkiv/pack-obj.lua index 3d2048218..ea36b10de 100644 --- a/tex/context/base/mkiv/pack-obj.lua +++ b/tex/context/base/mkiv/pack-obj.lua @@ -53,8 +53,16 @@ end job.register('job.objects.collected', tobesaved, initializer, nil) local function saveobject(tag,number,page) - local t = { number, page } - tobesaved[tag], collected[tag] = t, t + local data = { number, page } + tobesaved[tag] = data + collected[tag] = data +end + +local function saveobjectspec(specification) + local tag = specification.tag + local data = { specification.number, specification.page } + tobesaved[tag] = data + collected[tag] = data end local function setobject(tag,number,page) @@ -162,9 +170,12 @@ function objects.restore(ns,id) -- why not just pass a box number here too (ok, local hbox = codeinjections.restoreboxresource(index) -- a nut ! if status then local list = getlist(hbox) - local page = new_latelua(function() - saveobject(ns .. "::" .. id,index,getcount("realpageno")) - end) + local page = new_latelua { + action = saveobjectspec, + tag = ns .. "::" .. id, + number = index, + page = getcount("realpageno"), + } setlink(list,page) end setbox("objectbox",hbox) diff --git a/tex/context/base/mkiv/page-ini.mkiv b/tex/context/base/mkiv/page-ini.mkiv index 38477dc27..618ea9006 100644 --- a/tex/context/base/mkiv/page-ini.mkiv +++ b/tex/context/base/mkiv/page-ini.mkiv @@ -344,6 +344,10 @@ {\clf_forcestrutdepth\normalpagebox\strutdp\c_page_force_strut_depth_trace_mode \unvbox\normalpagebox} +\installoutputroutine\forcestrutdepthplus % experimental + {\clf_forcestrutdepthplus\normalpagebox\strutdp\c_page_force_strut_depth_trace_mode + \unvbox\normalpagebox} + % maybe better: % % \installoutputroutine\doforcestrutdepth diff --git a/tex/context/base/mkiv/page-lin.lua b/tex/context/base/mkiv/page-lin.lua index b556ca32b..3689c7f8d 100644 --- a/tex/context/base/mkiv/page-lin.lua +++ b/tex/context/base/mkiv/page-lin.lua @@ -224,7 +224,9 @@ implement { local function check_number(n,a,skip,sameline) local d = data[a] if d then - local tag, skipflag, s = d.tag or "", 0, d.start or 1 + local tag = d.tag or "" + local skipflag = 0 + local s = d.start or 1 current_list[#current_list+1] = { n, s } if sameline then skipflag = 0 @@ -471,14 +473,17 @@ end function boxed.stage_two(n,m) if #current_list > 0 then m = m or lines.scratchbox - local t, tn = { }, 0 + local t = { } + local tn = 0 for l in nexthlist, getlist(getbox(m)) do tn = tn + 1 t[tn] = copy_node(l) -- use take_box instead end for i=1,#current_list do local li = current_list[i] - local n, m, ti = li[1], li[2], t[i] + local n = li[1] + local m = li[2] + local ti = t[i] if ti then -- local d = getdirection(n) -- local l = getlist(n) diff --git a/tex/context/base/mkiv/page-sid.mkiv b/tex/context/base/mkiv/page-sid.mkiv index 803381244..e6c1be985 100644 --- a/tex/context/base/mkiv/page-sid.mkiv +++ b/tex/context/base/mkiv/page-sid.mkiv @@ -84,6 +84,8 @@ \newcount \c_page_sides_m_of_lines \newconditional \c_page_sides_delayed +\newconditional \c_page_sides_check_same_page + \newif \iftracesidefloats % public (might change) %D Defaults: @@ -399,10 +401,18 @@ {\iftracesidefloats \begingroup \c_page_force_strut_depth_trace_mode\plusone - \forcestrutdepth + \ifconditional\c_page_sides_check_same_page + \forcestrutdepthplus + \else + \forcestrutdepth + \fi \endgroup \else - \forcestrutdepth + \ifconditional\c_page_sides_check_same_page + \forcestrutdepthplus + \else + \forcestrutdepth + \fi \fi \page_otr_command_set_vsize} % new @@ -712,7 +722,7 @@ \advance\d_page_sides_progress-\pagetotal \fi} -\def\page_sides_analyse_space +\def\page_sides_analyse_space_stage_one {\global\settrue\c_page_sides_flag % \ifdim\pagegoal=\maxdimen % \pagegoal\textheight % maybe @@ -751,8 +761,10 @@ % \advance\scratchdimenone -\onepoint (maybe) \else \advance\scratchdimentwo -\strutdp - \fi - % how about \pagedepth + \fi} + +\def\page_sides_analyse_space_stage_two + {% how about \pagedepth \ifdim\scratchdimenone>\scratchdimentwo \global\setfalse\c_page_floats_room \else @@ -767,6 +779,22 @@ \global\settrue\c_page_floats_room \fi} +\def\page_sides_analyse_space + {\page_sides_analyse_space_stage_one + \ifconditional\c_page_sides_check_same_page + \ifdim\d_spac_prevcontent>\zeropoint + \ifdim\dimexpr\scratchdimenone+\d_spac_prevcontent>\scratchdimentwo + \clf_pushatsame + \setbox\scratchbox\vpack{\clf_popatsame}% + \page + \box\scratchbox + \vskip-\lineskip + \page_sides_analyse_space_stage_one + \fi + \fi + \fi + \page_sides_analyse_space_stage_two} + %D As we have no clear end of one or more paragraphs we only have pre float %D skips. diff --git a/tex/context/base/mkiv/publ-aut.lua b/tex/context/base/mkiv/publ-aut.lua index fd98c5e38..e74c7ee18 100644 --- a/tex/context/base/mkiv/publ-aut.lua +++ b/tex/context/base/mkiv/publ-aut.lua @@ -159,8 +159,11 @@ local function splitauthor(author,justsplit) if n == 1 then -- {First Middle von Last} local words = lpegmatch(spacesplitter,author) - firstnames, vons, surnames = { }, { }, { } - local i, n = 1, #words + local i = 1 + local n = #words + firstnames = { } + vons = { } + surnames = { } while i <= n do local w = words[i] if is_upper(w) then @@ -198,9 +201,12 @@ local function splitauthor(author,justsplit) elseif n == 2 then -- {Last, First} -- {von Last, First} - firstnames, vons, surnames = { }, { }, { } local words = lpegmatch(spacesplitter,split[1]) - local i, n = 1, #words + local i = 1 + local n = #words + firstnames = { } + vons = { } + surnames = { } while i <= n do local w = words[i] if is_upper(w) then @@ -210,21 +216,25 @@ local function splitauthor(author,justsplit) end end while i <= n do - surnames[#surnames+1], i = words[i], i + 1 + surnames[#surnames+1] = words[i] + i = i + 1 end -- local words = lpegmatch(spacesplitter,split[2]) - local i, n = 1, #words + local i = 1 + local n = #words while i <= n do local w = words[i] if is_upper(w) then - firstnames[#firstnames+1], i = w, i + 1 + firstnames[#firstnames+1] = w + i = i + 1 else break end end while i <= n do - vons[#vons+1], i = words[i], i + 1 + vons[#vons+1] = words[i] + i = i + 1 end if surnames and firstnames and #surnames == 0 then -- safeguard @@ -316,12 +326,14 @@ local function the_initials(initials,symbol,connector) if not connector then connector = "-" end - local result, r = { }, 0 + local result = { } + local r = 0 for i=1,#initials do local initial = initials[i] if type(initial) == "table" then -- J.-J. - local set, s = { }, 0 + local set = { } + local s = 0 for i=1,#initial do if i > 1 then s = s + 1 ; set[s] = connector diff --git a/tex/context/base/mkiv/publ-imp-apa.mkvi b/tex/context/base/mkiv/publ-imp-apa.mkvi index 160cc4522..36e4882d2 100644 --- a/tex/context/base/mkiv/publ-imp-apa.mkvi +++ b/tex/context/base/mkiv/publ-imp-apa.mkvi @@ -696,6 +696,30 @@ apa:Advanced={Publicación en línea avanzada}, apa:Retrieved={Obtenido de}] % {Disponible desde}] + +\setupbtxlabeltext + [sv] + [apa:number={nr.}, + apa:edition={Utgåva}, + apa:Editor=Redaktör, + apa:Editors=Redaktörer, + apa:Volume=Band, + apa:Volumes=Band, + apa:nd={u.å.}, % utan årtal + apa:supplement=Bilaga, % Supplement + apa:MotionPicture=Spelfilm, % ? + apa:Writer={Manusförfattare}, % Assuming for a movie + apa:Writers={Manusförfattare}, % + apa:Producer=Producent, % Assuming for a movie + apa:Producers=Producenter, % + apa:Director={Regissör}, % Assuming for a movie + apa:Directors={Regissörer}, % + apa:Recordedby={Inspelad av}, % Assuming for a movie + apa:Author={Författare}, + apa:Translator={Översättare}, + apa:Advanced={Avancerad onlinepublikation}, % ? + apa:Retrieved={Hämtad från}] + % cite setups % The following differs from the default returning n.d. if year is empty diff --git a/tex/context/base/mkiv/publ-imp-aps.mkvi b/tex/context/base/mkiv/publ-imp-aps.mkvi index 4180b6491..d085b96eb 100644 --- a/tex/context/base/mkiv/publ-imp-aps.mkvi +++ b/tex/context/base/mkiv/publ-imp-aps.mkvi @@ -514,6 +514,20 @@ aps:tobe={que se publicará}, aps:unpublished={inédito}] +\setupbtxlabeltext + [sv] + [aps:number={nr.}, + aps:edition={Utgåva}, + aps:Editor=Redaktör, + aps:Editors=Redaktörer, + aps:Volume=Band, + aps:Volumes=Band, + aps:supplement=Bilaga, + aps:inpress={under tryckning}, + aps:tobe={att publiceras}, + aps:unpublished={opublicerat}] + + % cite setups \startsetups btx:aps:nd @@ -651,8 +665,10 @@ \stoptexdefinition \starttexdefinition unexpanded btx:aps:author - \btxflush{author} - \btxcomma + \btxdoif {author} { + \btxflush{author} + \btxcomma + } \stoptexdefinition \starttexdefinition unexpanded btx:aps:organization-if-not-author diff --git a/tex/context/base/mkiv/publ-imp-commands.mkvi b/tex/context/base/mkiv/publ-imp-commands.mkvi index 14e2dbae1..281b8324a 100644 --- a/tex/context/base/mkiv/publ-imp-commands.mkvi +++ b/tex/context/base/mkiv/publ-imp-commands.mkvi @@ -10,6 +10,6 @@ \definebtxcommand\acro #1{\dontleavehmode{\smallcaps#1}} \let\<< -\let\<> +\let\>> \protect \endinput diff --git a/tex/context/base/mkiv/publ-imp-default.mkvi b/tex/context/base/mkiv/publ-imp-default.mkvi index 22638c900..fef993fe0 100644 --- a/tex/context/base/mkiv/publ-imp-default.mkvi +++ b/tex/context/base/mkiv/publ-imp-default.mkvi @@ -342,24 +342,36 @@ [it] [\s!default:and=e, \s!default:number={nº}, - \s!default:edition={ed.}, % edizione + \s!default:edition={ed.}, % edizione \s!default:Editor={A cura di}, \s!default:Editors={A cura di}, - \s!default:Volume={Vol.}, % Volume - \s!default:Volumes={Vol.}, % Volumi + \s!default:Volume={Vol.}, % Volume + \s!default:Volumes={Vol.}, % Volumi \s!default:others={et al.}] \setupbtxlabeltext [es] [\s!default:and=y, \s!default:number={nº}, - \s!default:edition={ed.}, % edición - \s!default:Editor=Editor, % Ed./Eds. + \s!default:edition={ed.}, % edición + \s!default:Editor=Editor, % Ed./Eds. \s!default:Editors=Editores, \s!default:Volume={Vol.}, % Volumen \s!default:Volumes={Vols.}, % Volúmenes \s!default:others={et al.}] +\setupbtxlabeltext + [sv] + [\s!default:and=och, + \s!default:number={nr.}, + \s!default:edition={Utgåva}, + \s!default:Editor=Redaktör, + \s!default:Editors=Redaktörer, + \s!default:Volume=Band, + \s!default:Volumes=Band, + \s!default:others={et al.}] + + % First some helpers: \starttexdefinition btx:default:composed-title diff --git a/tex/context/base/mkiv/publ-ini.lua b/tex/context/base/mkiv/publ-ini.lua index ecc013dcd..f62352f07 100644 --- a/tex/context/base/mkiv/publ-ini.lua +++ b/tex/context/base/mkiv/publ-ini.lua @@ -1065,14 +1065,17 @@ do -- maybe not redo when already done local function shortsorter(a,b) - local ay, by = a[2], b[2] -- year + local ay = a[2] -- year + local by = b[2] -- year if ay ~= by then return ay < by end - local ay, by = a[3], b[3] -- suffix + local ay = a[3] -- suffix + local by = b[3] -- suffix if ay ~= by then -- bah, bah, bah - local an, bn = tonumber(ay), tonumber(by) + local an = tonumber(ay) + local bn = tonumber(by) if an and bn then return an < bn else @@ -2023,7 +2026,8 @@ do for i=1,nofranges do local r = ranges[i] ctx_btxsetconcat(concatstate(i,nofranges)) - local first, last = r[1], r[2] + local first = r[1] + local last = r[2] ctx_btxsetfirstinternal(first[2].internal) ctx_btxsetfirstpage(first[1]) if last then @@ -2044,7 +2048,8 @@ do } local function identical(a,b) - local na, nb = #a, #b + local na = #a + local nb = #b if na ~= nb then return false end @@ -2056,7 +2061,8 @@ do end return true end - local ha, hb = a.hash, b.hash + local ha = a.hash + local hb = b.hash if ha then return ha == hb end diff --git a/tex/context/base/mkiv/scrn-wid.lua b/tex/context/base/mkiv/scrn-wid.lua index 5b70bec75..17c9ebddc 100644 --- a/tex/context/base/mkiv/scrn-wid.lua +++ b/tex/context/base/mkiv/scrn-wid.lua @@ -143,6 +143,7 @@ implement { { "file" }, { "name" }, { "buffer" }, + { "mimetype" }, } } } @@ -172,6 +173,7 @@ implement { { "file" }, { "name" }, { "buffer" }, + { "mimetype" }, } } } diff --git a/tex/context/base/mkiv/scrn-wid.mkvi b/tex/context/base/mkiv/scrn-wid.mkvi index d1571ca65..b92880f2e 100644 --- a/tex/context/base/mkiv/scrn-wid.mkvi +++ b/tex/context/base/mkiv/scrn-wid.mkvi @@ -109,6 +109,7 @@ file {\attachmentparameter\c!file}% name {\attachmentparameter\c!name}% buffer {\attachmentparameter\c!buffer}% + mimetype {\attachmentparameter\c!type}% \relax \endgroup \else @@ -211,6 +212,7 @@ file {\attachmentparameter\c!file}% name {\attachmentparameter\c!name}% buffer {\attachmentparameter\c!buffer}% + mimetype {\attachmentparameter\c!type}% \relax \wd\b_scrn_attachment_link\currentattachmentwidth \ht\b_scrn_attachment_link\currentattachmentheight @@ -228,6 +230,7 @@ file {\attachmentparameter\c!file}% name {\attachmentparameter\c!name}% buffer {\attachmentparameter\c!buffer}% + mimetype {\attachmentparameter\c!type}% \relax} \unexpanded\def\scrn_attachment_flush_traced diff --git a/tex/context/base/mkiv/scrp-ini.lua b/tex/context/base/mkiv/scrp-ini.lua index c9479cccb..e6aa5f072 100644 --- a/tex/context/base/mkiv/scrp-ini.lua +++ b/tex/context/base/mkiv/scrp-ini.lua @@ -468,8 +468,8 @@ function scripts.injectors.handler(head) if not start then return head else - local last_a, normal_process, lastfont, originals = nil, nil, nil, nil - local first, last, ok = nil, nil, false + local last_a, normal_process, lastfont, originals, first, last + local ok = false while start do local char, id = isglyph(start) if char then @@ -1012,12 +1012,14 @@ do end, nobreakspace_before = function(head,current) - local g, p = space_glue(current), new_penalty(10000) + local g = space_glue(current) + local p = new_penalty(10000) head, current = insert_node_before(head,current,p) return insert_node_before(head,current,g) end, nobreakspace_after = function(head,current) - local g, p = space_glue(current), new_penalty(10000) + local g = space_glue(current) + local p = new_penalty(10000) head, current = insert_node_after(head,current,g) return insert_node_after(head,current,p) end, diff --git a/tex/context/base/mkiv/sort-ini.lua b/tex/context/base/mkiv/sort-ini.lua index f90b70be5..0916337b1 100644 --- a/tex/context/base/mkiv/sort-ini.lua +++ b/tex/context/base/mkiv/sort-ini.lua @@ -401,8 +401,10 @@ local function basic(a,b) -- trace ea and eb -- hashed (shared) entries return 0 end - local ea, eb = a.split, b.split - local na, nb = #ea, #eb + local ea = a.split + local eb = b.split + local na = #ea + local nb = #eb if na == 0 and nb == 0 then -- simple variant (single word) local result = 0 @@ -414,7 +416,8 @@ local function basic(a,b) -- trace ea and eb end end if result == 0 then - local la, lb = #ea.uc, #eb.uc + local la = #ea.uc + local lb = #eb.uc if la > lb then return 1 elseif lb > la then @@ -429,7 +432,8 @@ local function basic(a,b) -- trace ea and eb -- complex variant, used in register (multiple words) local result = 0 for i=1,nb < na and nb or na do - local eai, ebi = ea[i], eb[i] + local eai = ea[i] + local ebi = eb[i] for j=1,#sequence do local m = sequence[j] result = basicsort(eai[m],ebi[m]) @@ -438,7 +442,8 @@ local function basic(a,b) -- trace ea and eb end end if result == 0 then - local la, lb = #eai.uc, #ebi.uc + local la = #eai.uc + local lb = #ebi.uc if la > lb then return 1 elseif lb > la then @@ -586,8 +591,18 @@ function splitters.utf(str,checked) -- we could append m and u but this is clean -- end -- end end - local m_case, z_case, p_case, m_mapping, z_mapping, p_mapping, char, byte, n = { }, { }, { }, { }, { }, { }, { }, { }, 0 - local nm, nz, np = 0, 0, 0 + local m_case = { } + local z_case = { } + local p_case = { } + local m_mapping = { } + local z_mapping = { } + local p_mapping = { } + local char = { } + local byte = { } + local n = 0 + local nm = 0 + local nz = 0 + local np = 0 for sc in utfcharacters(str) do local b = utfbyte(sc) if b >= digitsoffset then diff --git a/tex/context/base/mkiv/spac-hor.mkiv b/tex/context/base/mkiv/spac-hor.mkiv index 32b7f06fb..24c7c7893 100644 --- a/tex/context/base/mkiv/spac-hor.mkiv +++ b/tex/context/base/mkiv/spac-hor.mkiv @@ -717,7 +717,7 @@ \global\s_spac_narrower_left \zeropoint \global\s_spac_narrower_right \zeropoint \global\s_spac_narrower_middle\zeropoint - \edef\askednarrower{#1} + \edef\askednarrower{#1}% \ifx\askednarrower\v!reverse \ifconditional\s_spac_narrower_last_swap \leftskip \s_spac_narrower_right_last diff --git a/tex/context/base/mkiv/spac-prf.lua b/tex/context/base/mkiv/spac-prf.lua index d355cc533..32582c56f 100644 --- a/tex/context/base/mkiv/spac-prf.lua +++ b/tex/context/base/mkiv/spac-prf.lua @@ -131,6 +131,9 @@ local function getprofile(line,step) local margin = step / 4 local min = 0 local max = ceiling(getwidth(line)/step) + 1 + local wd = 0 + local ht = 0 + local dp = 0 for i=min,max do heights[i] = 0 @@ -139,8 +142,6 @@ local function getprofile(line,step) -- remember p - local wd, ht, dp = 0, 0, 0 - local function progress() position = width width = position + wd diff --git a/tex/context/base/mkiv/spac-ver.lua b/tex/context/base/mkiv/spac-ver.lua index 07a58ae47..1410e3278 100644 --- a/tex/context/base/mkiv/spac-ver.lua +++ b/tex/context/base/mkiv/spac-ver.lua @@ -168,6 +168,7 @@ local nodepool = nuts.pool local new_penalty = nodepool.penalty local new_kern = nodepool.kern +local new_glue = nodepool.glue local new_rule = nodepool.rule local nodecodes = nodes.nodecodes @@ -877,7 +878,8 @@ end local trace_list, tracing_info, before, after = { }, false, "", "" local function nodes_to_string(head) - local current, t = head, { } + local current = head + local t = { } while current do local id = getid(current) local ty = nodecodes[id] @@ -1266,17 +1268,26 @@ do if trace then reset_tracing(head) end - local current, oldhead = head, head - local glue_order, glue_data, force_glue = 0, nil, false - local penalty_order, penalty_data, natural_penalty, special_penalty = 0, nil, nil, nil - local parskip, ignore_parskip, ignore_following, ignore_whitespace, keep_together = nil, false, false, false, false - local lastsnap = nil + local current = head + local oldhead = head + local glue_order = 0 + local glue_data + local force_glue = false + local penalty_order = 0 + local penalty_data + local natural_penalty + local special_penalty + local parskip + local ignore_parskip = false + local ignore_following = false + local ignore_whitespace = false + local keep_together = false + local lastsnap + local pagehead + local pagetail -- -- todo: keep_together: between headers -- - local pagehead = nil - local pagetail = nil - local function getpagelist() if not pagehead then pagehead = texlists.page_head @@ -1952,8 +1963,9 @@ do if stackhead then if trace_collect_vspacing then report("%s > appending %s nodes to stack (final): %s",where,newhead) end setlink(stacktail,newhead) - newhead = stackhead - stackhead, stacktail = nil, nil + newhead = stackhead + stackhead = nil + stacktail = nil end if stackhack then stackhack = false @@ -2146,27 +2158,105 @@ do trackers.register("vspacing.forcestrutdepth",function(v) trace = v end) - function vspacing.forcestrutdepth(n,depth,trace_mode) + local last = nil + + -- function vspacing.forcestrutdepth(n,depth,trace_mode,plus) + -- local box = texgetbox(n) + -- if box then + -- box = tonut(box) + -- local head = getlist(box) + -- if head then + -- local tail = find_node_tail(head) + -- if tail and getid(tail) == hlist_code then + -- local dp = getdepth(tail) + -- if dp < depth then + -- setdepth(tail,depth) + -- outer.prevdepth = depth + -- if trace or trace_mode > 0 then + -- nuts.setvisual(tail,"depth") + -- end + -- end + -- end + -- end + -- end + -- end + + function vspacing.forcestrutdepth(n,depth,trace_mode,plus) local box = texgetbox(n) if box then box = tonut(box) local head = getlist(box) if head then local tail = find_node_tail(head) - if tail and getid(tail) == hlist_code then - local dp = getdepth(tail) - if dp < depth then - setdepth(tail,depth) - outer.prevdepth = depth - if trace or trace_mode > 0 then - nuts.setvisual(tail,"depth") + if tail then + if getid(tail) == hlist_code then + local dp = getdepth(tail) + if dp < depth then + setdepth(tail,depth) + outer.prevdepth = depth + if trace or trace_mode > 0 then + nuts.setvisual(tail,"depth") + end + end + end + last = nil + if plus then + -- penalty / skip ... + local height = 0 + local sofar = 0 + local same = false + local seen = false + local list = { } + last = nil + while tail do + local id = getid(tail) + if id == hlist_code or id == vlist_code then + local w, h, d = getwhd(tail) + height = height + h + d + sofar + sofar = 0 + last = tail + elseif id == kern_code then + sofar = sofar + getkern(tail) + elseif id == glue_code then + if seen then + sofar = sofar + getwidth(tail) + seen = false + else + break + end + elseif id == penalty_code then + local p = getpenalty(tail) + if p >= 10000 then + same = true + seen = true + else + break + end + else + break + end + tail = getprev(tail) end + texsetdimen("global","d_spac_prevcontent",same and height or 0) end end end end end + function vspacing.pushatsame() + -- needs better checking ! + if last then -- setsplit + nuts.setnext(getprev(last)) + nuts.setprev(last) + end + end + + function vspacing.popatsame() + -- needs better checking ! + nuts.write(last) + end + end -- interface @@ -2194,6 +2284,25 @@ do } implement { + name = "forcestrutdepthplus", + arguments = { "integer", "dimension", "integer", true }, + actions = vspacing.forcestrutdepth, + scope = "private" + } + + implement { + name = "pushatsame", + actions = vspacing.pushatsame, + scope = "private" + } + + implement { + name = "popatsame", + actions = vspacing.popatsame, + scope = "private" + } + + implement { name = "vspacingsetamount", actions = vspacing.setskip, scope = "private", diff --git a/tex/context/base/mkiv/spac-ver.mkiv b/tex/context/base/mkiv/spac-ver.mkiv index 7b36f9a5b..3f1be18e5 100644 --- a/tex/context/base/mkiv/spac-ver.mkiv +++ b/tex/context/base/mkiv/spac-ver.mkiv @@ -244,6 +244,7 @@ \newskip \s_spac_lastskip \newdimen\d_spac_prevdepth \newcount\c_spac_spacefactor +\newdimen\d_spac_prevcontent % set by lua \unexpanded\def\removelastskip {\ifvmode\ifdim\lastskip=\zeropoint\else\vskip-\lastskip\fi\fi} diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf Binary files differindex c2c5d8791..faae4787a 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 b460df354..622b5fbe7 100644 --- a/tex/context/base/mkiv/status-lua.pdf +++ b/tex/context/base/mkiv/status-lua.pdf diff --git a/tex/context/base/mkiv/strc-doc.lua b/tex/context/base/mkiv/strc-doc.lua index 3445cbd24..4b2ac04b7 100644 --- a/tex/context/base/mkiv/strc-doc.lua +++ b/tex/context/base/mkiv/strc-doc.lua @@ -389,8 +389,9 @@ function sections.setentry(given) -- new number olddepth = newdepth if metadata.increment then - local oldn, newn = numbers[newdepth] or 0, 0 - local fd = forced[newdepth] + local oldn = numbers[newdepth] or 0 + local newn = 0 + local fd = forced[newdepth] if fd then if fd[1] == "add" then newn = oldn + fd[2] + 1 @@ -445,7 +446,10 @@ end function sections.reportstructure() if sections.verbose then - local numbers, ownnumbers, status, depth = data.numbers, data.ownnumbers, data.status, data.depth + local numbers = data.numbers + local ownnumbers = data.ownnumbers + local status = data.status + local depth = data.depth local d = status[depth] local o = concat(ownnumbers,".",1,depth) local n = (numbers and concat(numbers,".",1,min(depth,#numbers))) or 0 @@ -718,7 +722,8 @@ function sections.typesetnumber(entry,kind,...) -- kind='section','number','pref criterium = 0 end -- - local firstprefix, lastprefix = 0, 16 -- too much, could max found level + local firstprefix = 0 + local lastprefix = 16 -- too much, could max found level if segments == v_current then firstprefix = data.depth lastprefix = firstprefix @@ -741,9 +746,11 @@ function sections.typesetnumber(entry,kind,...) -- kind='section','number','pref end end -- - local numbers, ownnumbers = entry.numbers, entry.ownnumbers + local numbers = entry.numbers + local ownnumbers = entry.ownnumbers if numbers then - local done, preceding = false, false + local done = false + local preceding = false -- local result = kind == "direct" and { } if result then @@ -761,11 +768,14 @@ function sections.typesetnumber(entry,kind,...) -- kind='section','number','pref if prefixlist and (kind == "section" or kind == "prefix" or kind == "direct") then -- find valid set (problem: for sectionnumber we should pass the level) -- no holes - local b, e, bb, ee = 1, #prefixlist, 0, 0 + local b = 1 + local e = #prefixlist + local bb = 0 + local ee = 0 -- find last valid number for k=e,b,-1 do local prefix = prefixlist[k] - local index = sections.getlevel(prefix) or k + local index = sections.getlevel(prefix) or k if index >= firstprefix and index <= lastprefix then local number = numbers and numbers[index] if number then @@ -781,7 +791,7 @@ function sections.typesetnumber(entry,kind,...) -- kind='section','number','pref -- find valid range for k=b,e do local prefix = prefixlist[k] - local index = sections.getlevel(prefix) or k + local index = sections.getlevel(prefix) or k if index >= firstprefix and index <= lastprefix then local number = numbers and numbers[index] if number then diff --git a/tex/context/base/mkiv/strc-lst.lua b/tex/context/base/mkiv/strc-lst.lua index 72c24ed5d..bc6135e72 100644 --- a/tex/context/base/mkiv/strc-lst.lua +++ b/tex/context/base/mkiv/strc-lst.lua @@ -99,7 +99,8 @@ local v_default = variables.default -- for the moment not public -- local function zerostrippedconcat(t,separator) - local f, l = 1, #t + local f = 1 + local l = #t for i=f,l do if t[i] == 0 then f = f + 1 @@ -309,7 +310,8 @@ local synchronizepage = function(r) -- bah ... will move return synchronizepage(r) end -local function enhancelist(n) +local function enhancelist(specification) + local n = specification.n local l = cached[n] if not l then report_lists("enhancing %a, unknown internal",n) @@ -851,18 +853,22 @@ end function lists.userdata(name,r,tag) -- to tex (todo: xml) local result = lists.result[r] if result then - local userdata, metadata = result.userdata, result.metadata + local userdata = result.userdata local str = userdata and userdata[tag] if str then - return str, metadata + return str, result.metadata end end end function lists.uservalue(name,r,tag,default) -- to lua local str = lists.result[r] - str = str and str.userdata - str = str and str[tag] + if str then + str = str.userdata + end + if str then + str = str[tag] + end return str or default end @@ -1076,7 +1082,9 @@ implement { implement { name = "enhancelist", arguments = "integer", - actions = enhancelist, + actions = function(n) + enhancelist { n = n } + end } implement { @@ -1084,7 +1092,7 @@ implement { arguments = "integer", protected = true, -- for now, pre 1.09 actions = function(n) - ctx_latelua(function() enhancelist(n) end) + ctx_latelua { action = enhancelist, n = n } end, } diff --git a/tex/context/base/mkiv/strc-mar.lua b/tex/context/base/mkiv/strc-mar.lua index c904c699e..0221b9b8f 100644 --- a/tex/context/base/mkiv/strc-mar.lua +++ b/tex/context/base/mkiv/strc-mar.lua @@ -437,7 +437,8 @@ local function resolve(name,first,last,strict,quitonfalse,notrace) if trace_marks_get and not notrace then report_marks("found chain [ % => T ]",fullchain) end - local chaindata, chainlength = { }, #fullchain + local chaindata = { } + local chainlength = #fullchain for i=1,chainlength do local cname = fullchain[i] if data[cname].set > 0 then @@ -513,7 +514,8 @@ local methods = { } local function doresolve(name,rangename,swap,df,dl,strict) local range = ranges[rangename] or ranges[v_page] - local first, last = range.first, range.last + local first = range.first + local last = range.last if trace_marks_get then report_marks("action %a, name %a, range %a, swap %a, first %a, last %a, df %a, dl %a, strict %a", "resolving",name,rangename,swap or false,first,last,df,dl,strict or false) @@ -642,7 +644,10 @@ function marks.tracers.showtable() context.tabulaterowbold("name","parent","chain","children","fullchain") context.ML() for k, v in table.sortedpairs(data) do - local parent, chain, children, fullchain = v.parent or "", v.chain or "", v.children or { }, v.fullchain or { } + local parent = v.parent or "" + local chain = v.chain or "" + local children = v.children or { } + local fullchain = v.fullchain or { } table.sort(children) -- in-place but harmless context.tabulaterowtyp(k,parent,chain,concat(children," "),concat(fullchain," ")) end diff --git a/tex/context/base/mkiv/strc-not.lua b/tex/context/base/mkiv/strc-not.lua index bb9d64beb..b2c8106e1 100644 --- a/tex/context/base/mkiv/strc-not.lua +++ b/tex/context/base/mkiv/strc-not.lua @@ -247,15 +247,38 @@ end notes.internal = internal notes.ordered = ordered +-- local function onsamepageasprevious(tag) +-- local same = false +-- local n = getn(tag,n) +-- local current = get(tag,n) +-- local previous = get(tag,n-1) +-- if current and previous then +-- local cr = current.references +-- local pr = previous.references +-- same = cr and pr and cr.realpage == pr.realpage +-- end +-- return same and true or false +-- end + local function onsamepageasprevious(tag) - local same = false - local n = getn(tag,n) - local current, previous = get(tag,n), get(tag,n-1) - if current and previous then - local cr, pr = current.references, previous.references - same = cr and pr and cr.realpage == pr.realpage + local n = getn(tag,n) + local current = get(tag,n) + if not current then + return false + end + local cr = current.references + if not cr then + return false + end + local previous = get(tag,n-1) + if not previous then + return false + end + local pr = previous.references + if not pr then + return false end - return same and true or false + return cr.realpage == pr.realpage end notes.doifonsamepageasprevious = onsamepageasprevious @@ -471,7 +494,7 @@ local texsetglue = tex.setglue local function check_spacing(n,i) local gn, pn, mn = texgetglue(n) local gi, pi, mi = texgetglue(i > 1 and "s_strc_notes_inbetween" or "s_strc_notes_before") - local gt, pt, mt = gn+gi, pn+pi, mn+mi + local gt, pt, mt = gn + gi, pn + pi, mn + mi if trace_insert then report_insert("%s %i: %p plus %p minus %p","always ",n,gn,pn,mn) report_insert("%s %i: %p plus %p minus %p",i > 1 and "inbetween" or "before ",n,gi,pi,mi) diff --git a/tex/context/base/mkiv/strc-num.lua b/tex/context/base/mkiv/strc-num.lua index e1a133f4a..25e575a56 100644 --- a/tex/context/base/mkiv/strc-num.lua +++ b/tex/context/base/mkiv/strc-num.lua @@ -273,7 +273,7 @@ end function counters.compact(name,level,onlynumbers) local cd = counterdata[name] if cd then - local data = cd.data + local data = cd.data local compact = { } for i=1,level or #data do local d = data[i] @@ -541,22 +541,26 @@ function counters.converted(name,spec) -- name can be number and reference to st local cd if type(name) == "number" then cd = specials.retrieve("counter",name) - cd = cd and cd.counter + if cd then + cd = cd.counter + end else cd = counterdata[name] end if cd then - local spec = spec or { } - local numbers, ownnumbers = { }, { } - local reverse = spec.order == v_reverse - local kind = spec.type or "number" - local data = cd.data + local spec = spec or { } + local numbers = { } + local ownnumbers = { } + local reverse = spec.order == v_reverse + local kind = spec.type or "number" + local data = cd.data for k=1,#data do local v = data[k] -- somewhat messy, what if subnr? only last must honour kind? local vn if v.own then - numbers[k], ownnumbers[k] = v.number, v.own + numbers[k] = v.number + ownnumbers[k] = v.own else if kind == v_first then vn = v.first @@ -577,13 +581,14 @@ function counters.converted(name,spec) -- name can be number and reference to st end end end - numbers[k], ownnumbers[k] = vn or v.number, nil + numbers[k] = vn or v.number + ownnumbers[k] = nil end end - cd.numbers = numbers + cd.numbers = numbers cd.ownnumbers = ownnumbers sections.typesetnumber(cd,'number',spec) - cd.numbers = nil + cd.numbers = nil cd.ownnumbers = nil end end diff --git a/tex/context/base/mkiv/strc-pag.lua b/tex/context/base/mkiv/strc-pag.lua index dcd35fc20..ee1b245b9 100644 --- a/tex/context/base/mkiv/strc-pag.lua +++ b/tex/context/base/mkiv/strc-pag.lua @@ -113,8 +113,9 @@ end -- end function pages.number(realdata,pagespec) - local userpage, block = realdata.number, realdata.block or "" -- sections.currentblock() - local numberspec = realdata.numberdata + local userpage = realdata.number + local block = realdata.block or "" -- sections.currentblock() + local numberspec = realdata.numberdata local conversionset = (pagespec and pagespec.conversionset ~= "" and pagespec.conversionset) or (numberspec and numberspec.conversionset ~= "" and numberspec.conversionset) or "" local conversion = (pagespec and pagespec.conversion ~= "" and pagespec.conversion ) or (numberspec and numberspec.conversion ~= "" and numberspec.conversion ) or "" local starter = (pagespec and pagespec.starter ~= "" and pagespec.starter ) or (numberspec and numberspec.starter ~= "" and numberspec.starter ) or "" @@ -212,9 +213,11 @@ end function helpers.prefixlastpage(data,prefixspec,pagespec) if data then - local r = data.references - local ls, lr = r.section, r.realpage - r.section, r.realpage = r.lastsection or r.section, r.lastrealpage or r.realpage + local r = data.references + local ls = r.section + local lr = r.realpage + r.section = r.lastsection or r.section + r.realpage = r.lastrealpage or r.realpage helpers.prefixpage(data,prefixspec,pagespec) r.section, r.realpage = ls, lr end @@ -227,7 +230,8 @@ function helpers.analyze(entry,specification) if not entry then return false, false, "no entry" end - local yes, no = variables.yes, variables.no + local yes = variables.yes + local no = variables.no -- section data local references = entry.references if not references then diff --git a/tex/context/base/mkiv/strc-ref.lua b/tex/context/base/mkiv/strc-ref.lua index e7ea73d3c..e01bacaac 100644 --- a/tex/context/base/mkiv/strc-ref.lua +++ b/tex/context/base/mkiv/strc-ref.lua @@ -434,8 +434,8 @@ end references.synchronizepage = synchronizepage -local function enhancereference(prefix,tag) - local l = tobesaved[prefix][tag] +local function enhancereference(specification) + local l = tobesaved[specification.prefix][specification.tag] if l then synchronizepage(l.references) end @@ -446,7 +446,9 @@ references.enhance = enhancereference -- implement { -- name = "enhancereference", -- arguments = "2 strings", --- actions = references.enhance, +-- actions = function(prefix,tag) +-- enhancereference { prefix = prefix, tag = tag } +-- end, -- } implement { @@ -454,7 +456,7 @@ implement { arguments = "2 strings", protected = true, actions = function(prefix,tag) - ctx_latelua(function() enhancereference(prefix,tag) end) + ctx_latelua { action = enhancereference, prefix = prefix, tag = tag } end, } @@ -1999,7 +2001,8 @@ local function setinternalreference(specification) local internal = specification.internal local destination = unsetvalue if innermethod == v_auto or innermethod == v_name then - local t, tn = { }, 0 -- maybe add to current (now only used for tracing) + local t = { } -- maybe add to current (now only used for tracing) + local tn = 0 local reference = specification.reference local view = specification.view if reference then @@ -2320,7 +2323,8 @@ genericfilters.default = genericfilters.text function genericfilters.page(data,prefixspec,pagespec) local pagedata = data.pagedata if pagedata then - local number, conversion = pagedata.number, pagedata.conversion + local number = pagedata.number + local conversion = pagedata.conversion if not number then -- error elseif conversion then diff --git a/tex/context/base/mkiv/strc-reg.lua b/tex/context/base/mkiv/strc-reg.lua index 28f8cddcd..47ba1c533 100644 --- a/tex/context/base/mkiv/strc-reg.lua +++ b/tex/context/base/mkiv/strc-reg.lua @@ -568,14 +568,19 @@ local function storeregister(rawdata) -- metadata, references, entries return #entries end -local function enhanceregister(name,n) - local data = tobesaved[name].metadata.notsaved and collected[name] or tobesaved[name] +local function enhanceregister(specification) + local name = specification.name + local n = specification.n + local saved = tobesaved[name] + local data = saved.metadata.notsaved and collected[name] or saved local entry = data.entries[n] if entry then entry.references.realpage = texgetcount("realpageno") end end +-- This can become extendregister(specification)! + local function extendregister(name,tag,rawdata) -- maybe do lastsection internally if type(tag) == "string" then tag = tagged[tag] @@ -632,7 +637,9 @@ end implement { name = "enhanceregister", arguments = { "string", "integer" }, - actions = enhanceregister, + actions = function(name,n) + enhanceregister { name = name, n = n } -- todo: move to scanner + end, } implement { @@ -640,7 +647,7 @@ implement { arguments = { "string", "integer" }, protected = true, actions = function(name,n) - ctx_latelua(function() enhanceregister(name,n) end) + ctx_latelua { action = enhanceregister, name = name, n = n } end, } @@ -712,7 +719,8 @@ function registers.compare(a,b) local ka = a.metadata.kind local kb = b.metadata.kind if ka == kb then - local page_a, page_b = a.references.realpage, b.references.realpage + local page_a = a.references.realpage + local page_b = b.references.realpage if not page_a or not page_b then return 0 elseif page_a < page_b then @@ -857,7 +865,9 @@ function registers.sort(data,options) end function registers.unique(data,options) - local result, nofresult, prev = { }, 0, nil + local result = { } + local nofresult = 0 + local prev = nil local dataresult = data.result for k=1,#dataresult do local v = dataresult[k] @@ -869,7 +879,8 @@ function registers.unique(data,options) elseif pr.realpage ~= vr.realpage then -- ok else - local pl, vl = pr.lastrealpage, vr.lastrealpage + local pl = pr.lastrealpage + local vl = vr.lastrealpage if pl or vl then if not vl then -- ok @@ -897,7 +908,11 @@ end function registers.finalize(data,options) -- maps character to index (order) local result = data.result data.metadata.nofsorted = #result - local split, nofsplit, lasttag, done, nofdone = { }, 0, nil, nil, 0 + local split = { } + local nofsplit = 0 + local lasttag = nil + local done = nil + local nofdone = 0 local firstofsplit = sorters.firstofsplit for k=1,#result do local v = result[k] @@ -1007,7 +1022,8 @@ implement { -- todo: ownnumber local function pagerange(f_entry,t_entry,is_last,prefixspec,pagespec) - local fer, ter = f_entry.references, t_entry.references + local fer = f_entry.references + local ter = t_entry.references ctx_registerpagerange( f_entry.metadata.name or "", f_entry.processors and f_entry.processors[2] or "", @@ -1040,7 +1056,8 @@ local function pagenumber(entry,prefixspec,pagespec) end local function packed(f_entry,t_entry) - local fer, ter = f_entry.references, t_entry.references + local fer = f_entry.references + local ter = t_entry.references ctx_registerpacked( fer.internal or 0, ter.internal or 0 @@ -1049,8 +1066,12 @@ end local function collapsedpage(pages) for i=2,#pages do - local first, second = pages[i-1], pages[i] - local first_first, first_last, second_first, second_last = first[1], first[2], second[1], second[2] + local first = pages[i-1] + local second = pages[i] + local first_first = first[1] + local first_last = first[2] + local second_first = second[1] + local second_last = second[2] local first_last_pn = first_last .references.realpage local second_first_pn = second_first.references.realpage local second_last_pn = second_last .references.realpage @@ -1146,7 +1167,8 @@ function registers.flush(data,options,prefixspec,pagespec) done[i] = false end local data = sublist.data - local d, n = 0, 0 + local d = 0 + local n = 0 ctx_startregistersection(sublist.tag) for d=1,#data do local entry = data[d] @@ -1341,7 +1363,8 @@ function registers.flush(data,options,prefixspec,pagespec) end local function case_4() - local t, nt = { }, 0 + local t = { } + local nt = 0 while true do if entry.seeword and entry.seeword.valid then nt = nt + 1 @@ -1361,7 +1384,7 @@ function registers.flush(data,options,prefixspec,pagespec) end end for i=1,nt do - local entry = t[i] + local entry = t[i] local seeword = entry.seeword local seetext = seeword.text or "" local processor = seeword.processor or (entry.processors and entry.processors[1]) or "" diff --git a/tex/context/base/mkiv/strc-reg.mkiv b/tex/context/base/mkiv/strc-reg.mkiv index 559e1bd42..1ab7d8ae0 100644 --- a/tex/context/base/mkiv/strc-reg.mkiv +++ b/tex/context/base/mkiv/strc-reg.mkiv @@ -939,6 +939,18 @@ \fi \popcurrentregister} +\newconditional\c_strc_registers_following + +\appendtoks + \edef\p_compress{\registerparameter\c!compress}% + \ifx\p_compress\v!text + \settrue\c_strc_registers_following + \letregisterparameter\c!compress\v!yes + \else + \setfalse\c_strc_registers_following + \fi +\to \everyplaceregister + \unexpanded\def\registerpagerange#1#2#3#4#5#6#7#8% #1:class #2:processor content, content todo: -- configurable {\pushcurrentregister{#1}% \edef\p_pagenumber{\registerparameter\c!pagenumber}% @@ -949,9 +961,17 @@ \dostarttagged\t!registerfrompage\empty \withregisterpagecommand{#2}{#3}{#4}{#5}% \dostoptagged - \registeronepagerangeseparator - \dostarttagged\t!registertopage\empty - \withregisterpagecommand{#2}{#6}{#7}{#8}% + \ifconditional\c_strc_registers_following + \ifnum#3=\numexpr#6-1\relax + \labeltext{following:\s!singular}% + \else + \labeltext{following:\s!plural}% + \fi + \else + \registeronepagerangeseparator + \dostarttagged\t!registertopage\empty + \withregisterpagecommand{#2}{#6}{#7}{#8}% + \fi \dostoptagged \dostoptagged \fi diff --git a/tex/context/base/mkiv/strc-ren.mkiv b/tex/context/base/mkiv/strc-ren.mkiv index 01464ad86..5cdf5f4a7 100644 --- a/tex/context/base/mkiv/strc-ren.mkiv +++ b/tex/context/base/mkiv/strc-ren.mkiv @@ -376,10 +376,12 @@ \egroup \ifconditional\headisdisplay \useindentnextparameter\headparameter + \else\ifconditional\headissomewhere + \ignoreparskip + \noindentation \else \ignoreparskip - \noindentation % recently added, was a bug - \fi} + \fi\fi} % nice testcase % diff --git a/tex/context/base/mkiv/supp-box.lua b/tex/context/base/mkiv/supp-box.lua index a22eb8f69..1f31f7681 100644 --- a/tex/context/base/mkiv/supp-box.lua +++ b/tex/context/base/mkiv/supp-box.lua @@ -365,7 +365,9 @@ implement { } local function getnaturaldimensions(n) - local w, h, d = 0, 0, 0 + local w = 0 + local h = 0 + local d = 0 local l = getlist(getbox(n)) if l then w, h, d = getdimensions(l) @@ -395,7 +397,9 @@ interfaces.implement { name = "getnaturalwd", arguments = "integer", actions = function(n) - local w, h, d = 0, 0, 0 + local w = 0 + local h = 0 + local d = 0 local l = getlist(getbox(n)) if l then w, h, d = getdimensions(l) diff --git a/tex/context/base/mkiv/symb-ini.mkiv b/tex/context/base/mkiv/symb-ini.mkiv index abf857675..428fcd381 100644 --- a/tex/context/base/mkiv/symb-ini.mkiv +++ b/tex/context/base/mkiv/symb-ini.mkiv @@ -44,9 +44,23 @@ %D \stoptyping \installcorenamespace{symbol} +\installcorenamespace{symbols} \installcorenamespace{symbolset} \installcorenamespace{symboldefault} +%D For now we only have one option. + +\installparameterhandler\??symbols {symbols} +\installsetuphandler \??symbols {symbols} + +\appendtoks + \doifelse{\symbolsparameter\c!stylealternative}\v!math + \settrue\setfalse\prefermathovertextchar +\to \everysetupsymbols + +\setupsymbols + [\c!stylealternative=\v!text] + \let\currentsymbol \empty \let\currentsymbolset\empty diff --git a/tex/context/base/mkiv/syst-ini.mkiv b/tex/context/base/mkiv/syst-ini.mkiv index 7690af018..7ce48c79f 100644 --- a/tex/context/base/mkiv/syst-ini.mkiv +++ b/tex/context/base/mkiv/syst-ini.mkiv @@ -1100,6 +1100,7 @@ \suppressmathparerror \plusone \suppressifcsnameerror\plusone +\let \suppresslongerror \relax \newcount\suppresslongerror \let\normalsuppresslongerror \suppresslongerror \let \suppressoutererror \suppresslongerror \let\normalsuppressoutererror \suppresslongerror \let \suppressmathparerror \suppresslongerror \let\normalsuppressmathparerror \suppresslongerror diff --git a/tex/context/base/mkiv/tabl-tbl.mkiv b/tex/context/base/mkiv/tabl-tbl.mkiv index 75839caed..f3c2e2e10 100644 --- a/tex/context/base/mkiv/tabl-tbl.mkiv +++ b/tex/context/base/mkiv/tabl-tbl.mkiv @@ -1670,9 +1670,9 @@ \def\tabl_tabulate_hrule_inject_normal {\autorule - \s!height .5\d_tabl_tabulate_hrulethickness_local - \s!depth .5\d_tabl_tabulate_hrulethickness_local - \s!left \d_tabl_tabulate_indent + \s!height.5\d_tabl_tabulate_hrulethickness_local + \s!depth .5\d_tabl_tabulate_hrulethickness_local + \s!left \d_tabl_tabulate_indent \relax} \def\tabl_tabulate_hrule_inject_colored diff --git a/tex/context/base/mkiv/tabl-xtb.lua b/tex/context/base/mkiv/tabl-xtb.lua index d87a5f49e..c9d50638e 100644 --- a/tex/context/base/mkiv/tabl-xtb.lua +++ b/tex/context/base/mkiv/tabl-xtb.lua @@ -377,7 +377,8 @@ function xtables.set_reflow_width() -- drc.dimensionstate = dimensionstate -- - local nx, ny = drc.nx, drc.ny + local nx = drc.nx + local ny = drc.ny if nx > 1 or ny > 1 then -- local spans = data.spans -- not used local self = true diff --git a/tex/context/base/mkiv/toks-ini.lua b/tex/context/base/mkiv/toks-ini.lua index 43e2d80a3..2c85a5754 100644 --- a/tex/context/base/mkiv/toks-ini.lua +++ b/tex/context/base/mkiv/toks-ini.lua @@ -33,6 +33,7 @@ end local scan_toks = token.scan_toks local scan_string = token.scan_string local scan_argument = token.scan_argument +local scan_tokenlist = token.scan_tokenlist local scan_int = token.scan_int local scan_code = token.scan_code local scan_dimen = token.scan_dimen @@ -208,6 +209,10 @@ if not scan_csname then end +local function scan_verbatim() + return scan_argument(false) +end + tokens.scanners = { -- these expand token = scan_token, toks = scan_toks, @@ -222,6 +227,8 @@ tokens.scanners = { -- these expand count = scan_int, string = scan_string, argument = scan_argument, + tokenlist = scan_tokenlist, + verbatim = scan_verbatim, code = scan_code, word = scan_word, number = scan_number, diff --git a/tex/context/base/mkiv/toks-scn.lua b/tex/context/base/mkiv/toks-scn.lua index f73ecc86c..297ef7121 100644 --- a/tex/context/base/mkiv/toks-scn.lua +++ b/tex/context/base/mkiv/toks-scn.lua @@ -22,6 +22,8 @@ local tokenbits = tokens.bits local scanstring = scanners.string local scanargument = scanners.argument +local scanverbatim = scanners.verbatim +local scantokenlist = scanners.tokenlist local scaninteger = scanners.integer local scannumber = scanners.number local scankeyword = scanners.keyword @@ -149,6 +151,9 @@ local shortcuts = { close = close, scanners = scanners, scanstring = scanstring, + scanargument = scanargument, + scanverbatim = scanverbatim, + scantokenlist = scantokenlist, scaninteger = scaninteger, scannumber = scannumber, scantable = scantable, diff --git a/tex/context/base/mkiv/trac-deb.lua b/tex/context/base/mkiv/trac-deb.lua index 95f3052fe..9788e72a0 100644 --- a/tex/context/base/mkiv/trac-deb.lua +++ b/tex/context/base/mkiv/trac-deb.lua @@ -31,6 +31,7 @@ local strings = tracers.strings local texgetdimen = tex.getdimen local texgettoks = tex.gettoks local texgetcount = tex.getcount +local texgethelp = tex.gethelptext or function() end local implement = interfaces.implement @@ -183,7 +184,7 @@ local function processerror(offset) local linenumber = tonumber(status.linenumber) or 0 local lastcontext = status.lasterrorcontext local lasttexerror = status.lasterrorstring or "?" - local lastluaerror = status.lastluaerrorstring or lasttexerror + local lastluaerror = status.lastluaerrorstring or "?" -- lasttexerror local luaerrorline = match(lastluaerror,[[lua%]?:.-(%d+)]]) or (lastluaerror and find(lastluaerror,"?:0:",1,true) and 0) local lastmpserror = match(lasttexerror,[[^.-mp%serror:%s*(.*)$]]) resetmessages() @@ -194,58 +195,83 @@ local function processerror(offset) offset = tonumber(offset) or 10, lasttexerror = lasttexerror, lastmpserror = lastmpserror, - lastluaerror = lastluaerror, + lastluaerror = lastluaerror, -- can be the same as lasttexerror luaerrorline = luaerrorline, lastcontext = lastcontext, + lasttexhelp = texgethelp(), } end -- so one can overload the printer if (really) needed +local quitonerror = true + +directives.register("system.quitonerror",function(v) quitonerror = toboolean(v) end) + +local busy = false + function tracers.printerror(specification) - local filename = specification.filename - local linenumber = specification.linenumber - local lasttexerror = specification.lasttexerror - local lastmpserror = specification.lastmpserror - local lastluaerror = specification.lastluaerror - local lastcontext = specification.lasterrorcontext - local luaerrorline = specification.luaerrorline - local errortype = specification.errortype - local offset = specification.offset - local report = errorreporter(luaerrorline) - if not filename then - report("error not related to input file: %s ...",lasttexerror) - elseif type(filename) == "number" then - report("error on line %s of filehandle %s: %s ...",linenumber,lasttexerror) - else - report_nl() - if luaerrorline then - if linenumber == 0 or not filename or filename == "" then - print("\nfatal lua error:\n\n",lastluaerror,"\n") - os.exit(1) - return + if not busy then + busy = true + local filename = specification.filename + local linenumber = specification.linenumber + local lasttexerror = specification.lasttexerror + local lastmpserror = specification.lastmpserror + local lastluaerror = specification.lastluaerror + local lastcontext = specification.lasterrorcontext + local luaerrorline = specification.luaerrorline + local errortype = specification.errortype + local offset = specification.offset + local report = errorreporter(luaerrorline) + if not filename then + report("error not related to input file: %s ...",lasttexerror) + elseif type(filename) == "number" then + report("error on line %s of filehandle %s: %s ...",linenumber,lasttexerror) + else + report_nl() + if luaerrorline then + if linenumber == 0 or not filename or filename == "" then + print("\nfatal lua error:\n\n",lastluaerror,"\n") + luatex.abort() + return + else + report("lua error on line %s in file %s:\n\n%s",linenumber,filename,lastluaerror) + end + elseif lastmpserror then + report("mp error on line %s in file %s:\n\n%s",linenumber,filename,lastmpserror) else - report("lua error on line %s in file %s:\n\n%s",linenumber,filename,lastluaerror) + report("tex error on line %s in file %s: %s",linenumber,filename,lasttexerror) + if lastcontext then + report_nl() + report_str(lastcontext) + report_nl() + elseif tex.show_context then + report_nl() + tex.show_context() + end end - elseif lastmpserror then - report("mp error on line %s in file %s:\n\n%s",linenumber,filename,lastmpserror) - else - report("tex error on line %s in file %s: %s",linenumber,filename,lasttexerror) - if lastcontext then + report_nl() + report_str(tracers.showlines(filename,linenumber,offset,tonumber(luaerrorline))) + report_nl() + end + local errname = file.addsuffix(tex.jobname .. "-error","log") + if quitonerror then + table.save(errname,specification) + local help = specification.lasttexhelp + if help and #help > 0 then report_nl() - report_str(lastcontext) + report_str(help) report_nl() - elseif tex.show_context then report_nl() - tex.show_context() end + luatex.abort() end - report_nl() - report_str(tracers.showlines(filename,linenumber,offset,tonumber(luaerrorline))) - report_nl() + busy = false end end +luatex.wrapup(function() os.remove(file.addsuffix(tex.jobname .. "-error","log")) end) + local function processwarning(offset) -- local inputstack = resolvers.inputstack -- local filename = inputstack[#inputstack] or status.filename @@ -324,6 +350,7 @@ function lmx.showerror(lmxname) else lmx.show(lmxname or 'context-error.lmx',variables) end + luatex.abort() end function lmx.overloaderror() diff --git a/tex/context/base/mkiv/trac-exp.lua b/tex/context/base/mkiv/trac-exp.lua index 5879f1b7b..e25110999 100644 --- a/tex/context/base/mkiv/trac-exp.lua +++ b/tex/context/base/mkiv/trac-exp.lua @@ -64,7 +64,7 @@ function exporters.man(specification,...) end -- result[#result+1] = formatters['.TH "%s" "1" "%s" "version %s" "%s"'](name,os.date("01-01-%Y"),version,detail) - result[#result+1] = formatters[".SH NAME\n.B %s"](name) + result[#result+1] = formatters[".SH NAME\n %s - %s"](name,detail) -- KB/TL wants 'detail' in this line too result[#result+1] = formatters[".SH SYNOPSIS\n.B %s [\n.I OPTIONS ...\n.B ] [\n.I FILENAMES\n.B ]"](runner) result[#result+1] = formatters[".SH DESCRIPTION\n.B %s"](detail) -- diff --git a/tex/context/base/mkiv/trac-inf.lua b/tex/context/base/mkiv/trac-inf.lua index 7a5c35fd5..a7823c251 100644 --- a/tex/context/base/mkiv/trac-inf.lua +++ b/tex/context/base/mkiv/trac-inf.lua @@ -214,13 +214,11 @@ function statistics.show() -- collectgarbage("collect") register("lua properties",function() local hashchar = tonumber(status.luatex_hashchars) - local hashtype = status.luatex_hashtype local mask = lua.mask or "ascii" - return format("engine: %s %s, used memory: %s, hash type: %s, hash chars: min(%i,40), symbol mask: %s (%s)", + return format("engine: %s %s, used memory: %s, hash chars: min(%i,40), symbol mask: %s (%s)", jit and "luajit" or "lua", LUAVERSION, statistics.memused(), - hashtype or "default", hashchar and 2^hashchar or "unknown", mask, mask == "utf" and "τεχ" or "tex") diff --git a/tex/context/base/mkiv/trac-lmx.lua b/tex/context/base/mkiv/trac-lmx.lua index c7f949618..a531a76d6 100644 --- a/tex/context/base/mkiv/trac-lmx.lua +++ b/tex/context/base/mkiv/trac-lmx.lua @@ -684,8 +684,9 @@ end lmx.make = lmxmake function lmx.show(name,variables) + -- todo: pcall local htmfile = lmxmake(name,variables) - lmx.popupfile(htmfile) + -- lmx.popupfile(htmfile) return htmfile end diff --git a/tex/context/base/mkiv/trac-log.lua b/tex/context/base/mkiv/trac-log.lua index 206af5668..e76c9f684 100644 --- a/tex/context/base/mkiv/trac-log.lua +++ b/tex/context/base/mkiv/trac-log.lua @@ -114,7 +114,7 @@ local direct, subdirect, writer, pushtarget, poptarget, setlogfile, settimedlog, -- we don't want this overhead for single messages (not that there are that -- many; we could have a special weak table) -if runningtex then +if runningtex and texio then if texio.setescape then texio.setescape(0) -- or (false) diff --git a/tex/context/base/mkiv/trac-vis.lua b/tex/context/base/mkiv/trac-vis.lua index b61dadb51..4dc3bd03b 100644 --- a/tex/context/base/mkiv/trac-vis.lua +++ b/tex/context/base/mkiv/trac-vis.lua @@ -1210,6 +1210,7 @@ do prev_trace_fontkern = trace_fontkern prev_trace_italic = trace_italic prev_trace_expansion = trace_expansion + attr = a if a == unsetvalue then trace_hbox = false trace_vbox = false @@ -1231,6 +1232,7 @@ do trace_line = false trace_space = false trace_depth = false + goto list else -- dead slow: -- cache[a]() trace_hbox = band(a, 1) ~= 0 @@ -1254,7 +1256,8 @@ do trace_space = band(a,262144) ~= 0 trace_depth = band(a,524288) ~= 0 end - attr = a + elseif a == unsetvalue then + goto list end if trace_strut then setattr(current,a_layer,l_strut) @@ -1313,7 +1316,24 @@ do if trace_penalty then head, current = ruledpenalty(head,current,vertical) end - elseif id == hlist_code then + elseif id == hlist_code or id == vlist_code then + goto list + elseif id == whatsit_code then + if trace_whatsit then + head, current = whatsit(head,current) + end + elseif id == user_code then + if trace_user then + head, current = user(head,current) + end + elseif id == math_code then + if trace_math then + head, current = math(head,current) + end + end + goto next + ::list:: + if id == hlist_code then local content = getlist(current) if content then setlist(current,visualize(content,false,nil,current)) @@ -1336,19 +1356,8 @@ do elseif trace_vbox then head, current = ruledbox(head,current,true,l_vbox,"__V",trace_simple,previous,trace_origin,parent) end - elseif id == whatsit_code then - if trace_whatsit then - head, current = whatsit(head,current) - end - elseif id == user_code then - if trace_user then - head, current = user(head,current) - end - elseif id == math_code then - if trace_math then - head, current = math(head,current) - end end + ::next:: previous = current current = getnext(current) end diff --git a/tex/context/base/mkiv/typo-brk.lua b/tex/context/base/mkiv/typo-brk.lua index 76e50ce18..d670c5319 100644 --- a/tex/context/base/mkiv/typo-brk.lua +++ b/tex/context/base/mkiv/typo-brk.lua @@ -265,7 +265,7 @@ function breakpoints.handler(head) -- for now we collect but when found ok we can move the handler here -- although it saves nothing in terms of performance local lang = getlang(current) - local smap = lang and lang >= 0 and lang < 0x7FFF and (cmap[numbers[lang]] or cmap[""]) + local smap = lang and lang >= 0 and lang < 0x7FFF and (cmap[languages.numbers[lang]] or cmap[""]) if smap then local skip = smap.skip local start = current @@ -314,17 +314,17 @@ function breakpoints.handler(head) return head end -- we have hits - local numbers = languages.numbers + -- local numbers = languages.numbers for i=1,#done do local data = done[i] local start = data[1] local stop = data[2] local cmap = data[3] local smap = data[4] --- -- we do a sanity check for language --- local lang = getlang(start) --- local smap = lang and lang >= 0 and lang < 0x7FFF and (cmap[numbers[lang]] or cmap[""]) --- if smap then + -- we do a sanity check for language + -- local lang = getlang(start) + -- local smap = lang and lang >= 0 and lang < 0x7FFF and (cmap[numbers[lang]] or cmap[""]) + -- if smap then local nleft = smap.nleft local cleft = 0 local prev = getprev(start) @@ -392,7 +392,7 @@ function breakpoints.handler(head) head, start = method(head,start,stop,smap,kern) end end --- end + -- end end end return head diff --git a/tex/context/base/mkiv/typo-lin.lua b/tex/context/base/mkiv/typo-lin.lua index 3b0de080d..758d0d502 100644 --- a/tex/context/base/mkiv/typo-lin.lua +++ b/tex/context/base/mkiv/typo-lin.lua @@ -408,12 +408,16 @@ function paragraphs.moveinline(n,blob,dx,dy) end end -local lateluafunction = nodepool.lateluafunction -local setposition = job.positions.set -local t_anchor = { x = true, c = true } +local latelua = nodepool.latelua +local setposition = jobpositions.setspec local function setanchor(h_anchor) - return lateluafunction(function() setposition("md:h",h_anchor,t_anchor) end) + return latelua { + action = setposition, + name = "md:h", + index = h_anchor, + value = { x = true, c = true }, + } end function paragraphs.calculatedelta(n,width,delta,atleft,islocal,followshape,area) diff --git a/tex/context/base/mkiv/typo-mar.lua b/tex/context/base/mkiv/typo-mar.lua index 19507f7f5..7e69162a9 100644 --- a/tex/context/base/mkiv/typo-mar.lua +++ b/tex/context/base/mkiv/typo-mar.lua @@ -59,8 +59,6 @@ local v_paragraph = variables.paragraph local v_line = variables.line local nuts = nodes.nuts -local nodepool = nuts.pool - local tonode = nuts.tonode local hpack_nodes = nuts.hpack @@ -82,7 +80,6 @@ local setshift = nuts.setshift local getwidth = nuts.getwidth local setwidth = nuts.setwidth local getheight = nuts.getheight -local getprop = nuts.getprop local setattrlist = nuts.setattrlist @@ -103,10 +100,9 @@ local userdefined_code = whatsitcodes.userdefined local nodepool = nuts.pool -local new_usernode = nodepool.usernode local new_hlist = nodepool.hlist - -local lateluafunction = nodepool.lateluafunction +local new_usernode = nodepool.usernode +local latelua = nodepool.latelua local texgetdimen = tex.getdimen local texgetcount = tex.getcount @@ -204,7 +200,6 @@ end function margins.save(t) setmetatable(t,defaults) local content = takebox(t.number) - setprop(content,"specialcontent","margindata") local location = t.location local category = t.category local inline = t.inline @@ -220,6 +215,7 @@ function margins.save(t) report_margindata("ignoring empty margin data %a",location or "unknown") return end + setprop(content,"specialcontent","margindata") local store if inline then store = inlinestore @@ -450,25 +446,29 @@ end -- anchors are only set for lines that have a note -local function sa(tag) -- maybe l/r keys ipv left/right keys - local p = cache[tag] +local function sa(specification) -- maybe l/r keys ipv left/right keys + local tag = specification.tag + local p = cache[tag] if p then if trace_marginstack then report_margindata("updating anchor %a",tag) end p.p = true p.y = true - setposition('md:v',tag,p) + -- maybe settobesaved first + setposition("md:v",tag,p) cache[tag] = nil -- do this later, per page a cleanup end end local function setanchor(v_anchor) -- freezes the global here - return lateluafunction(function() sa(v_anchor) end) + return latelua { action = sa, tag = v_anchor } end -local function aa(tag,n) -- maybe l/r keys ipv left/right keys - local p = jobpositions.gettobesaved('md:v',tag) +local function aa(specification) -- maybe l/r keys ipv left/right keys + local tag = specification.tag + local n = specification.n + local p = jobpositions.gettobesaved('md:v',tag) if p then if trace_marginstack then report_margindata("updating injected %a",tag) @@ -485,7 +485,7 @@ local function aa(tag,n) -- maybe l/r keys ipv left/right keys end local function addtoanchor(v_anchor,n) -- freezes the global here - return lateluafunction(function() aa(v_anchor,n) end) + return latelua { action = aa, tag = v_anchor, n = n } end local function markovershoot(current) -- todo: alleen als offset > line @@ -589,7 +589,7 @@ local function inject(parent,head,candidate) elseif previous == current then firstonstack = false elseif ap and ac and ap.p == ac.p then - local distance = ap.y - ac.y + local distance = (ap.y or 0) - (ac.y or 0) if trace_margindata then report_margindata("distance %p",distance) end @@ -680,7 +680,7 @@ local function inject(parent,head,candidate) setwidth(box,0) -- not needed when wrapped -- if isstacked then - setlink(box,addtoanchor(v_anchor,nofinjected)) + setlink(box,addtoanchor(v_anchors,nofinjected)) box = new_hlist(box) -- set height / depth ? end @@ -733,7 +733,7 @@ local function flushinline(parent,head) -- for now we also check for inline+yes/continue, maybe someday no such check -- will happen; we can assume most inlines are one line heigh; also this -- together feature can become optional - registertogether(tonode(parent),room) -- !! tonode + registertogether(parent,room) end end end @@ -768,7 +768,7 @@ local function flushed(scope,parent) -- current is hlist continue = continue or con nofstored = nofstored - 1 if room then - registertogether(tonode(parent),room) -- !! tonode + registertogether(parent,room) end else break diff --git a/tex/context/base/mkiv/util-deb.lua b/tex/context/base/mkiv/util-deb.lua index 6932e8804..bd94b6d01 100644 --- a/tex/context/base/mkiv/util-deb.lua +++ b/tex/context/base/mkiv/util-deb.lua @@ -30,7 +30,15 @@ local names = { } local initialize = false -if not (FFISUPPORTED and ffi) then +if lua.getpreciseticks then + + initialize = function() + ticks = lua.getpreciseticks + seconds = lua.getpreciseseconds + initialize = false + end + +elseif not (FFISUPPORTED and ffi) then -- we have no precise timer diff --git a/tex/context/base/mkiv/util-env.lua b/tex/context/base/mkiv/util-env.lua index cadfb7ac5..dde765874 100644 --- a/tex/context/base/mkiv/util-env.lua +++ b/tex/context/base/mkiv/util-env.lua @@ -150,8 +150,11 @@ environment.sortedflags = nil -- context specific arguments (in order not to confuse the engine) function environment.initializearguments(arg) - local arguments, files = { }, { } - environment.arguments, environment.files, environment.sortedflags = arguments, files, nil + local arguments = { } + local files = { } + environment.arguments = arguments + environment.files = files + environment.sortedflags = nil for index=1,#arg do local argument = arg[index] if index > 0 then @@ -170,6 +173,11 @@ function environment.initializearguments(arg) end end end + if not environment.ownname then + if os.selfpath and os.selfname then + environment.ownname = file.addsuffix(file.join(os.selfpath,os.selfname),"lua") + end + end environment.ownname = file.reslash(environment.ownname or arg[0] or 'unknown.lua') end diff --git a/tex/context/base/mkiv/util-fil.lua b/tex/context/base/mkiv/util-fil.lua index 9f96a01b9..79af27743 100644 --- a/tex/context/base/mkiv/util-fil.lua +++ b/tex/context/base/mkiv/util-fil.lua @@ -14,10 +14,14 @@ local char = string.char -- flac files). In Lua 5.3 we can probably do this better. Some code will move -- here. +-- We could comment those that are in fio and sio. + utilities = utilities or { } local files = { } utilities.files = files +-- we could have a gc method that closes but files auto close anyway + local zerobased = { } function files.open(filename,zb) @@ -249,7 +253,7 @@ end if bit32 then - local rshift = bit32.rshift + local rshift = bit32.rshift function files.writecardinal2(f,n) local a = char(n % 256) @@ -258,6 +262,35 @@ if bit32 then f:write(b,a) end + function files.writecardinal4(f,n) + local a = char(n % 256) + n = rshift(n,8) + local b = char(n % 256) + n = rshift(n,8) + local c = char(n % 256) + n = rshift(n,8) + local d = char(n % 256) + f:write(d,c,b,a) + end + + function files.writecardinal2le(f,n) + local a = char(n % 256) + n = rshift(n,8) + local b = char(n % 256) + f:write(a,b) + end + + function files.writecardinal4le(f,n) + local a = char(n % 256) + n = rshift(n,8) + local b = char(n % 256) + n = rshift(n,8) + local c = char(n % 256) + n = rshift(n,8) + local d = char(n % 256) + f:write(a,b,c,d) + end + else local floor = math.floor @@ -269,17 +302,35 @@ else f:write(b,a) end -end + function files.writecardinal4(f,n) + local a = char(n % 256) + n = floor(n/256) + local b = char(n % 256) + n = floor(n/256) + local c = char(n % 256) + n = floor(n/256) + local d = char(n % 256) + f:write(d,c,b,a) + end + + function files.writecardinal2le(f,n) + local a = char(n % 256) + n = floor(n/256) + local b = char(n % 256) + f:write(a,b) + end + + function files.writecardinal4le(f,n) + local a = char(n % 256) + n = floor(n/256) + local b = char(n % 256) + n = floor(n/256) + local c = char(n % 256) + n = floor(n/256) + local d = char(n % 256) + f:write(a,b,c,d) + end -function files.writecardinal4(f,n) - local a = char(n % 256) - n = rshift(n,8) - local b = char(n % 256) - n = rshift(n,8) - local c = char(n % 256) - n = rshift(n,8) - local d = char(n % 256) - f:write(d,c,b,a) end function files.writestring(f,s) @@ -292,30 +343,42 @@ end if fio and fio.readcardinal1 then - files.readcardinal1 = fio.readcardinal1 - files.readcardinal2 = fio.readcardinal2 - files.readcardinal3 = fio.readcardinal3 - files.readcardinal4 = fio.readcardinal4 - files.readinteger1 = fio.readinteger1 - files.readinteger2 = fio.readinteger2 - files.readinteger3 = fio.readinteger3 - files.readinteger4 = fio.readinteger4 - files.readfixed2 = fio.readfixed2 - files.readfixed4 = fio.readfixed4 - files.read2dot14 = fio.read2dot14 - files.setposition = fio.setposition - files.getposition = fio.getposition - - files.readbyte = files.readcardinal1 - files.readsignedbyte = files.readinteger1 - files.readcardinal = files.readcardinal1 - files.readinteger = files.readinteger1 - - local skipposition = fio.skipposition - files.skipposition = skipposition - - files.readbytes = fio.readbytes - files.readbytetable = fio.readbytetable + files.readcardinal1 = fio.readcardinal1 + files.readcardinal2 = fio.readcardinal2 + files.readcardinal3 = fio.readcardinal3 + files.readcardinal4 = fio.readcardinal4 + + files.readcardinal1le = fio.readcardinal1le or files.readcardinal1le + files.readcardinal2le = fio.readcardinal2le or files.readcardinal2le + files.readcardinal3le = fio.readcardinal3le or files.readcardinal3le + files.readcardinal4le = fio.readcardinal4le or files.readcardinal4le + + files.readinteger1 = fio.readinteger1 + files.readinteger2 = fio.readinteger2 + files.readinteger3 = fio.readinteger3 + files.readinteger4 = fio.readinteger4 + + files.readinteger1le = fio.readinteger1le or files.readinteger1le + files.readinteger2le = fio.readinteger2le or files.readinteger2le + files.readinteger3le = fio.readinteger3le or files.readinteger3le + files.readinteger4le = fio.readinteger4le or files.readinteger4le + + files.readfixed2 = fio.readfixed2 + files.readfixed4 = fio.readfixed4 + files.read2dot14 = fio.read2dot14 + files.setposition = fio.setposition + files.getposition = fio.getposition + + files.readbyte = files.readcardinal1 + files.readsignedbyte = files.readinteger1 + files.readcardinal = files.readcardinal1 + files.readinteger = files.readinteger1 + + local skipposition = fio.skipposition + files.skipposition = skipposition + + files.readbytes = fio.readbytes + files.readbytetable = fio.readbytetable function files.skipshort(f,n) skipposition(f,2*(n or 1)) @@ -327,6 +390,30 @@ if fio and fio.readcardinal1 then end +if fio and fio.writecardinal1 then + + files.writecardinal1 = fio.writecardinal1 + files.writecardinal2 = fio.writecardinal2 + files.writecardinal3 = fio.writecardinal3 + files.writecardinal4 = fio.writecardinal4 + + files.writecardinal1le = fio.writecardinal1le + files.writecardinal2le = fio.writecardinal2le + files.writecardinal3le = fio.writecardinal3le + files.writecardinal4le = fio.writecardinal4le + + files.writeinteger1 = fio.writeinteger1 or fio.writecardinal1 + files.writeinteger2 = fio.writeinteger2 or fio.writecardinal2 + files.writeinteger3 = fio.writeinteger3 or fio.writecardinal3 + files.writeinteger4 = fio.writeinteger4 or fio.writecardinal4 + + files.writeinteger1le = files.writeinteger1le or fio.writecardinal1le + files.writeinteger2le = files.writeinteger2le or fio.writecardinal2le + files.writeinteger3le = files.writeinteger3le or fio.writecardinal3le + files.writeinteger4le = files.writeinteger4le or fio.writecardinal4le + +end + if fio and fio.readcardinaltable then files.readcardinaltable = fio.readcardinaltable diff --git a/tex/context/base/mkiv/util-fmt.lua b/tex/context/base/mkiv/util-fmt.lua index 371a5dfce..fe80c6420 100644 --- a/tex/context/base/mkiv/util-fmt.lua +++ b/tex/context/base/mkiv/util-fmt.lua @@ -35,10 +35,17 @@ function formatters.formatcolumns(result,between) for j=1,n do local rj = r[j] local tj = type(rj) +-- if tj == "number" then +-- numbers[j] = true +-- end +-- if tj ~= "string" then +-- rj = tostring(rj) +-- r[j] = rj +-- end if tj == "number" then numbers[j] = true - end - if tj ~= "string" then + rj = tostring(rj) + elseif tj ~= "string" then rj = tostring(rj) r[j] = rj end diff --git a/tex/context/base/mkiv/util-prs.lua b/tex/context/base/mkiv/util-prs.lua index 891f1096a..3154bf6c2 100644 --- a/tex/context/base/mkiv/util-prs.lua +++ b/tex/context/base/mkiv/util-prs.lua @@ -24,8 +24,8 @@ local sortedhash = table.sortedhash local sortedkeys = table.sortedkeys local tohash = table.tohash -local hashes = { } -utilities.parsers.hashes = hashes +local hashes = { } +parsers.hashes = hashes -- we share some patterns local digit = R("09") @@ -308,7 +308,9 @@ end function parsers.hash_to_string(h,separator,yes,no,strict,omit) if h then - local t, tn, s = { }, 0, sortedkeys(h) + local t = { } + local tn = 0 + local s = sortedkeys(h) omit = omit and tohash(omit) for i=1,#s do local key = s[i] @@ -361,7 +363,7 @@ end local pattern = Cf(Ct("") * Cg(C((1-S(", "))^1) * S(", ")^0 * Cc(true))^1,rawset) -function utilities.parsers.settings_to_set(str) +function parsers.settings_to_set(str) return str and lpegmatch(pattern,str) or { } end @@ -374,7 +376,8 @@ end) getmetatable(hashes.settings_to_set).__mode = "kv" -- could be an option (maybe sharing makes sense) function parsers.simple_hash_to_string(h, separator) - local t, tn = { }, 0 + local t = { } + local tn = 0 for k, v in sortedhash(h) do if v then tn = tn + 1 @@ -390,13 +393,13 @@ local str = Cs(lpegpatterns.unquoted) + C((1-whitespace-equal)^1) local setting = Cf( Carg(1) * (whitespace^0 * Cg(str * whitespace^0 * (equal * whitespace^0 * str + Cc(""))))^1,rawset) local splitter = setting^1 -function utilities.parsers.options_to_hash(str,target) +function parsers.options_to_hash(str,target) return str and lpegmatch(splitter,str,1,target or { }) or { } end local splitter = lpeg.tsplitat(" ") -function utilities.parsers.options_to_array(str) +function parsers.options_to_array(str) return str and lpegmatch(splitter,str) or { } end @@ -415,7 +418,8 @@ local function repeater(n,str) if n == 1 then return unpack(s) else - local t, tn = { }, 0 + local t = { } + local tn = 0 for i=1,n do for j=1,#s do tn = tn + 1 @@ -557,7 +561,7 @@ end -- and this is a slightly patched version of a version posted by Philipp Gesang --- local mycsvsplitter = utilities.parsers.rfc4180splitter() +-- local mycsvsplitter = parsers.rfc4180splitter() -- local crap = [[ -- first,second,third,fourth @@ -597,11 +601,11 @@ function parsers.rfc4180splitter(specification) end end --- utilities.parsers.stepper("1,7-",9,function(i) print(">>>",i) end) --- utilities.parsers.stepper("1-3,7,8,9") --- utilities.parsers.stepper("1-3,6,7",function(i) print(">>>",i) end) --- utilities.parsers.stepper(" 1 : 3, ,7 ") --- utilities.parsers.stepper("1:4,9:13,24:*",30) +-- parsers.stepper("1,7-",9,function(i) print(">>>",i) end) +-- parsers.stepper("1-3,7,8,9") +-- parsers.stepper("1-3,6,7",function(i) print(">>>",i) end) +-- parsers.stepper(" 1 : 3, ,7 ") +-- parsers.stepper("1:4,9:13,24:*",30) local function ranger(first,last,n,action) if not first then @@ -654,7 +658,7 @@ function parsers.unittoxml(str) return lpegmatch(pattern,str) end --- print(utilities.parsers.unittotex("10^-32 %"),utilities.parsers.unittoxml("10^32 %")) +-- print(parsers.unittotex("10^-32 %"),utilities.parsers.unittoxml("10^32 %")) local cache = { } local spaces = lpegpatterns.space^0 @@ -670,7 +674,7 @@ end) local commalistiterator = cache[","] -function utilities.parsers.iterator(str,separator) +function parsers.iterator(str,separator) local n = #str if n == 0 then return dummy @@ -689,7 +693,7 @@ function utilities.parsers.iterator(str,separator) end end --- for s in utilities.parsers.iterator("a b c,b,c") do +-- for s in parsers.iterator("a b c,b,c") do -- print(s) -- end @@ -721,7 +725,7 @@ local name = C((1-S(", "))^1) local parser = (Carg(1) * name / initialize) * (S(", ")^1 * (Carg(1) * name / fetch))^0 local merge = Cf(parser,process) -function utilities.parsers.mergehashes(hash,list) +function parsers.mergehashes(hash,list) return lpegmatch(merge,list,1,hash) end @@ -731,9 +735,9 @@ end -- cc = { epsilon = 3 }, -- } -- --- inspect(utilities.parsers.mergehashes(t,"aa, bb, cc")) +-- inspect(parsers.mergehashes(t,"aa, bb, cc")) -function utilities.parsers.runtime(time) +function parsers.runtime(time) if not time then time = os.runtime() end @@ -755,7 +759,7 @@ local token = lbrace * C((1-rbrace)^1) * rbrace + C(anything^1) local pattern = spacing * (method * spacing * apply + Carg(1)) * spacing * token -function utilities.parsers.splitmethod(str,default) +function parsers.splitmethod(str,default) if str then return lpegmatch(pattern,str,1,default or false) else @@ -763,9 +767,38 @@ function utilities.parsers.splitmethod(str,default) end end --- print(utilities.parsers.splitmethod(" foo -> {bar} ")) --- print(utilities.parsers.splitmethod("foo->{bar}")) --- print(utilities.parsers.splitmethod("foo->bar")) --- print(utilities.parsers.splitmethod("foo")) --- print(utilities.parsers.splitmethod("{foo}")) --- print(utilities.parsers.splitmethod()) +-- print(parsers.splitmethod(" foo -> {bar} ")) +-- print(parsers.splitmethod("foo->{bar}")) +-- print(parsers.splitmethod("foo->bar")) +-- print(parsers.splitmethod("foo")) +-- print(parsers.splitmethod("{foo}")) +-- print(parsers.splitmethod()) + +local p_year = lpegpatterns.digit^4 / tonumber + +local pattern = Cf( Ct("") * + ( + ( Cg(Cc("year") * p_year) + * S("-/") * Cg(Cc("month") * cardinal) + * S("-/") * Cg(Cc("day") * cardinal) + ) + + ( Cg(Cc("day") * cardinal) + * S("-/") * Cg(Cc("month") * cardinal) + * S("-/") * Cg(Cc("year") * p_year) + ) + ) + * P(" ") * Cg(Cc("hour") * cardinal) + * P(":") * Cg(Cc("min") * cardinal) + * (P(":") * Cg(Cc("sec") * cardinal))^-1 +, rawset) + +lpegpatterns.splittime = pattern + +function parsers.totime(str) + return lpegmatch(pattern,str) +end + +-- print(os.time(parsers.totime("2019-03-05 12:12:12"))) +-- print(os.time(parsers.totime("2019/03/05 12:12:12"))) +-- print(os.time(parsers.totime("05-03-2019 12:12:12"))) +-- print(os.time(parsers.totime("05/03/2019 12:12:12"))) diff --git a/tex/context/base/mkiv/util-sac.lua b/tex/context/base/mkiv/util-sac.lua index dc8ba72f1..976989a77 100644 --- a/tex/context/base/mkiv/util-sac.lua +++ b/tex/context/base/mkiv/util-sac.lua @@ -29,6 +29,12 @@ function streams.openstring(f,zerobased) end end +function streams.getstring(f) + if f then + return f[1] + end +end + function streams.close() -- dummy end @@ -137,7 +143,7 @@ function streams.readcardinal2(f) return 0x100 * a + b end -function streams.readcardinal2LE(f) +function streams.readcardinal2le(f) local i = f[2] local j = i + 1 f[2] = j + 1 @@ -217,6 +223,14 @@ function streams.readcardinal4(f) return 0x1000000 * a + 0x10000 * b + 0x100 * c + d end +function streams.readcardinal4le(f) + local i = f[2] + local j = i + 3 + f[2] = j + 1 + local d, c, b, a = byte(f[1],i,j) + return 0x1000000 * a + 0x10000 * b + 0x100 * c + d +end + function streams.readinteger4(f) local i = f[2] local j = i + 3 diff --git a/tex/context/base/mkiv/util-soc-imp-copas.lua b/tex/context/base/mkiv/util-soc-imp-copas.lua index 3e66e5888..1268613d1 100644 --- a/tex/context/base/mkiv/util-soc-imp-copas.lua +++ b/tex/context/base/mkiv/util-soc-imp-copas.lua @@ -50,6 +50,8 @@ local copas = { report = report, + trace = false, + } local function statushandler(status, ...) @@ -60,7 +62,9 @@ local function statushandler(status, ...) if type(err) == "table" then err = err[1] end - report("error: %s",tostring(err)) + if copas.trace then + report("error: %s",tostring(err)) + end return nil, err end @@ -76,7 +80,9 @@ function socket.newtry(finalizer) if not status then local detail = select(2,...) pcall(finalizer,detail) - report("error: %s",tostring(detail)) + if copas.trace then + report("error: %s",tostring(detail)) + end return end return ... diff --git a/tex/context/base/mkiv/util-soc-imp-mime.lua b/tex/context/base/mkiv/util-soc-imp-mime.lua index 4b5d2baff..7a5cef27b 100644 --- a/tex/context/base/mkiv/util-soc-imp-mime.lua +++ b/tex/context/base/mkiv/util-soc-imp-mime.lua @@ -3,8 +3,8 @@ local type, tostring = type, tostring -local mime = require("mime.core") -local ltn12 = ltn12 or require("ltn12") +local mime = mime or package.loaded.mime or require("mime.core") +local ltn12 = ltn12 or package.loaded.ltn12 or require("ltn12") local filtercycle = ltn12.filter.cycle diff --git a/tex/context/base/mkiv/util-soc-imp-socket.lua b/tex/context/base/mkiv/util-soc-imp-socket.lua index 3da155749..d1486f8f8 100644 --- a/tex/context/base/mkiv/util-soc-imp-socket.lua +++ b/tex/context/base/mkiv/util-soc-imp-socket.lua @@ -5,7 +5,7 @@ local type, tostring, setmetatable = type, tostring, setmetatable local min = math.min local format = string.format -local socket = require("socket.core") +local socket = socket or package.loaded.socket or require("socket.core") local connect = socket.connect local tcp4 = socket.tcp4 diff --git a/tex/context/base/mkiv/util-str.lua b/tex/context/base/mkiv/util-str.lua index 713c294eb..5470c2fd6 100644 --- a/tex/context/base/mkiv/util-str.lua +++ b/tex/context/base/mkiv/util-str.lua @@ -14,7 +14,6 @@ local format, gsub, rep, sub, find = string.format, string.gsub, string.rep, str local load, dump = load, string.dump local tonumber, type, tostring, next, setmetatable = tonumber, type, tostring, next, setmetatable local unpack, concat = table.unpack, table.concat -local unpack, concat = table.unpack, table.concat local P, V, C, S, R, Ct, Cs, Cp, Carg, Cc = lpeg.P, lpeg.V, lpeg.C, lpeg.S, lpeg.R, lpeg.Ct, lpeg.Cs, lpeg.Cp, lpeg.Carg, lpeg.Cc local patterns, lpegmatch = lpeg.patterns, lpeg.match local utfchar, utfbyte, utflen = utf.char, utf.byte, utf.len @@ -610,8 +609,8 @@ local environment = { formattednumber = number.formatted, sparseexponent = number.sparseexponent, formattedfloat = number.formattedfloat, - stripzero = lpeg.patterns.stripzero, - stripzeros = lpeg.patterns.stripzeros, + stripzero = patterns.stripzero, + stripzeros = patterns.stripzeros, FORMAT = string.f9, } @@ -745,7 +744,7 @@ end local format_k = function(b,a) -- slow n = n + 1 - return format("formattedfloat(a%s,%i,%i)",n,b or 0, a or 0) + return format("formattedfloat(a%s,%s,%s)",n,b or 0,a or 0) end local format_g = function(f) @@ -1329,9 +1328,9 @@ patterns.luaquoted = Cs(Cc('"') * ((1-S('"\n'))^1 + P('"')/'\\"' + P('\n')/'\\n" -- escaping by lpeg is faster for strings without quotes, slower on a string with quotes, but -- faster again when other q-escapables are found (the ones we don't need to escape) -add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],{ xmlescape = lpeg.patterns.xmlescape }) -add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape = lpeg.patterns.texescape }) -add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape = lpeg.patterns.luaescape }) +add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],{ xmlescape = patterns.xmlescape }) +add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape = patterns.texescape }) +add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape = patterns.luaescape }) -- -- yes or no: -- @@ -1409,3 +1408,31 @@ local f_16_16 = formatters["%0.5N"] function number.to16dot16(n) return f_16_16(n/65536.0) end + +-- + +if not string.explode then + + local tsplitat = lpeg.tsplitat + + local p_utf = patterns.utf8character + local p_check = C(p_utf) * (P("+") * Cc(true))^0 + local p_split = Ct(C(p_utf)^0) + local p_space = Ct((C(1-P(" ")^1) + P(" ")^1)^0) + + function string.explode(str,symbol) + if symbol == "" then + return lpegmatch(p_split,str) + elseif symbol then + local a, b = lpegmatch(p_check,symbol) + if b then + return lpegmatch(tsplitat(P(a)^1),str) + else + return lpegmatch(tsplitat(a),str) + end + else + return lpegmatch(p_space,str) + end + end + +end diff --git a/tex/context/base/mkiv/util-tab.lua b/tex/context/base/mkiv/util-tab.lua index ed4cef996..2f425cca3 100644 --- a/tex/context/base/mkiv/util-tab.lua +++ b/tex/context/base/mkiv/util-tab.lua @@ -22,7 +22,8 @@ local utftoeight = utf.toeight local splitter = lpeg.tsplitat(".") function utilities.tables.definetable(target,nofirst,nolast) -- defines undefined tables - local composed, t = nil, { } + local composed = nil + local t = { } local snippets = lpegmatch(splitter,target) for i=1,#snippets - (nolast and 1 or 0) do local name = snippets[i] @@ -310,7 +311,8 @@ function tables.encapsulate(core,capsule,protect) end end --- best keep [%q] keys (as we have some in older applications i.e. saving user data +-- best keep [%q] keys (as we have some in older applications i.e. saving user data (otherwise +-- we also need to check for reserved words) local f_hashed_string = formatters["[%q]=%q,"] local f_hashed_number = formatters["[%q]=%s,"] @@ -334,7 +336,6 @@ function table.fastserialize(t,prefix) local r = { type(prefix) == "string" and prefix or "return" } local m = 1 - local function fastserialize(t,outer) -- no mixes local n = #t m = m + 1 @@ -654,19 +655,20 @@ local function serialize(root,name,specification) -- we could check for k (index) being number (cardinal) if root and next(root) ~= nil then local first = nil - local last = 0 - last = #root - for k=1,last do - if rawget(root,k) == nil then - -- if root[k] == nil then - last = k - 1 - break - end - end + local last = #root if last > 0 then - first = 1 + for k=1,last do + if rawget(root,k) == nil then + -- if root[k] == nil then + last = k - 1 + break + end + end + if last > 0 then + first = 1 + end end - local sk = sortedkeys(root) -- inline fast version?\ + local sk = sortedkeys(root) for i=1,#sk do local k = sk[i] local v = root[k] diff --git a/tex/context/base/mkiv/util-zip.lua b/tex/context/base/mkiv/util-zip.lua new file mode 100644 index 000000000..7d252a74f --- /dev/null +++ b/tex/context/base/mkiv/util-zip.lua @@ -0,0 +1,549 @@ +if not modules then modules = { } end modules ['util-zip'] = { + version = 1.001, + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- This module is mostly meant for relative simple zip and unzip tasks. We can read +-- and write zip files but with limitations. Performance is quite good and it makes +-- us independent of zip tools, which (for some reason) are not always installed. +-- +-- This is an lmtx module and at some point will be lmtx only but for a while we +-- keep some hybrid functionality. + +local type, tostring, tonumber = type, tostring, tonumber +local sort = table.sort + +local find, format, sub, gsub = string.find, string.format, string.sub, string.gsub +local osdate, ostime = os.date, os.time +local ioopen = io.open +local loaddata, savedata = io.loaddata, io.savedata +local filejoin, isdir, dirname, mkdirs = file.join, lfs.isdir, file.dirname, dir.mkdirs + +local files = utilities.files +local openfile = files.open +local closefile = files.close +local readstring = files.readstring +local readcardinal2 = files.readcardinal2le +local readcardinal4 = files.readcardinal4le +local setposition = files.setposition +local getposition = files.getposition + +local band = bit32.band +local rshift = bit32.rshift +local lshift = bit32.lshift + +local decompress, calculatecrc + +if flate then + + decompress = flate.flate_decompress + calculatecrc = flate.update_crc32 + +else + + local zlibdecompress = zlib.decompress + local zlibchecksum = zlib.crc32 + + decompress = function(source,targetsize) + local target = zlibdecompress(source,-15) + if target then + return target + else + return false, 1 + end + end + + calculatecrc = function(buffer,initial) + return zlibchecksum(initial or 0,buffer) + end + +end + +local zipfiles = { } +utilities.zipfiles = zipfiles + +local openzipfile, closezipfile, unzipfile, foundzipfile, getziphash, getziplist do + + function openzipfile(name) + return { + name = name, + handle = openfile(name,0), + } + end + + local function collect(z) + if not z.list then + local list = { } + local hash = { } + local position = 0 + local index = 0 + local handle = z.handle + while true do + setposition(handle,position) + local signature = readstring(handle,4) + if signature == "PK\3\4" then + -- [local file header 1] + -- [encryption header 1] + -- [file data 1] + -- [data descriptor 1] + local version = readcardinal2(handle) + local flag = readcardinal2(handle) + local method = readcardinal2(handle) + local filetime = readcardinal2(handle) + local filedate = readcardinal2(handle) + local crc32 = readcardinal4(handle) + local compressed = readcardinal4(handle) + local uncompressed = readcardinal4(handle) + local namelength = readcardinal2(handle) + local extralength = readcardinal2(handle) + local filename = readstring(handle,namelength) + local descriptor = band(flag,8) ~= 0 + local encrypted = band(flag,1) ~= 0 + local acceptable = method == 0 or method == 8 + -- 30 bytes of header including the signature + local skipped = 0 + local size = 0 + if encrypted then + size = readcardinal2(handle) + skipbytes(size) + skipped = skipped + size + 2 + skipbytes(8) + skipped = skipped + 8 + size = readcardinal2(handle) + skipbytes(size) + skipped = skipped + size + 2 + size = readcardinal4(handle) + skipbytes(size) + skipped = skipped + size + 4 + size = readcardinal2(handle) + skipbytes(size) + skipped = skipped + size + 2 + end + position = position + 30 + namelength + extralength + skipped + if descriptor then + setposition(handle,position + compressed) + crc32 = readcardinal4(handle) + compressed = readcardinal4(handle) + uncompressed = readcardinal4(handle) + end + if acceptable then + index = index + 1 + local data = { + filename = filename, + index = index, + position = position, + method = method, + compressed = compressed, + uncompressed = uncompressed, + crc32 = crc32, + encrypted = encrypted, + } + hash[filename] = data + list[index] = data + else + -- maybe a warning when encrypted + end + position = position + compressed + else + break + end + z.list = list + z.hash = hash + end + end + end + + function getziplist(z) + local list = z.list + if not list then + collect(z) + end + return z.list + end + + function getziphash(z) + local hash = z.hash + if not hash then + collect(z) + end + return z.hash + end + + function foundzipfile(z,name) + return getziphash(z)[name] + end + + function closezipfile(z) + local f = z.handle + if f then + closefile(f) + z.handle = nil + end + end + + function unzipfile(z,filename,check) + local hash = z.hash + if not hash then + hash = zipfiles.hash(z) + end + local data = hash[filename] -- normalize + if not data then + -- lower and cleanup + -- only name + end + if data then + local handle = z.handle + local position = data.position + local compressed = data.compressed + if compressed > 0 then + setposition(handle,position) + local result = readstring(handle,compressed) + if data.method == 8 then + result = decompress(result,data.uncompressed) + end + if check and data.crc32 ~= calculatecrc(result) then + print("checksum mismatch") + return "" + end + return result + else + return "" + end + end + end + + zipfiles.open = openzipfile + zipfiles.close = closezipfile + zipfiles.unzip = unzipfile + zipfiles.hash = getziphash + zipfiles.list = getziplist + zipfiles.found = foundzipfile + +end + +if flate then do + + local writecardinal1 = files.writebyte + local writecardinal2 = files.writecardinal2le + local writecardinal4 = files.writecardinal4le + + local logwriter = logs.writer + + local globpattern = dir.globpattern + local compress = flate.flate_compress + local checksum = flate.update_crc32 + + -- local function fromdostime(dostime,dosdate) + -- return ostime { + -- year = (dosdate >> 9) + 1980, -- 25 .. 31 + -- month = (dosdate >> 5) & 0x0F, -- 21 .. 24 + -- day = (dosdate ) & 0x1F, -- 16 .. 20 + -- hour = (dostime >> 11) , -- 11 .. 15 + -- min = (dostime >> 5) & 0x3F, -- 5 .. 10 + -- sec = (dostime ) & 0x1F, -- 0 .. 4 + -- } + -- end + -- + -- local function todostime(time) + -- local t = osdate("*t",time) + -- return + -- ((t.year - 1980) << 9) + (t.month << 5) + t.day, + -- (t.hour << 11) + (t.min << 5) + (t.sec >> 1) + -- end + + local function fromdostime(dostime,dosdate) + return ostime { + year = rshift(dosdate, 9) + 1980, -- 25 .. 31 + month = band(rshift(dosdate, 5), 0x0F), -- 21 .. 24 + day = band( (dosdate ), 0x1F), -- 16 .. 20 + hour = band(rshift(dostime,11) ), -- 11 .. 15 + min = band(rshift(dostime, 5), 0x3F), -- 5 .. 10 + sec = band( (dostime ), 0x1F), -- 0 .. 4 + } + end + + local function todostime(time) + local t = osdate("*t",time) + return + lshift(t.year - 1980, 9) + lshift(t.month,5) + t.day, + lshift(t.hour ,11) + lshift(t.min ,5) + rshift(t.sec,1) + end + + local function openzip(filename,level,comment,verbose) + local f = ioopen(filename,"wb") + if f then + return { + filename = filename, + handle = f, + list = { }, + level = tonumber(level) or 3, + comment = tostring(comment), + verbose = verbose, + uncompressed = 0, + compressed = 0, + } + end + end + + local function writezip(z,name,data,level,time) + local f = z.handle + local list = z.list + local level = tonumber(level) or z.level or 3 + local method = 8 + local zipped = compress(data,level) + local checksum = checksum(data) + local verbose = z.verbose + -- + if not zipped then + method = 0 + zipped = data + end + -- + local start = f:seek() + local compressed = #zipped + local uncompressed = #data + -- + z.compressed = z.compressed + compressed + z.uncompressed = z.uncompressed + uncompressed + -- + if verbose then + local pct = 100 * compressed/uncompressed + if pct >= 100 then + logwriter(format("%10i %s",uncompressed,name)) + else + logwriter(format("%10i %02.1f %s",uncompressed,pct,name)) + end + end + -- + f:write("\x50\x4b\x03\x04") -- PK.. 0x04034b50 + -- + writecardinal2(f,0) -- minimum version + writecardinal2(f,0) -- flag + writecardinal2(f,method) -- method + writecardinal2(f,0) -- time + writecardinal2(f,0) -- date + writecardinal4(f,checksum) -- crc32 + writecardinal4(f,compressed) -- compressed + writecardinal4(f,uncompressed) -- uncompressed + writecardinal2(f,#name) -- namelength + writecardinal2(f,0) -- extralength + -- + f:write(name) -- name + f:write(zipped) + -- + list[#list+1] = { #zipped, #data, name, checksum, start, time or 0 } + end + + local function closezip(z) + local f = z.handle + local list = z.list + local comment = z.comment + local verbose = z.verbose + local count = #list + local start = f:seek() + -- + for i=1,count do + local l = list[i] + local compressed = l[1] + local uncompressed = l[2] + local name = l[3] + local checksum = l[4] + local start = l[5] + local time = l[6] + local date, time = todostime(time) + f:write('\x50\x4b\x01\x02') + writecardinal2(f,0) -- version made by + writecardinal2(f,0) -- version needed to extract + writecardinal2(f,0) -- flags + writecardinal2(f,8) -- method + writecardinal2(f,time) -- time + writecardinal2(f,date) -- date + writecardinal4(f,checksum) -- crc32 + writecardinal4(f,compressed) -- compressed + writecardinal4(f,uncompressed) -- uncompressed + writecardinal2(f,#name) -- namelength + writecardinal2(f,0) -- extralength + writecardinal2(f,0) -- commentlength + writecardinal2(f,0) -- nofdisks -- ? + writecardinal2(f,0) -- internal attr (type) + writecardinal4(f,0) -- external attr (mode) + writecardinal4(f,start) -- local offset + f:write(name) -- name + end + -- + local stop = f:seek() + local size = stop - start + -- + f:write('\x50\x4b\x05\x06') + writecardinal2(f,0) -- disk + writecardinal2(f,0) -- disks + writecardinal2(f,count) -- entries + writecardinal2(f,count) -- entries + writecardinal4(f,size) -- dir size + writecardinal4(f,start) -- dir offset + if type(comment) == "string" and comment ~= "" then + writecardinal2(f,#comment) -- comment length + f:write(comment) -- comemnt + else + writecardinal2(f,0) + end + -- + if verbose then + local compressed = z.compressed + local uncompressed = z.uncompressed + local filename = z.filename + -- + local pct = 100 * compressed/uncompressed + logwriter("") + if pct >= 100 then + logwriter(format("%10i %s",uncompressed,filename)) + else + logwriter(format("%10i %02.1f %s",uncompressed,pct,filename)) + end + end + -- + f:close() + end + + local function zipdir(zipname,path,level,verbose) + if type(zipname) == "table" then + verbose = zipname.verbose + level = zipname.level + path = zipname.path + zipname = zipname.zipname + end + if not zipname or zipname == "" then + return + end + if not path or path == "" then + path = "." + end + if not isdir(path) then + return + end + path = gsub(path,"\\+","/") + path = gsub(path,"/+","/") + local list = { } + local count = 0 + globpattern(path,"",true,function(name,size,time) + count = count + 1 + list[count] = { name, time } + end) + sort(list,function(a,b) + return a[1] < b[1] + end) + local zipf = openzip(zipname,level,comment,verbose) + if zipf then + local p = #path + 2 + for i=1,count do + local li = list[i] + local name = li[1] + local time = li[2] + local data = loaddata(name) + local name = sub(name,p,#name) + writezip(zipf,name,data,level,time,verbose) + end + closezip(zipf) + end + end + + local function unzipdir(zipname,path,verbose) + if type(zipname) == "table" then + verbose = zipname.verbose + path = zipname.path + zipname = zipname.zipname + end + if not zipname or zipname == "" then + return + end + if not path or path == "" then + path = "." + end + local z = openzipfile(zipname) + if z then + local list = getziplist(z) + if list then + local total = 0 + local count = #list + local step = number.idiv(count,10) + local done = 0 + for i=1,count do + local l = list[i] + local n = l.filename + local d = unzipfile(z,n) -- true for check + local p = filejoin(path,n) + if mkdirs(dirname(p)) then + if verbose == "steps" then + total = total + #d + done = done + 1 + if done >= step then + done = 0 + logwriter(format("%4i files of %4i done, %10i bytes",i,count,total)) + end + elseif verbose then + logwriter(n) + end + savedata(p,d) + end + end + if verbose == "steps" then + logwriter(format("%4i files of %4i done, %10i bytes",count,count,total)) + end + closezipfile(z) + return true + else + closezipfile(z) + end + end + end + + zipfiles.zipdir = zipdir + zipfiles.unzipdir = unzipdir + +end end + +if flate then + + local streams = utilities.streams + local openfile = streams.open + local closestream = streams.close + local setposition = streams.setposition + local getsize = streams.size + local readcardinal4 = streams.readcardinal4le + local getstring = streams.getstring + local decompress = flate.gz_decompress + + -- id1=1 id2=1 method=1 flags=1 mtime=4(le) extra=1 os=1 + -- flags:8 comment=...<nul> flags:4 name=...<nul> flags:2 extra=...<nul> flags:1 crc=2 + -- data:? + -- crc=4 size=4 + + function zipfiles.gunzipfile(filename) + local strm = openfile(filename) + if strm then + setposition(strm,getsize(strm) - 4 + 1) + local size = readcardinal4(strm) + local data = decompress(getstring(strm),size) + closestream(strm) + return data + end + end + +elseif gzip then + + local openfile = gzip.open + + function zipfiles.gunzipfile(filename) + local g = openfile(filename,"rb") + if g then + local d = g:read("*a") + d:close() + return d + end + end + +end + +return zipfiles diff --git a/tex/context/fonts/mkiv/type-imp-plex.mkiv b/tex/context/fonts/mkiv/type-imp-plex.mkiv index 44334bcbd..02de45022 100644 --- a/tex/context/fonts/mkiv/type-imp-plex.mkiv +++ b/tex/context/fonts/mkiv/type-imp-plex.mkiv @@ -45,80 +45,80 @@ \starttypescript [\s!sans,\s!serif,\s!mono] [plex-thin] [\s!name] \setups[\s!font:\s!fallback:\typescriptone] - \definefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-thin] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:plex\typescriptone}-thinitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-light] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-light] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-thin] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:plex\typescriptone}-thinitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-light] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-light] [\s!features=\typescriptprefix{f:plex\typescriptone}] \stoptypescript % extralight \starttypescript [\s!sans,\s!serif,\s!mono] [plex-extralight] [\s!name] \setups[\s!font:\s!fallback:\typescriptone] - \definefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-extralight] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:plex\typescriptone}-extralightitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-regular] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-italic] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-extralight] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:plex\typescriptone}-extralightitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-regular] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-italic] [\s!features=\typescriptprefix{f:plex\typescriptone}] \stoptypescript % light \starttypescript [\s!sans,\s!serif,\s!mono] [plex-light] [\s!name] \setups[\s!font:\s!fallback:\typescriptone] - \definefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-light] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:plex\typescriptone}-lightitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-text] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-textitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-light] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:plex\typescriptone}-lightitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-text] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-textitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] \stoptypescript % regular \starttypescript [\s!sans,\s!serif,\s!mono] [plex] [\s!name] \setups[\s!font:\s!fallback:\typescriptone] - \definefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-regular] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:plex\typescriptone}-italic] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-medium] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-mediumitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-regular] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:plex\typescriptone}-italic] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-medium] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-mediumitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] \stoptypescript % text \starttypescript [\s!sans,\s!serif,\s!mono] [plex-text] [\s!name] \setups[\s!font:\s!fallback:\typescriptone] - \definefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-text] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:plex\typescriptone}-textitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-semibold] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-semibolditalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-text] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:plex\typescriptone}-textitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-semibold] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-semibolditalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] \stoptypescript % medium \starttypescript [\s!sans,\s!serif,\s!mono] [plex-medium] [\s!name] \setups[\s!font:\s!fallback:\typescriptone] - \definefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-medium] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:plex\typescriptone}-mediumitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-bold] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-bolditalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-medium] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:plex\typescriptone}-mediumitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-bold] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-bolditalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] \stoptypescript % semibold \starttypescript [\s!sans,\s!serif,\s!mono] [plex-semibold] [\s!name] \setups[\s!font:\s!fallback:\typescriptone] - \definefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-semibold] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:plex\typescriptone}-semibolditalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-extra] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-extraitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-semibold] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:plex\typescriptone}-semibolditalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-extra] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-extraitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] \stoptypescript % bold \starttypescript [\s!sans,\s!serif,\s!mono] [plex-bold] [\s!name] \setups[\s!font:\s!fallback:\typescriptone] - \definefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-bold] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:plex\typescriptone}-bolditalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-bold] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-bolditalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-bold] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:plex\typescriptone}-bolditalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-bold] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-bolditalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] \stoptypescript % done @@ -144,92 +144,92 @@ \starttypescript [\s!sans,\s!serif,\s!mono] [ibmplex-thin] [\s!name] \setups[\s!font:\s!fallback:\typescriptone] - \definefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-thin] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:plex\typescriptone}-thinitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-text] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-textitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}Widened] [\s!file:\typescriptprefix{n:plex\typescriptone}-thin] [\s!features=\typescriptprefix{f:scplex\typescriptone}] - \definefontfallback[Fake\typescriptprefix{\typescriptone}Caps] [\typescriptprefix{\typescriptone}Widened] [0x0000-0xFFFF] [\s!rscale=0.85,method=uppercase] - \definefontsynonym [\typescriptprefix{\typescriptone}Caps] [\s!file:\typescriptprefix{n:plex\typescriptone}-thin] [\s!fallbacks=Fake\typescriptprefix{\typescriptone}Caps] + \edefinefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-thin] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:plex\typescriptone}-thinitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-text] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-textitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Widened] [\s!file:\typescriptprefix{n:plex\typescriptone}-thin] [\s!features=\typescriptprefix{f:scplex\typescriptone}] + \edefinefontfallback[Fake\typescriptprefix{\typescriptone}Caps] [\typescriptprefix{\typescriptone}Widened] [0x0000-0xFFFF] [\s!rscale=0.85,method=uppercase] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Caps] [\s!file:\typescriptprefix{n:plex\typescriptone}-thin] [\s!fallbacks=Fake\typescriptprefix{\typescriptone}Caps] \stoptypescript \starttypescript [\s!sans,\s!serif,\s!mono] [ibmplex-extralight] [\s!name] \setups[\s!font:\s!fallback:\typescriptone] - \definefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-extralight] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:plex\typescriptone}-extralightitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-medium] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-mediumitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}Widened] [\s!file:\typescriptprefix{n:plex\typescriptone}-extralight] [\s!features=\typescriptprefix{f:scplex\typescriptone}] - \definefontfallback[Fake\typescriptprefix{\typescriptone}Caps] [\typescriptprefix{\typescriptone}Widened] [0x0000-0xFFFF] [\s!rscale=0.85,method=uppercase] - \definefontsynonym [\typescriptprefix{\typescriptone}Caps] [\s!file:\typescriptprefix{n:plex\typescriptone}-extralight] [\s!fallbacks=Fake\typescriptprefix{\typescriptone}Caps] + \edefinefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-extralight] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:plex\typescriptone}-extralightitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-medium] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-mediumitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Widened] [\s!file:\typescriptprefix{n:plex\typescriptone}-extralight] [\s!features=\typescriptprefix{f:scplex\typescriptone}] + \edefinefontfallback[Fake\typescriptprefix{\typescriptone}Caps] [\typescriptprefix{\typescriptone}Widened] [0x0000-0xFFFF] [\s!rscale=0.85,method=uppercase] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Caps] [\s!file:\typescriptprefix{n:plex\typescriptone}-extralight] [\s!fallbacks=Fake\typescriptprefix{\typescriptone}Caps] \stoptypescript \starttypescript [\s!sans,\s!serif,\s!mono] [ibmplex-light] [\s!name] \setups[\s!font:\s!fallback:\typescriptone] - \definefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-light] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:plex\typescriptone}-lightitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-semibold] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-semibolditalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}Widened] [\s!file:\typescriptprefix{n:plex\typescriptone}-light] [\s!features=\typescriptprefix{f:scplex\typescriptone}] - \definefontfallback[Fake\typescriptprefix{\typescriptone}Caps] [\typescriptprefix{\typescriptone}Widened] [0x0000-0xFFFF] [\s!rscale=0.85,method=uppercase] - \definefontsynonym [\typescriptprefix{\typescriptone}Caps] [\s!file:\typescriptprefix{n:plex\typescriptone}-light] [\s!fallbacks=Fake\typescriptprefix{\typescriptone}Caps] + \edefinefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-light] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:plex\typescriptone}-lightitalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-semibold] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-semibolditalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Widened] [\s!file:\typescriptprefix{n:plex\typescriptone}-light] [\s!features=\typescriptprefix{f:scplex\typescriptone}] + \edefinefontfallback[Fake\typescriptprefix{\typescriptone}Caps] [\typescriptprefix{\typescriptone}Widened] [0x0000-0xFFFF] [\s!rscale=0.85,method=uppercase] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Caps] [\s!file:\typescriptprefix{n:plex\typescriptone}-light] [\s!fallbacks=Fake\typescriptprefix{\typescriptone}Caps] \stoptypescript \starttypescript [\s!sans,\s!serif,\s!mono] [ibmplex] [\s!name] \setups[\s!font:\s!fallback:\typescriptone] - \definefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-regular] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:plex\typescriptone}-italic] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-bold] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-bolditalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}Widened] [\s!file:\typescriptprefix{n:plex\typescriptone}-regular] [\s!features=\typescriptprefix{f:scplex\typescriptone}] - \definefontfallback[Fake\typescriptprefix{\typescriptone}Caps] [\typescriptprefix{\typescriptone}Widened] [0x0000-0xFFFF] [\s!rscale=0.85,method=uppercase] - \definefontsynonym [\typescriptprefix{\typescriptone}Caps] [\s!file:\typescriptprefix{n:plex\typescriptone}-regular] [\s!fallbacks=Fake\typescriptprefix{\typescriptone}Caps] + \edefinefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-regular] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:plex\typescriptone}-italic] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-bold] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:plex\typescriptone}-bolditalic] [\s!features=\typescriptprefix{f:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Widened] [\s!file:\typescriptprefix{n:plex\typescriptone}-regular] [\s!features=\typescriptprefix{f:scplex\typescriptone}] + \edefinefontfallback[Fake\typescriptprefix{\typescriptone}Caps] [\typescriptprefix{\typescriptone}Widened] [0x0000-0xFFFF] [\s!rscale=0.85,method=uppercase] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Caps] [\s!file:\typescriptprefix{n:plex\typescriptone}-regular] [\s!fallbacks=Fake\typescriptprefix{\typescriptone}Caps] \stoptypescript % narrow \starttypescript [\s!sans,\s!serif,\s!mono] [ibmplexnarrow-thin] [\s!name] \setups[\s!font:\s!fallback:\typescriptone] - \definefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-thin] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-thinitalic] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-text] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-textitalic] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}Widened] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-thin] [\s!features=\typescriptprefix{f:scnarrowplex\typescriptone}] - \definefontfallback[Fake\typescriptprefix{\typescriptone}Caps] [\typescriptprefix{\typescriptone}Widened] [0x0000-0xFFFF] [\s!rscale=0.85,method=uppercase] - \definefontsynonym [\typescriptprefix{\typescriptone}Caps] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-thin] [\s!fallbacks=Fake\typescriptprefix{\typescriptone}Caps] + \edefinefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-thin] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-thinitalic] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-text] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-textitalic] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Widened] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-thin] [\s!features=\typescriptprefix{f:scnarrowplex\typescriptone}] + \edefinefontfallback[Fake\typescriptprefix{\typescriptone}Caps] [\typescriptprefix{\typescriptone}Widened] [0x0000-0xFFFF] [\s!rscale=0.85,method=uppercase] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Caps] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-thin] [\s!fallbacks=Fake\typescriptprefix{\typescriptone}Caps] \stoptypescript \starttypescript [\s!sans,\s!serif,\s!mono] [ibmplexnarrow-extralight] [\s!name] \setups[\s!font:\s!fallback:\typescriptone] - \definefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-extralight] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-extralightitalic] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-medium] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-mediumitalic] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}Widened] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-extralight] [\s!features=\typescriptprefix{f:scnarrowplex\typescriptone}] - \definefontfallback[Fake\typescriptprefix{\typescriptone}Caps] [\typescriptprefix{\typescriptone}Widened] [0x0000-0xFFFF] [\s!rscale=0.85,method=uppercase] - \definefontsynonym [\typescriptprefix{\typescriptone}Caps] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-extralight] [\s!fallbacks=Fake\typescriptprefix{\typescriptone}Caps] + \edefinefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-extralight] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-extralightitalic] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-medium] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-mediumitalic] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Widened] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-extralight] [\s!features=\typescriptprefix{f:scnarrowplex\typescriptone}] + \edefinefontfallback[Fake\typescriptprefix{\typescriptone}Caps] [\typescriptprefix{\typescriptone}Widened] [0x0000-0xFFFF] [\s!rscale=0.85,method=uppercase] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Caps] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-extralight] [\s!fallbacks=Fake\typescriptprefix{\typescriptone}Caps] \stoptypescript \starttypescript [\s!sans,\s!serif,\s!mono] [ibmplexnarrow-light] [\s!name] \setups[\s!font:\s!fallback:\typescriptone] - \definefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-light] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-lightitalic] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-semibold] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-semibolditalic] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}Widened] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-light] [\s!features=\typescriptprefix{f:scnarrowplex\typescriptone}] - \definefontfallback[Fake\typescriptprefix{\typescriptone}Caps] [\typescriptprefix{\typescriptone}Widened] [0x0000-0xFFFF] [\s!rscale=0.85,method=uppercase] - \definefontsynonym [\typescriptprefix{\typescriptone}Caps] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-light] [\s!fallbacks=Fake\typescriptprefix{\typescriptone}Caps] + \edefinefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-light] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-lightitalic] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-semibold] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-semibolditalic] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Widened] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-light] [\s!features=\typescriptprefix{f:scnarrowplex\typescriptone}] + \edefinefontfallback[Fake\typescriptprefix{\typescriptone}Caps] [\typescriptprefix{\typescriptone}Widened] [0x0000-0xFFFF] [\s!rscale=0.85,method=uppercase] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Caps] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-light] [\s!fallbacks=Fake\typescriptprefix{\typescriptone}Caps] \stoptypescript \starttypescript [\s!sans,\s!serif,\s!mono] [ibmplexnarrow] [\s!name] \setups[\s!font:\s!fallback:\typescriptone] - \definefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-regular] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-italic] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-bold] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-bolditalic] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}Widened] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-regular] [\s!features=\typescriptprefix{f:scnarrowplex\typescriptone}] - \definefontfallback[Fake\typescriptprefix{\typescriptone}Caps] [\typescriptprefix{\typescriptone}Widened] [0x0000-0xFFFF] [\s!rscale=0.85,method=uppercase] - \definefontsynonym [\typescriptprefix{\typescriptone}Caps] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-regular] [\s!fallbacks=Fake\typescriptprefix{\typescriptone}Caps] + \edefinefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-regular] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Italic] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-italic] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-bold] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!BoldItalic] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-bolditalic] [\s!features=\typescriptprefix{f:narrowplex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Widened] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-regular] [\s!features=\typescriptprefix{f:scnarrowplex\typescriptone}] + \edefinefontfallback[Fake\typescriptprefix{\typescriptone}Caps] [\typescriptprefix{\typescriptone}Widened] [0x0000-0xFFFF] [\s!rscale=0.85,method=uppercase] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Caps] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-regular] [\s!fallbacks=Fake\typescriptprefix{\typescriptone}Caps] \stoptypescript @@ -245,109 +245,109 @@ \definefontfallback [SansHebrewFallbackBold] [SansHebrewBold] [0x0590-0x05ff] [check=yes,force=no] \starttypescript [\s!sans] [ibmplex-thin] [\s!name] - \definefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-thin] - [\s!features=\typescriptprefix{f:plex\typescriptone}, - \s!fallbacks=\typescriptprefix{tf:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-text] - [\s!features=\typescriptprefix{f:plex\typescriptone}, - \s!fallbacks=\typescriptprefix{bf:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}Hebrew] [\s!file:\typescriptprefix{n:plex\typescriptone-hebrew}-thin] - [\s!features=hebrew] - \definefontsynonym [\typescriptprefix{\typescriptone}Hebrew\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone-hebrew}-text] - [\s!features=hebrew] + \edefinefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-thin] + [\s!features=\typescriptprefix{f:plex\typescriptone}, + \s!fallbacks=\typescriptprefix{tf:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-text] + [\s!features=\typescriptprefix{f:plex\typescriptone}, + \s!fallbacks=\typescriptprefix{bf:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Hebrew] [\s!file:\typescriptprefix{n:plex\typescriptone-hebrew}-thin] + [\s!features=hebrew] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Hebrew\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone-hebrew}-text] + [\s!features=hebrew] \stoptypescript \starttypescript [\s!sans] [ibmplex-extralight] [\s!name] - \definefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-extralight] - [\s!features=\typescriptprefix{f:plex\typescriptone}, - \s!fallbacks=\typescriptprefix{tf:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-medium] - [\s!features=\typescriptprefix{f:plex\typescriptone}, - \s!fallbacks=\typescriptprefix{bf:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}Hebrew] [\s!file:\typescriptprefix{n:plex\typescriptone-hebrew}-extralight] - [\s!features=hebrew] - \definefontsynonym [\typescriptprefix{\typescriptone}Hebrew\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone-hebrew}-medium] - [\s!features=hebrew] + \edefinefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-extralight] + [\s!features=\typescriptprefix{f:plex\typescriptone}, + \s!fallbacks=\typescriptprefix{tf:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-medium] + [\s!features=\typescriptprefix{f:plex\typescriptone}, + \s!fallbacks=\typescriptprefix{bf:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Hebrew] [\s!file:\typescriptprefix{n:plex\typescriptone-hebrew}-extralight] + [\s!features=hebrew] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Hebrew\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone-hebrew}-medium] + [\s!features=hebrew] \stoptypescript \starttypescript [\s!sans] [ibmplex-light] [\s!name] - \definefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-light] - [\s!features=\typescriptprefix{f:plex\typescriptone}, - \s!fallbacks=\typescriptprefix{tf:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-semibold] - [\s!features=\typescriptprefix{f:plex\typescriptone}, - \s!fallbacks=\typescriptprefix{bf:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}Hebrew] [\s!file:\typescriptprefix{n:plex\typescriptone-hebrew}-light] - [\s!features=hebrew] - \definefontsynonym [\typescriptprefix{\typescriptone}Hebrew\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone-hebrew}-semibold] - [\s!features=hebrew] + \edefinefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-light] + [\s!features=\typescriptprefix{f:plex\typescriptone}, + \s!fallbacks=\typescriptprefix{tf:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-semibold] + [\s!features=\typescriptprefix{f:plex\typescriptone}, + \s!fallbacks=\typescriptprefix{bf:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Hebrew] [\s!file:\typescriptprefix{n:plex\typescriptone-hebrew}-light] + [\s!features=hebrew] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Hebrew\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone-hebrew}-semibold] + [\s!features=hebrew] \stoptypescript \starttypescript [\s!sans] [ibmplex] [\s!name] - \definefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-regular] - [\s!features=\typescriptprefix{f:plex\typescriptone}, - \s!fallbacks=\typescriptprefix{tf:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-bold] - [\s!features=\typescriptprefix{f:plex\typescriptone}, - \s!fallbacks=\typescriptprefix{bf:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}Hebrew] [\s!file:\typescriptprefix{n:plex\typescriptone-hebrew}-regular] - [\s!features=hebrew] - \definefontsynonym [\typescriptprefix{\typescriptone}Hebrew\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone-hebrew}-bold] - [\s!features=hebrew] + \edefinefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:plex\typescriptone}-regular] + [\s!features=\typescriptprefix{f:plex\typescriptone}, + \s!fallbacks=\typescriptprefix{tf:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone}-bold] + [\s!features=\typescriptprefix{f:plex\typescriptone}, + \s!fallbacks=\typescriptprefix{bf:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Hebrew] [\s!file:\typescriptprefix{n:plex\typescriptone-hebrew}-regular] + [\s!features=hebrew] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Hebrew\s!Bold] [\s!file:\typescriptprefix{n:plex\typescriptone-hebrew}-bold] + [\s!features=hebrew] \stoptypescript % narrow \starttypescript [\s!sans] [ibmplexnarrow-thin] [\s!name] - \definefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-thin] - [\s!features=\typescriptprefix{f:narrowplex\typescriptone}, - \s!fallbacks=\typescriptprefix{tf:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-text] - [\s!features=\typescriptprefix{f:narrowplex\typescriptone}, - \s!fallbacks=\typescriptprefix{bf:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}Hebrew] [\s!file:\typescriptprefix{n:narrowplex\typescriptone-hebrew}-thin] - [\s!features=hebrew] - \definefontsynonym [\typescriptprefix{\typescriptone}Hebrew\s!Bold] [\s!file:\typescriptprefix{n:narrowplex\typescriptone-hebrew}-text] - [\s!features=hebrew] + \edefinefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-thin] + [\s!features=\typescriptprefix{f:narrowplex\typescriptone}, + \s!fallbacks=\typescriptprefix{tf:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-text] + [\s!features=\typescriptprefix{f:narrowplex\typescriptone}, + \s!fallbacks=\typescriptprefix{bf:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Hebrew] [\s!file:\typescriptprefix{n:narrowplex\typescriptone-hebrew}-thin] + [\s!features=hebrew] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Hebrew\s!Bold] [\s!file:\typescriptprefix{n:narrowplex\typescriptone-hebrew}-text] + [\s!features=hebrew] \stoptypescript \starttypescript [\s!sans] [ibmplexnarrow-extralight] [\s!name] - \definefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-extralight] - [\s!features=\typescriptprefix{f:narrowplex\typescriptone}, - \s!fallbacks=\typescriptprefix{tf:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-medium] - [\s!features=\typescriptprefix{f:narrowplex\typescriptone}, - \s!fallbacks=\typescriptprefix{bf:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}Hebrew] [\s!file:\typescriptprefix{n:narrowplex\typescriptone-hebrew}-extralight] - [\s!features=hebrew] - \definefontsynonym [\typescriptprefix{\typescriptone}Hebrew\s!Bold] [\s!file:\typescriptprefix{n:narrowplex\typescriptone-hebrew}-medium] - [\s!features=hebrew] + \edefinefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-extralight] + [\s!features=\typescriptprefix{f:narrowplex\typescriptone}, + \s!fallbacks=\typescriptprefix{tf:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-medium] + [\s!features=\typescriptprefix{f:narrowplex\typescriptone}, + \s!fallbacks=\typescriptprefix{bf:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Hebrew] [\s!file:\typescriptprefix{n:narrowplex\typescriptone-hebrew}-extralight] + [\s!features=hebrew] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Hebrew\s!Bold] [\s!file:\typescriptprefix{n:narrowplex\typescriptone-hebrew}-medium] + [\s!features=hebrew] \stoptypescript \starttypescript [\s!sans] [ibmplexnarrow-light] [\s!name] - \definefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-light] - [\s!features=\typescriptprefix{f:narrowplex\typescriptone}, - \s!fallbacks=\typescriptprefix{tf:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-semibold] - [\s!features=\typescriptprefix{f:narrowplex\typescriptone}, - \s!fallbacks=\typescriptprefix{bf:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}Hebrew] [\s!file:\typescriptprefix{n:narrowplex\typescriptone-hebrew}-light] - [\s!features=hebrew] - \definefontsynonym [\typescriptprefix{\typescriptone}Hebrew\s!Bold] [\s!file:\typescriptprefix{n:narrowplex\typescriptone-hebrew}-semibold] - [\s!features=hebrew] + \edefinefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-light] + [\s!features=\typescriptprefix{f:narrowplex\typescriptone}, + \s!fallbacks=\typescriptprefix{tf:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-semibold] + [\s!features=\typescriptprefix{f:narrowplex\typescriptone}, + \s!fallbacks=\typescriptprefix{bf:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Hebrew] [\s!file:\typescriptprefix{n:narrowplex\typescriptone-hebrew}-light] + [\s!features=hebrew] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Hebrew\s!Bold] [\s!file:\typescriptprefix{n:narrowplex\typescriptone-hebrew}-semibold] + [\s!features=hebrew] \stoptypescript \starttypescript [\s!sans] [ibmplexnarrow] [\s!name] - \definefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-regular] - [\s!features=\typescriptprefix{f:narrowplex\typescriptone}, - \s!fallbacks=\typescriptprefix{tf:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-bold] - [\s!features=\typescriptprefix{f:narrowplex\typescriptone}, - \s!fallbacks=\typescriptprefix{bf:plex\typescriptone}] - \definefontsynonym [\typescriptprefix{\typescriptone}Hebrew] [\s!file:\typescriptprefix{n:narrowplex\typescriptone-hebrew}-regular] - [\s!features=hebrew] - \definefontsynonym [\typescriptprefix{\typescriptone}Hebrew\s!Bold] [\s!file:\typescriptprefix{n:narrowplex\typescriptone-hebrew}-bold] - [\s!features=hebrew] + \edefinefontsynonym [\typescriptprefix{\typescriptone}] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-regular] + [\s!features=\typescriptprefix{f:narrowplex\typescriptone}, + \s!fallbacks=\typescriptprefix{tf:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}\s!Bold] [\s!file:\typescriptprefix{n:narrowplex\typescriptone}-bold] + [\s!features=\typescriptprefix{f:narrowplex\typescriptone}, + \s!fallbacks=\typescriptprefix{bf:plex\typescriptone}] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Hebrew] [\s!file:\typescriptprefix{n:narrowplex\typescriptone-hebrew}-regular] + [\s!features=hebrew] + \edefinefontsynonym [\typescriptprefix{\typescriptone}Hebrew\s!Bold] [\s!file:\typescriptprefix{n:narrowplex\typescriptone-hebrew}-bold] + [\s!features=hebrew] \stoptypescript % The main definition, inspired by discussion at the 2018 ConTeXt meeting after a talk by Taco. Here diff --git a/tex/context/interface/mkii/keys-de.xml b/tex/context/interface/mkii/keys-de.xml index 573770eef..701dc246b 100644 --- a/tex/context/interface/mkii/keys-de.xml +++ b/tex/context/interface/mkii/keys-de.xml @@ -590,6 +590,7 @@ <cd:variable name='understrike' value='understrike'/> <cd:variable name='understrikes' value='understrikes'/> <cd:variable name='unframed' value='unframed'/> + <cd:variable name='unicode' value='unicode'/> <cd:variable name='unit' value='einheit'/> <cd:variable name='units' value='einheiten'/> <cd:variable name='unknown' value='unbekannt'/> diff --git a/tex/context/interface/mkii/keys-en.xml b/tex/context/interface/mkii/keys-en.xml index a3606e38b..686a4dc06 100644 --- a/tex/context/interface/mkii/keys-en.xml +++ b/tex/context/interface/mkii/keys-en.xml @@ -590,6 +590,7 @@ <cd:variable name='understrike' value='understrike'/> <cd:variable name='understrikes' value='understrikes'/> <cd:variable name='unframed' value='unframed'/> + <cd:variable name='unicode' value='unicode'/> <cd:variable name='unit' value='unit'/> <cd:variable name='units' value='units'/> <cd:variable name='unknown' value='unknown'/> diff --git a/tex/context/interface/mkii/keys-nl.xml b/tex/context/interface/mkii/keys-nl.xml index 1104e14c1..06df09bc5 100644 --- a/tex/context/interface/mkii/keys-nl.xml +++ b/tex/context/interface/mkii/keys-nl.xml @@ -590,6 +590,7 @@ <cd:variable name='understrike' value='understrike'/> <cd:variable name='understrikes' value='understrikes'/> <cd:variable name='unframed' value='unframed'/> + <cd:variable name='unicode' value='unicode'/> <cd:variable name='unit' value='eenheid'/> <cd:variable name='units' value='eenheden'/> <cd:variable name='unknown' value='onbekend'/> diff --git a/tex/context/interface/mkiv/i-context.pdf b/tex/context/interface/mkiv/i-context.pdf Binary files differindex 710c2b708..1c790c10b 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 c9466e104..d713701b0 100644 --- a/tex/context/interface/mkiv/i-readme.pdf +++ b/tex/context/interface/mkiv/i-readme.pdf diff --git a/tex/context/modules/common/s-abbreviations-logos.tex b/tex/context/modules/common/s-abbreviations-logos.tex index 00719a668..49a30451c 100644 --- a/tex/context/modules/common/s-abbreviations-logos.tex +++ b/tex/context/modules/common/s-abbreviations-logos.tex @@ -24,6 +24,7 @@ \logo [MKCI] {MkCI} \logo [MPII] {MpII} \logo [MPIV] {MpIV} +\logo [LMTX] {lmtx} \logo [ACROBAT] {Acro\-bat} \logo [AFM] {afm} @@ -37,6 +38,7 @@ \logo [APA] {apa} \logo [API] {api} \logo [ARABTEX] {Arab\TeXsuffix} +\logo [ARM] {arm} \logo [ASCII] {ascii} \logo [ASCIIMATH] {AsciiMath} \logo [ASCIITEX] {ascii\TeXsuffix} @@ -53,6 +55,7 @@ \logo [CJK] {cjk} \logo [CLD] {cld} \logo [CLD] {cld} +\logo [CMAKE] {cmake} \logo [CMR] {cmr} \logo [CMYK] {cmyk} \logo [CNC] {cnc} @@ -67,11 +70,12 @@ \logo [CTXTOOLS] {ctxtools} \logo [CWEB] {cweb} \logo [DAC] {dac} +\logo [DARWIN] {Darwin} \logo [DECTEN] {dec-10} \logo [DISTILLER] {distiller} \logo [DNA] {dna} \logo [DPI] {dpi} -\logo [DRATEX] {Dra\TeXsuffix} +%logo [DRATEX] {Dra\TeXsuffix} \logo [DSC] {dsc} \logo [DTD] {dtd} \logo [DTK] {dtk} @@ -86,7 +90,6 @@ \logo [DVISCR] {dviscr} \logo [DVIWINDO] {dviwindo} \logo [EBCDIC] {ebcdic} -\logo [EU] {eu} \logo [EC] {ec} \logo [EIFFEL] {Eiffel} \logo [EMACS] {emacs} @@ -96,6 +99,7 @@ \logo [EPS] {eps} \logo [EPUB] {ePub} \logo [ETEX] {\eTeX} +\logo [EU] {eu} \logo [EUROBACHOTEX] {EuroBacho\TeXsuffix} \logo [EUROMATH] {EuroMath} \logo [EUROTEX] {Euro\TeXsuffix} @@ -151,21 +155,21 @@ \logo [KVM] {kvm} \logo [LAMSTEX] {\LamSTeX} \logo [LATEX] {\LaTeX} -\logo [LATEXTE] {\LaTeX2e} -\logo [LATEXTN] {\LaTeX2.09} +%logo [LATEXTE] {\LaTeX2e} +%logo [LATEXTN] {\LaTeX2.09} \logo [LCD] {lcd} \logo [LINUX] {linux} \logo [LISP] {Lisp} \logo [LMX] {lmx} -\logo [LMTX] {lmtx} \logo [LPEG] {lpeg} \logo [LUA] {Lua} \logo [LUAJIT] {LuaJIT} \logo [LUAJITTEX] {Luajit\TeXsuffix} +\logo [LUAMETATEX] {\Lua Meta\TeXsuffix} \logo [LUATEX] {Lua\TeXsuffix} \logo [LUATOOLS] {luatools} \logo [MACOSX] {MacOSX} -\logo [MACROTEX] {Macro\TeXsuffix} +%logo [MACROTEX] {Macro\TeXsuffix} \logo [MAKEMPY] {MakeMPY} \logo [MAPPING] {map} \logo [MAPS] {Maps} @@ -188,25 +192,26 @@ \logo [MPS] {mps} \logo [MPTOPDF] {mptopdf} \logo [MSDOS] {msdos} +\logo [MSEXCEL] {MS~Excel} \logo [MSWINDOWS] {MS~Windows} \logo [MSWORD] {MS~Word} -\logo [MSEXCEL] {MS~Excel} \logo [MTXRUN] {mtxrun} \logo [MTXTOOLS] {mtxtools} \logo [MYSQL] {MySQL} \logo [NETPBM] {NetPBM} +\logo [NGINX] {nginx} \logo [NTG] {ntg} \logo [NTS] {nts} -\logo [NGINX] {nginx} \logo [OFM] {ofm} \logo [OMEGA] {Omega} +\logo [OPENBSD] {OpenBSD} \logo [OPENMATH] {OpenMath} \logo [OPENTYPE] {OpenType} \logo [OPI] {opi} +\logo [OSX] {os-x} \logo [OTEX] {Oriental \TeXsuffix} \logo [OTF] {otf} \logo [OTP] {otp} -\logo [OSX] {os-x} \logo [OVF] {ovf} \logo [PASCAL] {Pascal} \logo [PCTEX] {pc\TeXsuffix} @@ -243,8 +248,8 @@ \logo [RELAXNG] {Relax\kern.125emNG} \logo [RGB] {rgb} \logo [RLXTOOLS] {rlxtools} -\logo [RUBY] {Ruby} \logo [RSYNC] {Rsync} +\logo [RUBY] {Ruby} \logo [SCITE] {SciTE} \logo [SGML] {sgml} \logo [SI] {si} @@ -317,12 +322,12 @@ \logo [WEBC] {web2c} \logo [WIKI] {Wiki} \logo [WINDOWS] {Windows} -\logo [WINNT] {WinNT} -\logo [WINNX] {Win9x} +%logo [WINNT] {WinNT} +%logo [WINNX] {Win9x} \logo [WTHREEC] {W3C} \logo [WWW] {www} \logo [WYSIWYG] {wysiwyg} -\logo [XDVI] {Xdvi} +%logo [XDVI] {Xdvi} \logo [XETEX] {\XeTeX} \logo [XFDF] {xfdf} \logo [XHTML] {xhtml} @@ -331,7 +336,7 @@ \logo [XML] {xml} \logo [XMLTOOLS] {xmltools} \logo [XPATH] {xpath} -\logo [XPDFETEX] {xpdfe\TeXsuffix} +%logo [XPDFETEX] {xpdfe\TeXsuffix} \logo [XSL] {xsl} \logo [XSLFO] {xsl-fo} \logo [XSLT] {xslt} diff --git a/tex/context/modules/mkiv/m-chart.lua b/tex/context/modules/mkiv/m-chart.lua index cde563fb3..7973640a7 100644 --- a/tex/context/modules/mkiv/m-chart.lua +++ b/tex/context/modules/mkiv/m-chart.lua @@ -864,8 +864,8 @@ local function getchart(settings,forced_x,forced_y,forced_nx,forced_ny) for i=1,#data do local cell = data[i] if not autofocus or autofocus[cell.name] then -- offsets probably interfere with autofocus - local x = cell.x - local y = cell.y + local x = cell.realx -- was bug: .x + local y = cell.realy -- was bug: .y if minx == 0 or x < minx then minx = x end if miny == 0 or y < miny then miny = y end if minx == 0 or x > maxx then maxx = x end diff --git a/tex/context/modules/mkiv/m-punk.mkiv b/tex/context/modules/mkiv/m-punk.mkiv index 5b8455425..29a6d8cca 100644 --- a/tex/context/modules/mkiv/m-punk.mkiv +++ b/tex/context/modules/mkiv/m-punk.mkiv @@ -211,18 +211,18 @@ metapost.characters.flusher = flusher statistics.register("metapost font generation", function() local time = statistics.elapsedtime(flusher) if total > 0 then - return string.format("%i glyphs, %.3f seconds runtime, %0.3f glyphs/second", total, time, total/time) + return string.format("%i glyphs, %s seconds runtime, %0.3f glyphs/second", total, time, total/tonumber(time)) else - return string.format("%i glyphs, %.3f seconds runtime", total, time) + return string.format("%i glyphs, %s seconds runtime", total, time) end end) statistics.register("metapost font loading",function() local time = statistics.elapsedtime(metapost.characters) if variants > 0 then - return string.format("%.3f seconds, %i instances, %0.3f instances/second", time, variants, variants/time) + return string.format("%s seconds, %i instances, %0.3f instances/second", time, variants, variants/tonumber(time)) else - return string.format("%.3f seconds, %i instances", time, variants) + return string.format("%s seconds, %i instances", time, variants) end end) \stopluacode diff --git a/tex/context/sample/third/aristotle-grc.tex b/tex/context/sample/third/aristotle-grc.tex new file mode 100644 index 000000000..85d774f23 --- /dev/null +++ b/tex/context/sample/third/aristotle-grc.tex @@ -0,0 +1,13 @@ +\startlanguage[grc] +Λόγος δέ ἐστι φωνὴ σημαντική, ἧς τῶν μερῶν τι σημαντικόν ἐστι +κεχωρισμένον, ὡς φάσις ἀλλ᾽ οὐχ ὡς κατάφασις. λέγω δέ, οἷον ἄνθρωπος +σημαίνει τι, ἀλλ᾽ οὐχ ὅτι ἔστιν ἢ οὐκ ἔστιν (ἀλλ᾽ ἔσται κατάφασις ἢ +ἀπόφασις ἐάν τι προστεθῇ)· ἀλλ᾽ οὐχ ἡ τοῦ ἀνθρώπου συλλαβὴ μία· οὐδὲ +γὰρ ἐν τῷ μῦς τὸ υς σημαντικόν, ἀλλὰ φωνή ἐστι νῦν μόνον. ἐν δὲ τοῖς +διπλοῖς σημαίνει μέν, ἀλλ᾽ οὐ καθ᾽ αὑτό, ὥσπερ εἴρηται. ἔστι δὲ λόγος +ἅπας μὲν σημαντικός, οὐχ ὡς ὄργανον δέ, ἀλλ᾽ ὥσπερ εἴρηται κατὰ +συνθήκην· ἀποφαντικὸς δὲ οὐ πᾶς, ἀλλ᾽ ἐν ᾧ τὸ ἀληθεύειν ἢ ψεύδεσθαι +ὑπάρχει· οὐκ ἐν ἅπασι δὲ ὑπάρχει, οἷον ἡ εὐχὴ λόγος μέν, ἀλλ᾽ οὔτ᾽ +ἀληθὴς οὔτε ψευδής. οἱ μὲν οὖν ἄλλοι ἀφείσθωσαν, —ῥητορικῆς γὰρ ἢ +ποιητικῆς οἰκειοτέρα ἡ σκέψις,— ὁ δὲ ἀποφαντικὸς τῆς νῦν θεωρίας. +\stoplanguage diff --git a/tex/context/sample/third/capek-cz.tex b/tex/context/sample/third/capek-cz.tex new file mode 100644 index 000000000..8083d7152 --- /dev/null +++ b/tex/context/sample/third/capek-cz.tex @@ -0,0 +1,13 @@ +Tak vám jednou byl jeden chudý pán neboli člověk, on se vlastně jmenoval +František Král, ale tak mu říkali jenom tehdy, když ho sebral strážník a +dovedl ho na komisařství pro potulku, kde ho zapsali do takové tlusté knihy +a nechali ho přespat na pryčně a ráno ho zase poslali dál; na policii mu +tedy říkali František Král, ale ostatní lidé ho jmenovali všelijak jinak: +ten vandrák, ten šupák, ten tulák, ten pobuda, ten lajdák, ten otrapa, ten +hadrník, ten trhan, ten obejda, ten lenoch, ten chudák, ten jindyvyjduum, +ten člověk, ten kdovíkdo, ten poběhlík, ten krajánek, ten štvanec, ten +vošlapa, ten revertent, ten vagabund, ten darmošlap, ten budižkničemu, ten +hlad, ten hunt, ten holota a ještě mnoho jiných jmen mu dávali; kdyby každé +to názvisko platilo aspoň korunu, mohl by si za ně koupit žluté boty a možná +že i klobouk, ale takhle si za to nekoupil nic a měl jenom to, co mu lidé +dali. diff --git a/tex/context/sample/third/capek-vlnka-cz.tex b/tex/context/sample/third/capek-vlnka-cz.tex new file mode 100644 index 000000000..9fede2334 --- /dev/null +++ b/tex/context/sample/third/capek-vlnka-cz.tex @@ -0,0 +1,13 @@ +Tak vám jednou byl jeden chudý pán neboli člověk, on se vlastně jmenoval +František Král, ale tak mu říkali jenom tehdy, když ho sebral strážník +a~dovedl ho na komisařství pro potulku, kde ho zapsali do takové tlusté knihy +a~nechali ho přespat na pryčně a~ráno ho zase poslali dál; na policii mu +tedy říkali František Král, ale ostatní lidé ho jmenovali všelijak jinak: +ten vandrák, ten šupák, ten tulák, ten pobuda, ten lajdák, ten otrapa, ten +hadrník, ten trhan, ten obejda, ten lenoch, ten chudák, ten jindyvyjduum, +ten člověk, ten kdovíkdo, ten poběhlík, ten krajánek, ten štvanec, ten +vošlapa, ten revertent, ten vagabund, ten darmošlap, ten budižkničemu, ten +hlad, ten hunt, ten holota a~ještě mnoho jiných jmen mu dávali; kdyby každé +to názvisko platilo aspoň korunu, mohl by si za ně koupit žluté boty a~možná +že i~klobouk, ale takhle si za to nekoupil nic a~měl jenom to, co mu lidé +dali. diff --git a/tex/context/sample/third/dequincey.tex b/tex/context/sample/third/dequincey.tex new file mode 100644 index 000000000..a1070b562 --- /dev/null +++ b/tex/context/sample/third/dequincey.tex @@ -0,0 +1,5 @@ +For if once a man indulges himself in murder, very soon he comes to +think little of robbing; and from robbing he comes next to drinking and +Sabbath--breaking, and from that to incivility and procrastination. +Once begin upon this downward path, you never know where you are to +stop. diff --git a/tex/context/sample/third/dyrynk-cz.tex b/tex/context/sample/third/dyrynk-cz.tex new file mode 100644 index 000000000..e12a228b9 --- /dev/null +++ b/tex/context/sample/third/dyrynk-cz.tex @@ -0,0 +1,22 @@ +Čeho jsem si zvlášť všímal při prohlížení knih, je typografické jejich +zhotovení, technické provedení knihtiskařem, které po mém soudu je základem +dobré knižní úpravy. A tu nelze upřít, že řemeslná stránka je dosud stránkou +slabou většiny našich knih. Často až překvapí rozpor mezi péčí, kterou +věnoval umělec výzdobě knihy, a ledabylostí, s jakou ji tiskárna zhotovila. +Bývá to podivná harmonie: výzdoba umělecká a sazba i tisk jako denních +novin. Nejsou to malé závody, jichž výrobkům lze vytknouti tuto řemeslnou +chybu, i přední veliké tiskárny zhotovují takto >>krásné<< knihy. Stačí +prohlédnouti si podrobněji reprodukce v tomto díle, abychom se přesvědčili, +že to tvrzení není přehnané. + +Přece však lze pozorovati potěšitelný obrat k lepšímu: některé české +knihtiskárny se chlubí už správně vysazenými a dobře vytištěnými knihami. +Sice dosud jest málo impressí, které takto jeví úctu a vážnost k svému +černému umění, obracejíce knihtisk k jeho staré lásce, knize, a věnujíce +její vkusné úpravě čas, píči a píli; na prstech jedné ruky by je spočetl. +Nepochybuji však, že jich přibude, vždyť ničím nemůže se knihtiskárna +lépe doporučiti než svojí firmou na dokonale, krásně upravené knize, která +je rozkoší oku a potěšením duši, a ještě po letech a desetiletích, kdy +dávno upadnou v zapomnění drobné akcidence, zůstane v knihovnách jako svědek +odborné vyspělosti knihtiskárny, schopnosti jejích pracovníků +a prozíravosti i vkusu principála nebo řiditele závodu. diff --git a/tex/context/sample/third/dyrynk-vlnka-cz.tex b/tex/context/sample/third/dyrynk-vlnka-cz.tex new file mode 100644 index 000000000..1d4df1e49 --- /dev/null +++ b/tex/context/sample/third/dyrynk-vlnka-cz.tex @@ -0,0 +1,23 @@ + +Čeho jsem si zvlášť všímal při prohlížení knih, je typografické jejich +zhotovení, technické provedení knihtiskařem, které po mém soudu je základem +dobré knižní úpravy. A~tu nelze upřít, že řemeslná stránka je dosud stránkou +slabou většiny našich knih. Často až překvapí rozpor mezi péčí, kterou +věnoval umělec výzdobě knihy, a~ledabylostí, s~jakou ji tiskárna zhotovila. +Bývá to podivná harmonie: výzdoba umělecká a~sazba i~tisk jako denních +novin. Nejsou to malé závody, jichž výrobkům lze vytknouti tuto řemeslnou +chybu, i~přední veliké tiskárny zhotovují takto >>krásné<< knihy. Stačí +prohlédnouti si podrobněji reprodukce v~tomto díle, abychom se přesvědčili, +že to tvrzení není přehnané. + +Přece však lze pozorovati potěšitelný obrat k~lepšímu: některé české +knihtiskárny se chlubí už správně vysazenými a~dobře vytištěnými knihami. +Sice dosud jest málo impressí, které takto jeví úctu a~vážnost k~svému +černému umění, obracejíce knihtisk k~jeho staré lásce, knize, a~věnujíce +její vkusné úpravě čas, píči a~píli; na prstech jedné ruky by je spočetl. +Nepochybuji však, že jich přibude, vždyť ničím nemůže se knihtiskárna +lépe doporučiti než svojí firmou na dokonale, krásně upravené knize, která +je rozkoší oku a~potěšením duši, a~ještě po letech a~desetiletích, kdy +dávno upadnou v~zapomnění drobné akcidence, zůstane v~knihovnách jako svědek +odborné vyspělosti knihtiskárny, schopnosti jejích pracovníků +a~prozíravosti i~vkusu principála nebo řiditele závodu. diff --git a/tex/context/sample/third/kollar-cz.tex b/tex/context/sample/third/kollar-cz.tex new file mode 100644 index 000000000..5a4f63695 --- /dev/null +++ b/tex/context/sample/third/kollar-cz.tex @@ -0,0 +1,31 @@ + +Aj zde leží zem ta před okem mým slzy ronícím, +někdy kolébka, nyní národu mého rakev. +Stoj noho! posvátná místa jsou, kamkoli kráčíš, +k obloze, Tatry synu, vznes se vyvýše pohled, +neb raději k velikému prichyl tomu tam se dubisku, +jenž vzdoruje zhoubným až dosaváde časům. +Však času ten horší je člověk, jenž berlu železnou +v těchto krajích na tvou, Slavie, šíji chopil. +Horší, nežli divé války, hromu, ohně divější, +zaslepenec na své když zlobu plémě kydá. +Ó věkové dávní, jako noc vůkol mne ležící, +ó krajino, všeliké slávy i hanby obraz! +Od Labe zrádného k rovinám až Visly nevěrné, +od Dunaje k hltným Baltu celého pěnám: +Krásnohlasy zmužilých Slavjanů kde se někdy ozýval, +aj oněmělť už, byv k ourazu zášti, jazyk. +A kdo se loupeže té, volající vzhůru, dopustil? +Kdo zhanobil v jednom národu lidstvo celé? +Zardi se závistná Teutonie, sousedo Slávy, +tvé vin těchto počet spáchaly někdy ruky! +Neb krve nikde tolik nevylil černidla že žádný +nepřítel, co vylil k záhubě Slávy Němec. +Sám svobody kdo hoden, svobodu zná vážiti každou, +ten kdo do pout jímá otroky, sám je otrok. +Nechť ruky, nechť by jazyk v okovy své vázal otrocké, +jedno to, neb nezná šetřiti práva jiných. +Ten, kdo trůny bořil, lidskou krev darmo vyléval, +po světě nešťastnou války pochodni nosil: +ten porobu slušnou, buď Goth, buď Skytha zasloužil, +ne kdo divé chválil příkladem ordě pokoj. diff --git a/tex/context/sample/third/kollar-vlnka-cz.tex b/tex/context/sample/third/kollar-vlnka-cz.tex new file mode 100644 index 000000000..01e815e74 --- /dev/null +++ b/tex/context/sample/third/kollar-vlnka-cz.tex @@ -0,0 +1,30 @@ +Aj zde leží zem ta před okem mým slzy ronícím, +někdy kolébka, nyní národu mého rakev. +Stoj noho! posvátná místa jsou, kamkoli kráčíš, +k~obloze, Tatry synu, vznes se vyvýše pohled, +neb raději k~velikému prichyl tomu tam se dubisku, +jenž vzdoruje zhoubným až dosaváde časům. +Však času ten horší je člověk, jenž berlu železnou +v~těchto krajích na tvou, Slavie, šíji chopil. +Horší, nežli divé války, hromu, ohně divější, +zaslepenec na své když zlobu plémě kydá. +Ó věkové dávní, jako noc vůkol mne ležící, +ó krajino, všeliké slávy i~hanby obraz! +Od Labe zrádného k~rovinám až Visly nevěrné, +od Dunaje k~hltným Baltu celého pěnám: +Krásnohlasy zmužilých Slavjanů kde se někdy ozýval, +aj oněmělť už, byv k~ourazu zášti, jazyk. +A~kdo se loupeže té, volající vzhůru, dopustil? +Kdo zhanobil v~jednom národu lidstvo celé? +Zardi se závistná Teutonie, sousedo Slávy, +tvé vin těchto počet spáchaly někdy ruky! +Neb krve nikde tolik nevylil černidla že žádný +nepřítel, co vylil k~záhubě Slávy Němec. +Sám svobody kdo hoden, svobodu zná vážiti každou, +ten kdo do pout jímá otroky, sám je otrok. +Nechť ruky, nechť by jazyk v~okovy své vázal otrocké, +jedno to, neb nezná šetřiti práva jiných. +Ten, kdo trůny bořil, lidskou krev darmo vyléval, +po světě nešťastnou války pochodni nosil: +ten porobu slušnou, buď Goth, buď Skytha zasloužil, +ne kdo divé chválil příkladem ordě pokoj. diff --git a/tex/context/sample/third/komensky-cz.tex b/tex/context/sample/third/komensky-cz.tex new file mode 100644 index 000000000..f25bb47d9 --- /dev/null +++ b/tex/context/sample/third/komensky-cz.tex @@ -0,0 +1,33 @@ +Nejkrásnějším dílem Božím je svět, všeliké neviditelné Božské věcí viditelné +ukazující. Nejkrásnější je ale naše duše, jíž je dáno, myšlením zobrazovat +ve svém nitru svět i věci veškery. Nejkrásnější je řeč, jejíž pomocí +vmalováváme všeliké obrazy své duše v duši druhého. Nejkrásnější je písmo, +jímž zachycujeme a natrvalo upevňujeme řeč, samu o sobě prchavou a +pomíjející, a jímž jako bychom ji zadržovali, aby trvala. Nejkrásnější jsou +knihy, písmem ladně sestavené, jimiž zpodobenou moudrost posíláme lidem, +místně či časově vzdáleným, ba dokonce i pozdnímu potomstvu. Nejkrásnějším +darem Božím je vynález tiskových liter, jimž se knihy nesmírně rychle +rozmnožují. + +Sazeč, maje před sebou kasu, naplněnou kovovými literkami, uloženými v +přihrádkách, dívá se do rukopisu, postaveného na vidlici tak, aby pohodlně +viděl, v levé ruce sázítko, pravou rukou vybírá (z přihrádek) literky a +skládá je do sázítka v slova: když naplní sloupec, přenáší je na desku. +Jakmile pak je naplněn počet sloupců pro jednu stranu archu, rozdělí je +příložkami, ováže je a stáhne železnými rámy, aby se nerozpadly; a tím se +podle svého mínění sví povinnosti zhostil. + +A tak tito všichni pracujíce vzájemně vykonávající jakoby hračkou +podivuhodné dílo, lidem kdysi nepochopitelné, jen když mají všichni to, čeho +je přitom potření, jednak odborné znalosti zbystřené praxí, jednak vytrvalou +pozornost a píli. Znalosti: poněvadž třebaže je tiskařství řemeslem, je +nejsubtilnějším uměním, skládajícím se z přečetných maličkostí, na něž nutno +dávat dobrý pozor. Pozornost a píli: poněvadž zde, kde se stýká tolik +maličkostí, velmi snadno se něco přihodí, co by dílo rušilo, kdyby se +nebdělo. + +Tolik ve všeobecnosti o tom, jak se tisknou knihy vůbec. Jestliže by se +naskytla otázka, jak vznikají knihy dobré, bude třeba říci, že je žádoucí za +prvé rozumně sepsaný rukopis, hodný světla a nikoli tmy; na druhém místě +elegantní typy; na třetím čistý papír; na čtvrtém pak pozorná práce, aby vše +až do poslední čárky bylo zřetelné, rozlišené a správné. diff --git a/tex/context/sample/third/komensky-vlnka-cz.tex b/tex/context/sample/third/komensky-vlnka-cz.tex new file mode 100644 index 000000000..17a2ab3f7 --- /dev/null +++ b/tex/context/sample/third/komensky-vlnka-cz.tex @@ -0,0 +1,33 @@ +Nejkrásnějším dílem Božím je svět, všeliké neviditelné Božské věcí viditelné +ukazující. Nejkrásnější je ale naše duše, jíž je dáno, myšlením zobrazovat +ve svém nitru svět i~věci veškery. Nejkrásnější je řeč, jejíž pomocí +vmalováváme všeliké obrazy své duše v~duši druhého. Nejkrásnější je písmo, +jímž zachycujeme a~natrvalo upevňujeme řeč, samu o~sobě prchavou +a~pomíjející, a~jímž jako bychom ji zadržovali, aby trvala. Nejkrásnější jsou +knihy, písmem ladně sestavené, jimiž zpodobenou moudrost posíláme lidem, +místně či časově vzdáleným, ba dokonce i~pozdnímu potomstvu. Nejkrásnějším +darem Božím je vynález tiskových liter, jimž se knihy nesmírně rychle +rozmnožují. + +Sazeč, maje před sebou kasu, naplněnou kovovými literkami, uloženými +v~přihrádkách, dívá se do rukopisu, postaveného na vidlici tak, aby pohodlně +viděl, v~levé ruce sázítko, pravou rukou vybírá (z~přihrádek) literky +a~skládá je do sázítka v~slova: když naplní sloupec, přenáší je na desku. +Jakmile pak je naplněn počet sloupců pro jednu stranu archu, rozdělí je +příložkami, ováže je a~stáhne železnými rámy, aby se nerozpadly; a~tím se +podle svého mínění sví povinnosti zhostil. + +A~tak tito všichni pracujíce vzájemně vykonávající jakoby hračkou +podivuhodné dílo, lidem kdysi nepochopitelné, jen když mají všichni to, čeho +je přitom potřebí, jednak odborné znalosti zbystřené praxí, jednak vytrvalou +pozornost a~píli. Znalosti: poněvadž třebaže je tiskařství řemeslem, je +nejsubtilnějším uměním, skládajícím se z~přečetných maličkostí, na něž nutno +dávat dobrý pozor. Pozornost a~píli: poněvadž zde, kde se stýká tolik +maličkostí, velmi snadno se něco přihodí, co by dílo rušilo, kdyby se +nebdělo. + +Tolik ve všeobecnosti o~tom, jak se tisknou knihy vůbec. Jestliže by se +naskytla otázka, jak vznikají knihy dobré, bude třeba říci, že je žádoucí za +prvé rozumně sepsaný rukopis, hodný světla a~nikoli tmy; na druhém místě +elegantní typy; na třetím čistý papír; na čtvrtém pak pozorná práce, aby vše +až do poslední čárky bylo zřetelné, rozlišené a~správné. diff --git a/tex/context/sample/third/krdel-sk.tex b/tex/context/sample/third/krdel-sk.tex new file mode 100644 index 000000000..2f2395427 --- /dev/null +++ b/tex/context/sample/third/krdel-sk.tex @@ -0,0 +1,7 @@ + +KŔDEĽ ŠŤASTNÝCH ĎATĽOV UČÍ PRI ÚSTÍ VÁHU MĹKVÉHO KOŇA OBHRÝZAŤ KÔRU A ŽRAŤ ČERSTVÉ MÄSO. + +Kŕdeľ šťastných ďatľov učí pri ústí Váhu mĺkveho koňa obhrýzať kôru a žrať čerstvé mäso. + +0123456789 :;!?()[]\{\} -/--/--- ÖÜŮŘ öüůř + diff --git a/tex/context/sample/third/kun-cz.tex b/tex/context/sample/third/kun-cz.tex new file mode 100644 index 000000000..ee1471c1b --- /dev/null +++ b/tex/context/sample/third/kun-cz.tex @@ -0,0 +1,7 @@ + +ŽLUŤOUČKÝ KŮŇ ÚPĚL ĎÁBELSKÉ ÓDY, + +žluťoučký kůň úpěl ďábelské ódy. + +0123456789 :;!?()[]\{\} -/--/--- ŕĺľäöü ŔĹĽÄÖÜ + diff --git a/tex/generic/context/luatex/luatex-basics-nod.lua b/tex/generic/context/luatex/luatex-basics-nod.lua index e22f170ef..879da4bc7 100644 --- a/tex/generic/context/luatex/luatex-basics-nod.lua +++ b/tex/generic/context/luatex/luatex-basics-nod.lua @@ -70,81 +70,77 @@ nodes.nodecodes = nodecodes nodes.glyphcodes = glyphcodes nodes.disccodes = disccodes -local flush_node = node.flush_node -local remove_node = node.remove -local traverse_id = node.traverse_id - nodes.handlers.protectglyphs = node.protect_glyphs -- beware: nodes! nodes.handlers.unprotectglyphs = node.unprotect_glyphs -- beware: nodes! -function nodes.remove(head, current, free_too) - local t = current - head, current = remove_node(head,current) - if t then - if free_too then - flush_node(t) - t = nil - else - t.next, t.prev = nil, nil - end - end - return head, current, t -end - -function nodes.delete(head,current) - return nodes.remove(head,current,true) -end - -local getfield = node.getfield -local setfield = node.setfield - -nodes.getfield = getfield -nodes.setfield = setfield - -nodes.getattr = getfield -nodes.setattr = setfield - --- being lazy ... just copy a bunch ... not all needed in generic but we assume --- nodes to be kind of private anyway - -nodes.tostring = node.tostring or tostring -nodes.copy = node.copy -nodes.copy_node = node.copy -nodes.copy_list = node.copy_list -nodes.delete = node.delete -nodes.dimensions = node.dimensions -nodes.end_of_math = node.end_of_math -nodes.flush_list = node.flush_list -nodes.flush_node = node.flush_node -nodes.flush = node.flush_node -nodes.free = node.free -nodes.insert_after = node.insert_after -nodes.insert_before = node.insert_before -nodes.hpack = node.hpack -nodes.new = node.new -nodes.tail = node.tail -nodes.traverse = node.traverse -nodes.traverse_id = node.traverse_id -nodes.slide = node.slide -nodes.vpack = node.vpack - -nodes.first_glyph = node.first_glyph -nodes.has_glyph = node.has_glyph or node.first_glyph - -nodes.current_attr = node.current_attr -nodes.has_field = node.has_field -nodes.last_node = node.last_node -nodes.usedlist = node.usedlist -nodes.protrusion_skippable = node.protrusion_skippable -nodes.write = node.write - -nodes.has_attribute = node.has_attribute -nodes.set_attribute = node.set_attribute -nodes.unset_attribute = node.unset_attribute - -nodes.protect_glyphs = node.protect_glyphs -nodes.unprotect_glyphs = node.unprotect_glyphs -nodes.mlist_to_hlist = node.mlist_to_hlist +-- These are now gone in generic as they are context specific. + +-- local flush_node = node.flush_node +-- local remove_node = node.remove +-- local traverse_id = node.traverse_id +-- +-- function nodes.remove(head, current, free_too) +-- local t = current +-- head, current = remove_node(head,current) +-- if t then +-- if free_too then +-- flush_node(t) +-- t = nil +-- else +-- t.next, t.prev = nil, nil +-- end +-- end +-- return head, current, t +-- end +-- +-- function nodes.delete(head,current) +-- return nodes.remove(head,current,true) +-- end + +----- getfield = node.getfield +----- setfield = node.setfield + +-----.getfield = getfield +-----.setfield = setfield +-----.getattr = getfield +-----.setattr = setfield + +-----.tostring = node.tostring or tostring +-----.copy = node.copy +-----.copy_node = node.copy +-----.copy_list = node.copy_list +-----.delete = node.delete +-----.dimensions = node.dimensions +-----.end_of_math = node.end_of_math +-----.flush_list = node.flush_list +-----.flush_node = node.flush_node +-----.flush = node.flush_node +-----.free = node.free +-----.insert_after = node.insert_after +-----.insert_before = node.insert_before +-----.hpack = node.hpack +-----.new = node.new +-----.tail = node.tail +-----.traverse = node.traverse +-----.traverse_id = node.traverse_id +-----.slide = node.slide +-----.vpack = node.vpack + +-----.first_glyph = node.first_glyph +-----.has_glyph = node.has_glyph or node.first_glyph +-----.current_attr = node.current_attr +-----.has_field = node.has_field +-----.usedlist = node.usedlist +-----.protrusion_skippable = node.protrusion_skippable +-----.write = node.write + +-----.has_attribute = node.has_attribute +-----.set_attribute = node.set_attribute +-----.unset_attribute = node.unset_attribute + +-----.protect_glyphs = node.protect_glyphs +-----.unprotect_glyphs = node.unprotect_glyphs +-----.mlist_to_hlist = node.mlist_to_hlist -- in generic code, at least for some time, we stay nodes, while in context -- we can go nuts (e.g. experimental); this split permits us us keep code diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index d470094fc..6a8a418bd 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 : 02/14/19 16:57:24 +-- merge date : 04/04/19 13:31:02 do -- begin closure to overcome local limits and interference @@ -119,8 +119,7 @@ if not FFISUPPORTED then elseif not ffi.number then ffi.number=tonumber end -if not bit32 then - bit32=require("l-bit32") +if LUAVERSION>5.3 then end end -- closure @@ -1045,7 +1044,7 @@ if not modules then modules={} end modules ['l-table']={ } local type,next,tostring,tonumber,select=type,next,tostring,tonumber,select local table,string=table,string -local concat,sort,insert,remove=table.concat,table.sort,table.insert,table.remove +local concat,sort=table.concat,table.sort local format,lower,dump=string.format,string.lower,string.dump local getmetatable,setmetatable=getmetatable,setmetatable local lpegmatch,patterns=lpeg.match,lpeg.patterns @@ -1055,7 +1054,8 @@ function table.getn(t) return t and #t end function table.strip(tab) - local lst,l={},0 + local lst={} + local l=0 for i=1,#tab do local s=lpegmatch(stripper,tab[i]) or "" if s=="" then @@ -1068,7 +1068,8 @@ function table.strip(tab) end function table.keys(t) if t then - local keys,k={},0 + local keys={} + local k=0 for key in next,t do k=k+1 keys[k]=key @@ -1099,27 +1100,30 @@ local function compare(a,b) end local function sortedkeys(tab) if tab then - local srt,category,s={},0,0 + local srt={} + local category=0 + local s=0 for key in next,tab do s=s+1 srt[s]=key - if category==3 then - elseif category==1 then - if type(key)~="string" then - category=3 - end - elseif category==2 then - if type(key)~="number" then - category=3 - end - else + if category~=3 then local tkey=type(key) - if tkey=="string" then - category=1 - elseif tkey=="number" then - category=2 + if category==1 then + if tkey~="string" then + category=3 + end + elseif category==2 then + if tkey~="number" then + category=3 + end else - category=3 + if tkey=="string" then + category=1 + elseif tkey=="number" then + category=2 + else + category=3 + end end end end @@ -1136,7 +1140,8 @@ local function sortedkeys(tab) end local function sortedhashonly(tab) if tab then - local srt,s={},0 + local srt={} + local s=0 for key in next,tab do if type(key)=="string" then s=s+1 @@ -1153,7 +1158,8 @@ local function sortedhashonly(tab) end local function sortedindexonly(tab) if tab then - local srt,s={},0 + local srt={} + local s=0 for key in next,tab do if type(key)=="number" then s=s+1 @@ -1170,7 +1176,8 @@ local function sortedindexonly(tab) end local function sortedhashkeys(tab,cmp) if tab then - local srt,s={},0 + local srt={} + local s=0 for key in next,tab do if key then s=s+1 @@ -1246,7 +1253,9 @@ function table.prepend(t,list) return t end function table.merge(t,...) - t=t or {} + if not t then + t={} + end for i=1,select("#",...) do for k,v in next,(select(i,...)) do t[k]=v @@ -1275,7 +1284,8 @@ function table.imerge(t,...) return t end function table.imerged(...) - local tmp,ntmp={},0 + local tmp={} + local ntmp=0 for i=1,select("#",...) do local nst=select(i,...) for j=1,#nst do @@ -1307,7 +1317,9 @@ local function fastcopy(old,metatabletoo) end end local function copy(t,tables) - tables=tables or {} + if not tables then + tables={} + end local tcopy={} if not tables[t] then tables[t]=tcopy @@ -1354,7 +1366,8 @@ function table.tohash(t,value) return h end function table.fromhash(t) - local hsh,h={},0 + local hsh={} + local h=0 for k,v in next,t do if v then h=h+1 @@ -1455,7 +1468,8 @@ local function do_serialize(root,name,depth,level,indexed) end end if root and next(root)~=nil then - local first,last=nil,0 + local first=nil + local last=0 if compact then last=#root for k=1,last do @@ -1714,7 +1728,8 @@ local function serialize(_handle,root,name,specification) handle("}") end function table.serialize(root,name,specification) - local t,n={},0 + local t={} + local n=0 local function flush(s) n=n+1 t[n]=s @@ -1728,13 +1743,15 @@ function table.tofile(filename,root,name,specification) local f=io.open(filename,'w') if f then if maxtab>1 then - local t,n={},0 + local t={} + local n=0 local function flush(s) n=n+1 t[n]=s if n>maxtab then f:write(concat(t,"\n"),"\n") - t,n={},0 + t={} + n=0 end end serialize(flush,root,name,specification) @@ -1836,8 +1853,12 @@ local function are_equal(a,b,n,m) if a==b then return true elseif a and b and #a==#b then - n=n or 1 - m=m or #a + if not n then + n=1 + end + if not m then + m=#a + end for i=n,m do local ai,bi=a[i],b[i] if ai==bi then @@ -1937,7 +1958,8 @@ function table.mirrored(t) end function table.reversed(t) if t then - local tt,tn={},#t + local tt={} + local tn=#t if tn>0 then local ttn=0 for i=tn,1,-1 do @@ -2050,7 +2072,9 @@ function table.sorted(t,...) end function table.values(t,s) if t then - local values,keys,v={},{},0 + local values={} + local keys={} + local v=0 for key,value in next,t do if not keys[value] then v=v+1 @@ -2652,40 +2676,45 @@ local reslasher=lpeg.replacer(P("\\"),"/") function file.reslash(str) return str and lpegmatch(reslasher,str) end -function file.is_writable(name) - if not name then - elseif lfs.isdir(name) then - name=name.."/m_t_x_t_e_s_t.tmp" - local f=io.open(name,"wb") - if f then - f:close() - os.remove(name) - return true - end - elseif lfs.isfile(name) then - local f=io.open(name,"ab") - if f then - f:close() - return true - end - else - local f=io.open(name,"ab") - if f then - f:close() - os.remove(name) - return true +if lfs.isreadablefile and lfs.iswritablefile then + file.is_readable=lfs.isreadablefile + file.is_writable=lfs.iswritablefile +else + function file.is_writable(name) + if not name then + elseif lfs.isdir(name) then + name=name.."/m_t_x_t_e_s_t.tmp" + local f=io.open(name,"wb") + if f then + f:close() + os.remove(name) + return true + end + elseif lfs.isfile(name) then + local f=io.open(name,"ab") + if f then + f:close() + return true + end + else + local f=io.open(name,"ab") + if f then + f:close() + os.remove(name) + return true + end end - end - return false -end -local readable=P("r")*Cc(true) -function file.is_readable(name) - if name then - local a=attributes(name) - return a and lpegmatch(readable,a.permissions) or false - else return false end + local readable=P("r")*Cc(true) + function file.is_readable(name) + if name then + local a=attributes(name) + return a and lpegmatch(readable,a.permissions) or false + else + return false + end + end end file.isreadable=file.is_readable file.iswritable=file.is_writable @@ -3045,7 +3074,6 @@ local format,gsub,rep,sub,find=string.format,string.gsub,string.rep,string.sub,s local load,dump=load,string.dump local tonumber,type,tostring,next,setmetatable=tonumber,type,tostring,next,setmetatable local unpack,concat=table.unpack,table.concat -local unpack,concat=table.unpack,table.concat local P,V,C,S,R,Ct,Cs,Cp,Carg,Cc=lpeg.P,lpeg.V,lpeg.C,lpeg.S,lpeg.R,lpeg.Ct,lpeg.Cs,lpeg.Cp,lpeg.Carg,lpeg.Cc local patterns,lpegmatch=lpeg.patterns,lpeg.match local utfchar,utfbyte,utflen=utf.char,utf.byte,utf.len @@ -3384,8 +3412,8 @@ local environment={ formattednumber=number.formatted, sparseexponent=number.sparseexponent, formattedfloat=number.formattedfloat, - stripzero=lpeg.patterns.stripzero, - stripzeros=lpeg.patterns.stripzeros, + stripzero=patterns.stripzero, + stripzeros=patterns.stripzeros, FORMAT=string.f9, } local arguments={ "a1" } @@ -3472,7 +3500,7 @@ local format_F=function(f) end local format_k=function(b,a) n=n+1 - return format("formattedfloat(a%s,%i,%i)",n,b or 0,a or 0) + return format("formattedfloat(a%s,%s,%s)",n,b or 0,a or 0) end local format_g=function(f) n=n+1 @@ -3828,9 +3856,9 @@ patterns.xmlescape=Cs((P("<")/"<"+P(">")/">"+P("&")/"&"+P('"')/"" patterns.texescape=Cs((C(S("#$%\\{}"))/"\\%1"+anything)^0) patterns.luaescape=Cs(((1-S('"\n'))^1+P('"')/'\\"'+P('\n')/'\\n"')^0) patterns.luaquoted=Cs(Cc('"')*((1-S('"\n'))^1+P('"')/'\\"'+P('\n')/'\\n"')^0*Cc('"')) -add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],{ xmlescape=lpeg.patterns.xmlescape }) -add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape=lpeg.patterns.texescape }) -add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape=lpeg.patterns.luaescape }) +add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],{ xmlescape=patterns.xmlescape }) +add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape=patterns.texescape }) +add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape=patterns.luaescape }) local dquote=patterns.dquote local equote=patterns.escaped+dquote/'\\"'+1 local cquote=Cc('"') @@ -3862,6 +3890,27 @@ local f_16_16=formatters["%0.5N"] function number.to16dot16(n) return f_16_16(n/65536.0) end +if not string.explode then + local tsplitat=lpeg.tsplitat + local p_utf=patterns.utf8character + local p_check=C(p_utf)*(P("+")*Cc(true))^0 + local p_split=Ct(C(p_utf)^0) + local p_space=Ct((C(1-P(" ")^1)+P(" ")^1)^0) + function string.explode(str,symbol) + if symbol=="" then + return lpegmatch(p_split,str) + elseif symbol then + local a,b=lpegmatch(p_check,symbol) + if b then + return lpegmatch(tsplitat(P(a)^1),str) + else + return lpegmatch(tsplitat(a),str) + end + else + return lpegmatch(p_space,str) + end + end +end end -- closure @@ -4074,6 +4123,32 @@ if bit32 then local b=char(n%256) f:write(b,a) end + function files.writecardinal4(f,n) + local a=char(n%256) + n=rshift(n,8) + local b=char(n%256) + n=rshift(n,8) + local c=char(n%256) + n=rshift(n,8) + local d=char(n%256) + f:write(d,c,b,a) + end + function files.writecardinal2le(f,n) + local a=char(n%256) + n=rshift(n,8) + local b=char(n%256) + f:write(a,b) + end + function files.writecardinal4le(f,n) + local a=char(n%256) + n=rshift(n,8) + local b=char(n%256) + n=rshift(n,8) + local c=char(n%256) + n=rshift(n,8) + local d=char(n%256) + f:write(a,b,c,d) + end else local floor=math.floor function files.writecardinal2(f,n) @@ -4082,16 +4157,32 @@ else local b=char(n%256) f:write(b,a) end -end -function files.writecardinal4(f,n) - local a=char(n%256) - n=rshift(n,8) - local b=char(n%256) - n=rshift(n,8) - local c=char(n%256) - n=rshift(n,8) - local d=char(n%256) - f:write(d,c,b,a) + function files.writecardinal4(f,n) + local a=char(n%256) + n=floor(n/256) + local b=char(n%256) + n=floor(n/256) + local c=char(n%256) + n=floor(n/256) + local d=char(n%256) + f:write(d,c,b,a) + end + function files.writecardinal2le(f,n) + local a=char(n%256) + n=floor(n/256) + local b=char(n%256) + f:write(a,b) + end + function files.writecardinal4le(f,n) + local a=char(n%256) + n=floor(n/256) + local b=char(n%256) + n=floor(n/256) + local c=char(n%256) + n=floor(n/256) + local d=char(n%256) + f:write(a,b,c,d) + end end function files.writestring(f,s) f:write(char(byte(s,1,#s))) @@ -4104,10 +4195,18 @@ if fio and fio.readcardinal1 then files.readcardinal2=fio.readcardinal2 files.readcardinal3=fio.readcardinal3 files.readcardinal4=fio.readcardinal4 + files.readcardinal1le=fio.readcardinal1le or files.readcardinal1le + files.readcardinal2le=fio.readcardinal2le or files.readcardinal2le + files.readcardinal3le=fio.readcardinal3le or files.readcardinal3le + files.readcardinal4le=fio.readcardinal4le or files.readcardinal4le files.readinteger1=fio.readinteger1 files.readinteger2=fio.readinteger2 files.readinteger3=fio.readinteger3 files.readinteger4=fio.readinteger4 + files.readinteger1le=fio.readinteger1le or files.readinteger1le + files.readinteger2le=fio.readinteger2le or files.readinteger2le + files.readinteger3le=fio.readinteger3le or files.readinteger3le + files.readinteger4le=fio.readinteger4le or files.readinteger4le files.readfixed2=fio.readfixed2 files.readfixed4=fio.readfixed4 files.read2dot14=fio.read2dot14 @@ -4128,6 +4227,24 @@ if fio and fio.readcardinal1 then skipposition(f,4*(n or 1)) end end +if fio and fio.writecardinal1 then + files.writecardinal1=fio.writecardinal1 + files.writecardinal2=fio.writecardinal2 + files.writecardinal3=fio.writecardinal3 + files.writecardinal4=fio.writecardinal4 + files.writecardinal1le=fio.writecardinal1le + files.writecardinal2le=fio.writecardinal2le + files.writecardinal3le=fio.writecardinal3le + files.writecardinal4le=fio.writecardinal4le + files.writeinteger1=fio.writeinteger1 or fio.writecardinal1 + files.writeinteger2=fio.writeinteger2 or fio.writecardinal2 + files.writeinteger3=fio.writeinteger3 or fio.writecardinal3 + files.writeinteger4=fio.writeinteger4 or fio.writecardinal4 + files.writeinteger1le=files.writeinteger1le or fio.writecardinal1le + files.writeinteger2le=files.writeinteger2le or fio.writecardinal2le + files.writeinteger3le=files.writeinteger3le or fio.writecardinal3le + files.writeinteger4le=files.writeinteger4le or fio.writecardinal4le +end if fio and fio.readcardinaltable then files.readcardinaltable=fio.readcardinaltable files.readintegertable=fio.readintegertable @@ -4712,67 +4829,8 @@ end nodes.nodecodes=nodecodes nodes.glyphcodes=glyphcodes nodes.disccodes=disccodes -local flush_node=node.flush_node -local remove_node=node.remove -local traverse_id=node.traverse_id nodes.handlers.protectglyphs=node.protect_glyphs -nodes.handlers.unprotectglyphs=node.unprotect_glyphs -function nodes.remove(head,current,free_too) - local t=current - head,current=remove_node(head,current) - if t then - if free_too then - flush_node(t) - t=nil - else - t.next,t.prev=nil,nil - end - end - return head,current,t -end -function nodes.delete(head,current) - return nodes.remove(head,current,true) -end -local getfield=node.getfield -local setfield=node.setfield -nodes.getfield=getfield -nodes.setfield=setfield -nodes.getattr=getfield -nodes.setattr=setfield -nodes.tostring=node.tostring or tostring -nodes.copy=node.copy -nodes.copy_node=node.copy -nodes.copy_list=node.copy_list -nodes.delete=node.delete -nodes.dimensions=node.dimensions -nodes.end_of_math=node.end_of_math -nodes.flush_list=node.flush_list -nodes.flush_node=node.flush_node -nodes.flush=node.flush_node -nodes.free=node.free -nodes.insert_after=node.insert_after -nodes.insert_before=node.insert_before -nodes.hpack=node.hpack -nodes.new=node.new -nodes.tail=node.tail -nodes.traverse=node.traverse -nodes.traverse_id=node.traverse_id -nodes.slide=node.slide -nodes.vpack=node.vpack -nodes.first_glyph=node.first_glyph -nodes.has_glyph=node.has_glyph or node.first_glyph -nodes.current_attr=node.current_attr -nodes.has_field=node.has_field -nodes.last_node=node.last_node -nodes.usedlist=node.usedlist -nodes.protrusion_skippable=node.protrusion_skippable -nodes.write=node.write -nodes.has_attribute=node.has_attribute -nodes.set_attribute=node.set_attribute -nodes.unset_attribute=node.unset_attribute -nodes.protect_glyphs=node.protect_glyphs -nodes.unprotect_glyphs=node.unprotect_glyphs -nodes.mlist_to_hlist=node.mlist_to_hlist +nodes.handlers.unprotectglyphs=node.unprotect_glyphs local direct=node.direct local nuts={} nodes.nuts=nuts @@ -8637,7 +8695,6 @@ function constructors.scale(tfmdata,specification) local hasitalics=properties.hasitalics local autoitalicamount=properties.autoitalicamount local stackmath=not properties.nostackmath - local nonames=properties.noglyphnames local haskerns=properties.haskerns or properties.mode=="base" local hasligatures=properties.hasligatures or properties.mode=="base" local realdimensions=properties.realdimensions @@ -8744,6 +8801,7 @@ function constructors.scale(tfmdata,specification) local width=description.width local height=description.height local depth=description.depth + local isunicode=description.unicode if realdimensions then if not height or height==0 then local bb=description.boundingbox @@ -8768,16 +8826,16 @@ function constructors.scale(tfmdata,specification) if height then height=vdelta*height else height=scaledheight end if depth and depth~=0 then depth=delta*depth - if nonames then + if isunicode then chr={ index=index, height=height, depth=depth, width=width, + unicode=isunicode, } else chr={ - name=description.name, index=index, height=height, depth=depth, @@ -8785,33 +8843,23 @@ function constructors.scale(tfmdata,specification) } end else - if nonames then + if isunicode then chr={ index=index, height=height, width=width, + unicode=isunicode, } else chr={ - name=description.name, index=index, height=height, width=width, } end end - local isunicode=description.unicode if addtounicode then - if isunicode then - chr.unicode=isunicode - chr.tounicode=tounicode(isunicode) - else - chr.tounicode=unknowncode - end - else - if isunicode then - chr.unicode=isunicode - end + chr.tounicode=isunicode and tounicode(isunicode) or unknowncode end if hasquality then local ve=character.expansion_factor @@ -8881,7 +8929,10 @@ function constructors.scale(tfmdata,specification) if stackmath then local mk=character.mathkerns if mk then - local tr,tl,br,bl=mk.topright,mk.topleft,mk.bottomright,mk.bottomleft + local tr=mk.topright + local tl=mk.topleft + local br=mk.bottomright + local bl=mk.bottomleft chr.mathkern={ top_right=tr and mathkerns(tr,vdelta) or nil, top_left=tl and mathkerns(tl,vdelta) or nil, @@ -9167,7 +9218,9 @@ hashmethods.normal=function(list) end end function constructors.hashinstance(specification,force) - local hash,size,fallbacks=specification.hash,specification.size,specification.fallbacks + local hash=specification.hash + local size=specification.size + local fallbacks=specification.fallbacks if force or not hash then hash=constructors.hashfeatures(specification) specification.hash=hash @@ -9534,7 +9587,8 @@ function constructors.initializefeatures(what,tfmdata,features,trace,report) end end function constructors.collectprocessors(what,tfmdata,features,trace,report) - local processes,nofprocesses={},0 + local processes={} + local nofprocesses=0 if features and next(features) then local properties=tfmdata.properties local whathandler=handlers[what] @@ -10071,7 +10125,8 @@ function mappings.addtounicode(data,filename,checklookups,forceligatures) glyph.unicode=unicode end else - local t,n={},0 + local t={} + local n=0 for l=1,nsplit do local base=split[l] local u=unicodes[base] or unicodevector[base] or contextvector[name] @@ -10410,7 +10465,6 @@ local P,R,S,C,Cs,Cc,Ct,Carg,Cmt=lpeg.P,lpeg.R,lpeg.S,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg local lpegmatch=lpeg.match local rshift=bit32.rshift local setmetatableindex=table.setmetatableindex -local formatters=string.formatters local sortedkeys=table.sortedkeys local sortedhash=table.sortedhash local stripstring=string.nospaces @@ -14945,7 +14999,8 @@ end end end local function setbias(globals,locals) - local g,l=#globals,#locals + local g=#globals + local l=#locals return ((g<1240 and 107) or (g<33900 and 1131) or 32768)+1, ((l<1240 and 107) or (l<33900 and 1131) or 32768)+1 @@ -15681,7 +15736,8 @@ local function contours2outlines_normal(glyphs,shapes) local nofsegments=0 glyph.segments=segments if nofcontours>0 then - local px,py=0,0 + local px=0 + local py=0 local first=1 for i=1,nofcontours do local last=contours[i] @@ -15708,15 +15764,20 @@ local function contours2outlines_normal(glyphs,shapes) end control_pt=first_pt end - local x,y=first_pt[1],first_pt[2] + local x=first_pt[1] + local y=first_pt[2] if not done then - xmin,ymin,xmax,ymax=x,y,x,y + xmin=x + ymin=y + xmax=x + ymax=y done=true end nofsegments=nofsegments+1 segments[nofsegments]={ x,y,"m" } if not quadratic then - px,py=x,y + px=x + py=y end local previous_pt=first_pt for i=first,last do @@ -15735,8 +15796,10 @@ local function contours2outlines_normal(glyphs,shapes) control_pt=current_pt end elseif current_on then - local x1,y1=control_pt[1],control_pt[2] - local x2,y2=current_pt[1],current_pt[2] + local x1=control_pt[1] + local y1=control_pt[2] + local x2=current_pt[1] + local y2=current_pt[2] nofsegments=nofsegments+1 if quadratic then segments[nofsegments]={ x1,y1,x2,y2,"q" } @@ -15746,8 +15809,10 @@ local function contours2outlines_normal(glyphs,shapes) end control_pt=false else - local x2,y2=(previous_pt[1]+current_pt[1])/2,(previous_pt[2]+current_pt[2])/2 - local x1,y1=control_pt[1],control_pt[2] + local x2=(previous_pt[1]+current_pt[1])/2 + local y2=(previous_pt[2]+current_pt[2])/2 + local x1=control_pt[1] + local y1=control_pt[2] nofsegments=nofsegments+1 if quadratic then segments[nofsegments]={ x1,y1,x2,y2,"q" } @@ -15762,14 +15827,17 @@ local function contours2outlines_normal(glyphs,shapes) if first_pt==last_pt then else nofsegments=nofsegments+1 - local x2,y2=first_pt[1],first_pt[2] + local x2=first_pt[1] + local y2=first_pt[2] if not control_pt then segments[nofsegments]={ x2,y2,"l" } elseif quadratic then - local x1,y1=control_pt[1],control_pt[2] + local x1=control_pt[1] + local y1=control_pt[2] segments[nofsegments]={ x1,y1,x2,y2,"q" } else - local x1,y1=control_pt[1],control_pt[2] + local x1=control_pt[1] + local y1=control_pt[2] x1,y1,x2,y2,px,py=curveto(x1,y1,px,py,x2,y2) segments[nofsegments]={ x1,y1,x2,y2,px,py,"c" } end @@ -15828,7 +15896,8 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) end control_pt=first_pt end - local x,y=first_pt[1],first_pt[2] + local x=first_pt[1] + local y=first_pt[2] if not done then xmin,ymin,xmax,ymax=x,y,x,y done=true @@ -15841,7 +15910,8 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) segments[nofsegments]={ x,y,"m" } end if not quadratic then - px,py=x,y + px=x + py=y end local previous_pt=first_pt for i=first,last do @@ -15850,7 +15920,8 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) local previous_on=previous_pt[3] if previous_on then if current_on then - local x,y=current_pt[1],current_pt[2] + local x=current_pt[1] + local y=current_pt[2] if x<xmin then xmin=x elseif x>xmax then xmax=x end if y<ymin then ymin=y elseif y>ymax then ymax=y end if keepcurve then @@ -15858,14 +15929,17 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) segments[nofsegments]={ x,y,"l" } end if not quadratic then - px,py=x,y + px=x + py=y end else control_pt=current_pt end elseif current_on then - local x1,y1=control_pt[1],control_pt[2] - local x2,y2=current_pt[1],current_pt[2] + local x1=control_pt[1] + local y1=control_pt[2] + local x2=current_pt[1] + local y2=current_pt[2] if quadratic then if x1<xmin then xmin=x1 elseif x1>xmax then xmax=x1 end if y1<ymin then ymin=y1 elseif y1>ymax then ymax=y1 end @@ -15888,8 +15962,10 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) end control_pt=false else - local x2,y2=(previous_pt[1]+current_pt[1])/2,(previous_pt[2]+current_pt[2])/2 - local x1,y1=control_pt[1],control_pt[2] + local x2=(previous_pt[1]+current_pt[1])/2 + local y2=(previous_pt[2]+current_pt[2])/2 + local x1=control_pt[1] + local y1=control_pt[2] if quadratic then if x1<xmin then xmin=x1 elseif x1>xmax then xmax=x1 end if y1<ymin then ymin=y1 elseif y1>ymax then ymax=y1 end @@ -15921,8 +15997,10 @@ local function contours2outlines_shaped(glyphs,shapes,keepcurve) segments[nofsegments]={ first_pt[1],first_pt[2],"l" } end else - local x1,y1=control_pt[1],control_pt[2] - local x2,y2=first_pt[1],first_pt[2] + local x1=control_pt[1] + local y1=control_pt[2] + local x2=first_pt[1] + local y2=first_pt[2] if x1<xmin then xmin=x1 elseif x1>xmax then xmax=x1 end if y1<ymin then ymin=y1 elseif y1>ymax then ymax=y1 end if quadratic then @@ -19587,12 +19665,13 @@ function readers.avar(f,fontdata,specification) local lastfrom=false local lastto=false for i=1,nofvalues do - local f,t=read2dot14(f),read2dot14(f) - if lastfrom and f<=lastfrom then - elseif lastto and t>=lastto then + local from=read2dot14(f) + local to=read2dot14(f) + if lastfrom and from<=lastfrom then + elseif lastto and to>=lastto then else - values[#values+1]={ f,t } - lastfrom,lastto=f,t + values[#values+1]={ from,to } + lastfrom,lastto=from,to end end nofvalues=#values @@ -21074,7 +21153,9 @@ function readers.pack(data) end return false elseif nt>=threshold then - local one,two,rest=0,0,0 + local one=0 + local two=0 + local rest=0 if pass==1 then for k,v in next,c do if v==1 then @@ -22822,7 +22903,6 @@ local function copytotfm(data,cache_id) properties.space=spacer properties.encodingbytes=2 properties.format=data.format or formats.otf - properties.noglyphnames=true properties.filename=filename properties.fontname=fontname properties.fullname=fullname @@ -23176,7 +23256,9 @@ local function gref(descriptions,n) return f_unicode(n) end elseif n then - local num,nam,j={},{},0 + local num={} + local nam={} + local j=0 for i=1,#n do local ni=n[i] if tonumber(ni) then @@ -23381,12 +23463,15 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis local done=trace_baseinit and trace_ligatures and {} for i=1,nofligatures do local ligature=ligatures[i] - local unicode,tree=ligature[1],ligature[2] + local unicode=ligature[1] + local tree=ligature[2] make_1(present,tree,"ctx_"..unicode) end for i=1,nofligatures do local ligature=ligatures[i] - local unicode,tree,lookupname=ligature[1],ligature[2],ligature[3] + local unicode=ligature[1] + local tree=ligature[2] + local lookupname=ligature[3] make_2(present,tfmdata,characters,tree,"ctx_"..unicode,unicode,unicode,done,sequence) end end @@ -23952,7 +24037,8 @@ function injections.setmove(current,factor,rlmode,x,injection) end end function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk,checkmark) - local dx,dy=factor*(ba[1]-ma[1]),factor*(ba[2]-ma[2]) + local dx=factor*(ba[1]-ma[1]) + local dy=factor*(ba[2]-ma[2]) nofregisteredmarks=nofregisteredmarks+1 if rlmode>=0 then dx=tfmbase.width-dx @@ -25278,9 +25364,9 @@ if not classifiers then characters.classifiers=classifiers end function methods.arab(head,font,attr) - local first,last=nil,nil - local c_first,c_last=nil,nil - local current,done=head,false + local first,last,c_first,c_last + local current=head + local done=false current=tonut(current) while current do local char,id=ischar(current,font) @@ -26021,8 +26107,8 @@ function handlers.gsub_ligature(head,start,dataset,sequence,ligature,rlmode,skip local prev=getprev(start) if stop then setnext(stop) - local tail=getprev(stop) local copy=copy_node_list(start) + local tail=stop local liat=find_node_tail(copy) if pre then setlink(liat,pre) @@ -26113,7 +26199,8 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,skiphash,st end local format=step.format if format=="pair" then - local a,b=krn[1],krn[2] + local a=krn[1] + local b=krn[2] if a==true then elseif a then local x,y,w,h=setposition(1,start,factor,rlmode,a,injection) @@ -26631,7 +26718,8 @@ function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlm end local format=currentlookup.format if format=="pair" then - local a,b=krn[1],krn[2] + local a=krn[1] + local b=krn[2] if a==true then elseif a then local x,y,w,h=setposition(1,start,factor,rlmode,a,"injections") @@ -30034,7 +30122,7 @@ function handlers.devanagari_reorder_pre_base_reordering_consonants(head,start) end function handlers.devanagari_remove_joiners(head,start,kind,lookupname,replacement) local stop=getnext(start) - local font=getfont(start) + local font=getfont(start) local last=start while stop do local char=ischar(stop,font) @@ -31668,7 +31756,8 @@ local function addfeature(data,feature,specifications) if not nocheck and not description then skip=skip+1 elseif type(replacement)=="table" then - local r,n={},0 + local r={} + local n=0 for i=1,#replacement do local u=tounicode(replacement[i]) if nocheck or descriptions[u] then @@ -32601,13 +32690,15 @@ function afm.load(filename) local name=file.removesuffix(file.basename(filename)) local data=containers.read(afm.cache,name) local attr=lfs.attributes(filename) - local size,time=attr and attr.size or 0,attr and attr.modification or 0 + local size=attr and attr.size or 0 + local time=attr and attr.modification or 0 local pfbfile=file.replacesuffix(name,"pfb") local pfbname=resolvers.findfile(pfbfile,"pfb") or "" if pfbname=="" then pfbname=resolvers.findfile(file.basename(pfbfile),"pfb") or "" end - local pfbsize,pfbtime=0,0 + local pfbsize=0 + local pfbtime=0 if pfbname~="" then local attr=lfs.attributes(pfbname) pfbsize=attr.size or 0 @@ -32816,7 +32907,8 @@ local addthem=function(rawdata,ligatures) local one=descriptions[unicodes[ligname]] if one then for _,pair in next,ligdata do - local two,three=unicodes[pair[1]],unicodes[pair[2]] + local two=unicodes[pair[1]] + local three=unicodes[pair[2]] if two and three then local ol=one.ligatures if ol then @@ -32916,7 +33008,8 @@ local function adddimensions(data) for unicode,description in next,data.descriptions do local bb=description.boundingbox if bb then - local ht,dp=bb[4],-bb[2] + local ht=bb[4] + local dp=-bb[2] if ht==0 or ht<0 then else description.height=ht @@ -33182,7 +33275,7 @@ local function check_afm(specification,fullname) if foundname=="" then foundname=fonts.names.getfilename(fullname,"afm") or "" end - if foundname=="" and afm.autoprefixed then + if fullname and foundname=="" and afm.autoprefixed then local encoding,shortname=match(fullname,"^(.-)%-(.*)$") if encoding and shortname and fonts.encodings.known[encoding] then shortname=findbinfile(shortname,'afm') or "" diff --git a/tex/generic/context/luatex/luatex-fonts.lua b/tex/generic/context/luatex/luatex-fonts.lua index 69908dfcc..06fb682f3 100644 --- a/tex/generic/context/luatex/luatex-fonts.lua +++ b/tex/generic/context/luatex/luatex-fonts.lua @@ -209,8 +209,8 @@ if non_generic_context.luatex_fonts.skip_loading ~= true then -- A few slightly higher level support modules: - loadmodule("util-str.lua") - loadmodule("util-fil.lua") + loadmodule("util-str.lua") -- future versions can ship without this one + loadmodule("util-fil.lua") -- future versions can ship without this one -- The following modules contain code that is either not used at all -- outside context or will fail when enabled due to lack of other diff --git a/tex/generic/context/luatex/luatex-plain.tex b/tex/generic/context/luatex/luatex-plain.tex index 0a806c76f..f45608f7a 100644 --- a/tex/generic/context/luatex/luatex-plain.tex +++ b/tex/generic/context/luatex/luatex-plain.tex @@ -52,4 +52,6 @@ \edef\fmtversion{\fmtversion+luatex} +\automatichyphenmode=1 + \dump |