diff options
Diffstat (limited to 'tex')
30 files changed, 1703 insertions, 329 deletions
diff --git a/tex/context/base/mkii/cont-new.mkii b/tex/context/base/mkii/cont-new.mkii index ede175893..d256c24d9 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{2017.04.08 12:09} +\newcontextversion{2017.04.16 12:32} %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 cc11308ef..26595dd56 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{2017.04.08 12:09} +\edef\contextversion{2017.04.16 12:32} %D For those who want to use this: diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv index 3b0c97ff0..0d9ecfdd7 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{2017.04.08 12:09} +\newcontextversion{2017.04.16 12:32} %D This file is loaded at runtime, thereby providing an excellent place for %D hacks, patches, extensions and new features. diff --git a/tex/context/base/mkiv/cont-run.lua b/tex/context/base/mkiv/cont-run.lua index d9dad3f2d..2225a0fb2 100644 --- a/tex/context/base/mkiv/cont-run.lua +++ b/tex/context/base/mkiv/cont-run.lua @@ -180,6 +180,10 @@ local function processjob() local suffix = environment.suffix local filename = environment.filename -- hm, not inputfilename ! + if arguments.synctex then + directives.enable("system.synctex="..tostring(arguments.synctex)) + end + if not filename or filename == "" then -- skip elseif suffix == "xml" or arguments.forcexml then diff --git a/tex/context/base/mkiv/cont-run.mkiv b/tex/context/base/mkiv/cont-run.mkiv index fcca7b581..490c6bee2 100644 --- a/tex/context/base/mkiv/cont-run.mkiv +++ b/tex/context/base/mkiv/cont-run.mkiv @@ -15,6 +15,7 @@ \unprotect +\registerctxluafile{node-syn}{1.001} \registerctxluafile{cont-run}{1.001} \protect \endinput diff --git a/tex/context/base/mkiv/context.mkiv b/tex/context/base/mkiv/context.mkiv index 14f619247..c4446b3dd 100644 --- a/tex/context/base/mkiv/context.mkiv +++ b/tex/context/base/mkiv/context.mkiv @@ -39,7 +39,7 @@ %D up and the dependencies are more consistent. \edef\contextformat {\jobname} -\edef\contextversion{2017.04.08 12:09} +\edef\contextversion{2017.04.16 12:32} \edef\contextkind {beta} %D For those who want to use this: @@ -403,6 +403,7 @@ \loadmarkfile{tabl-ntb} \loadmarkfile{tabl-nte} \loadmarkfile{tabl-ltb} +\loadmarkfile{tabl-frm} \loadmarkfile{tabl-tsp} \loadmkvifile{tabl-xtb} \loadmarkfile{tabl-mis} diff --git a/tex/context/base/mkiv/font-ctx.lua b/tex/context/base/mkiv/font-ctx.lua index 0e64511e2..9e53b2c25 100644 --- a/tex/context/base/mkiv/font-ctx.lua +++ b/tex/context/base/mkiv/font-ctx.lua @@ -156,16 +156,17 @@ end helpers.name = getfontname +local addformatter = utilities.strings.formatters.add + if _LUAVERSION < 5.2 then - formatters.add(formatters,"font:name", [["'"..fontname(%s).."'"]], "local fontname = fonts.helpers.name") - formatters.add(formatters,"font:features",[["'"..sequenced(%s," ",true).."'"]],"local sequenced = table.sequenced") + addformatter(formatters,"font:name", [["'"..fontname(%s).."'"]], "local fontname = fonts.helpers.name") + addformatter(formatters,"font:features",[["'"..sequenced(%s," ",true).."'"]],"local sequenced = table.sequenced") else - -- somehow can fail: - formatters.add(formatters,"font:name", [["'"..fontname(%s).."'"]], { fontname = helpers.name }) - formatters.add(formatters,"font:features",[["'"..sequenced(%s," ",true).."'"]],{ sequenced = table.sequenced }) + addformatter(formatters,"font:name", [["'"..fontname(%s).."'"]], { fontname = helpers.name }) + addformatter(formatters,"font:features",[["'"..sequenced(%s," ",true).."'"]],{ sequenced = table.sequenced }) end @@ -183,12 +184,12 @@ do local shares = { } local hashes = { } -local nofinstances = 0 -local instances = table.setmetatableindex(function(t,k) - nofinstances = nofinstances + 1 - t[k] = nofinstances - return nofinstances -end) + local nofinstances = 0 + local instances = table.setmetatableindex(function(t,k) + nofinstances = nofinstances + 1 + t[k] = nofinstances + return nofinstances + end) function constructors.trytosharefont(target,tfmdata) constructors.noffontsloaded = constructors.noffontsloaded + 1 @@ -347,21 +348,13 @@ otftables.scripts.auto = "automatic fallback to latn when no dflt present" -- setmetatableindex(otffeatures.descriptions,otftables.features) -local privatefeatures = { -- this can go away - tlig = true, - trep = true, - anum = true, -} - local function checkedscript(tfmdata,resources,features) local latn = false local script = false if resources.features then for g, list in next, resources.features do for f, scripts in next, list do - if privatefeatures[f] then - -- skip - elseif scripts.dflt then + if scripts.dflt then script = "dflt" break elseif scripts.latn then diff --git a/tex/context/base/mkiv/font-def.lua b/tex/context/base/mkiv/font-def.lua index 6765be9d3..c8394badf 100644 --- a/tex/context/base/mkiv/font-def.lua +++ b/tex/context/base/mkiv/font-def.lua @@ -11,8 +11,9 @@ if not modules then modules = { } end modules ['font-def'] = { local lower, gsub = string.lower, string.gsub local tostring, next = tostring, next local lpegmatch = lpeg.match -local suffixonly, removesuffix = file.suffix, file.removesuffix +local suffixonly, removesuffix, basename = file.suffix, file.removesuffix, file.basename local formatters = string.formatters +local sortedhash, sortedkeys = table.sortedhash, table.sortedkeys local allocate = utilities.storage.allocate @@ -203,9 +204,9 @@ function resolvers.name(specification) features.normal = normal end normal.instance = instance -if not callbacks.supported.glyph_stream_provider then - normal.variableshapes = true -- for the moment -end + if not callbacks.supported.glyph_stream_provider then + normal.variableshapes = true -- for the moment + end end -- local suffix = lower(suffixonly(resolved)) @@ -313,6 +314,65 @@ local function checkembedding(tfmdata) tfmdata.embedding = embedding end +local function checkfeatures(tfmdata) + local resources = tfmdata.resources + local shared = tfmdata.shared + if resources and shared then + local features = resources.features + local usedfeatures = shared.features + if features and usedfeatures then + local usedlanguage = usedfeatures.language or "dflt" + local usedscript = usedfeatures.script or "dflt" + local function check(what) + if what then + local foundlanguages = { } + for feature, scripts in next, what do + if usedscript == "auto" or scripts["*"] then + -- ok + elseif not scripts[usedscript] then + -- report_defining("font %!font:name!, feature %a, no script %a", + -- tfmdata,feature,usedscript) + else + for script, languages in next, scripts do + if languages["*"] then + -- ok + elseif not languages[usedlanguage] then + report_defining("font %!font:name!, feature %a, script %a, no language %a", + tfmdata,feature,script,usedlanguage) + end + end + end + for script, languages in next, scripts do + for language in next, languages do + foundlanguages[language] = true + end + end + end + if false then + foundlanguages["*"] = nil + foundlanguages = sortedkeys(foundlanguages) + for feature, scripts in sortedhash(what) do + for script, languages in next, scripts do + if not languages["*"] then + for i=1,#foundlanguages do + local language = foundlanguages[i] + if not languages[language] then + report_defining("font %!font:name!, feature %a, script %a, no language %a", + tfmdata,feature,script,language) + end + end + end + end + end + end + end + end + check(features.gsub) + check(features.gpos) + end + end +end + function definers.loadfont(specification) local hash = constructors.hashinstance(specification) -- todo: also hash by instance / factors @@ -347,6 +407,7 @@ function definers.loadfont(specification) checkembedding(tfmdata) -- todo: general postprocessor loadedfonts[hash] = tfmdata designsizes[specification.hash] = tfmdata.parameters.designsize + checkfeatures(tfmdata) end end if not tfmdata then @@ -458,7 +519,7 @@ function definers.read(specification,size,id) -- id can be optional, name can al local parameters = tfmdata.parameters or { } report_defining("using %a font with id %a, name %a, size %a, bytes %a, encoding %a, fullname %a, filename %a", properties.format or "unknown", id, properties.name, parameters.size, properties.encodingbytes, - properties.encodingname, properties.fullname, file.basename(properties.filename)) + properties.encodingname, properties.fullname, basename(properties.filename)) end statistics.stoptiming(fonts) return tfmdata diff --git a/tex/context/base/mkiv/font-dsp.lua b/tex/context/base/mkiv/font-dsp.lua index 76bc5912d..d2aea7037 100644 --- a/tex/context/base/mkiv/font-dsp.lua +++ b/tex/context/base/mkiv/font-dsp.lua @@ -3024,6 +3024,195 @@ function readers.svg(f,fontdata,specification) fontdata.hascolor = true end +function readers.sbix(f,fontdata,specification) + local tableoffset = gotodatatable(f,fontdata,"sbix",specification.glyphs) + if tableoffset then + local version = readushort(f) + local flags = readushort(f) + local nofstrikes = readulong(f) + local strikes = { } + local nofglyphs = fontdata.nofglyphs + for i=1,nofstrikes do + strikes[i] = readulong(f) + end + -- if true then + local shapes = { } + local done = 0 + for i=1,nofstrikes do + local strikeoffset = strikes[i] + tableoffset + setposition(f,strikeoffset) + strikes[i] = { + ppem = readushort(f), + ppi = readushort(f), + offset = strikeoffset + } + end + -- highest first + sort(strikes,function(a,b) + if b.ppem == a.ppem then + return b.ppi < a.ppi + else + return b.ppem < a.ppem + end + end) + local glyphs = { } + for i=1,nofstrikes do + local strike = strikes[i] + local strikeppem = strike.ppem + local strikeppi = strike.ppi + local strikeoffset = strike.offset + setposition(f,strikeoffset) + for i=0,nofglyphs do + glyphs[i] = readulong(f) + end + local glyphoffset = glyphs[0] + for i=0,nofglyphs-1 do + local nextoffset = glyphs[i+1] + if not shapes[i] then + local datasize = nextoffset - glyphoffset + if datasize > 0 then + setposition(f,strikeoffset + glyphoffset) + shapes[i] = { + x = readshort(f), + y = readshort(f), + tag = readtag(f), -- maybe for tracing + data = readstring(f,datasize-8), + ppem = strikeppem, -- not used, for tracing + ppi = strikeppi, -- not used, for tracing + } + done = done + 1 + if done == nofglyphs then + break + end + end + end + glyphoffset = nextoffset + end + end + fontdata.sbixshapes = shapes + -- else + -- for i=1,nofstrikes do + -- local strikeoffset = strikes[i] + tableoffset + -- setposition(f,strikeoffset) + -- local glyphs = { } + -- strikes[i] = { + -- ppem = readushort(f), + -- ppi = readushort(f), + -- glyphs = glyphs, + -- } + -- for i=0,nofglyphs do + -- glyphs[i] = readulong(f) + -- end + -- local glyphoffset = glyphs[0] + -- for i=0,nofglyphs-1 do + -- local nextoffset = glyphs[i+1] + -- local datasize = nextoffset - glyphoffset + -- if datasize > 0 then + -- setposition(f,strikeoffset + glyphoffset) + -- glyphs[i] = { + -- x = readshort(f), + -- y = readshort(f), + -- tag = readtag(f), + -- data = readstring(f,datasize-8) + -- } + -- glyphoffset = nextoffset + -- end + -- end + -- end + -- fontdata.sbixshapes = strikes + -- end + end +end + +-- function readers.cblc(f,fontdata,specification) +-- local tableoffset = gotodatatable(f,fontdata,"cblc",specification.glyphs) +-- if tableoffset then +-- end +-- end +-- +-- function readers.cbdt(f,fontdata,specification) +-- local tableoffset = gotodatatable(f,fontdata,"ctdt",specification.glyphs) +-- if tableoffset then +-- +-- local function getmetrics(f) +-- return { +-- ascender = readinteger(f), +-- descender = readinteger(f), +-- widthmax = readcardinal(f), +-- caretslopedumerator = readinteger(f), +-- caretslopedenominator = readinteger(f), +-- caretoffset = readinteger(f), +-- minorigin = readinteger(f), +-- minadvance = readinteger(f), +-- maxbefore = readinteger(f), +-- minafter = readinteger(f), +-- pad1 = readinteger(f), +-- pad2 = readinteger(f), +-- } +-- end +-- +-- local majorversion = readushort(f) +-- local minorversion = readushort(f) +-- local nofsizetables = readulong(f) +-- local sizetable = { } +-- for i=1,nofsizetables do +-- sizetable[i] = { +-- subtables = readulong(f), +-- indexsize = readulong(f), +-- nofsubtables = readulong(f), +-- colorref = readulong(f), +-- hormetrics = getmetrics(f), +-- vermetrics = getmetrics(f), +-- firstindex = readushort(f), +-- lastindex = readushort(f), +-- ppemx = readbyte(f), +-- ppemy = readbyte(f), +-- bitdepth = readbyte(f), +-- flags = readbyte(f), +-- } +-- end +-- +-- sort(sizetable,function(a,b) +-- if b.ppemx == a.ppemx then +-- return b.bitdepth < a.bitdepth +-- else +-- return b.ppemx < a.ppemx +-- end +-- end) +-- +-- local shapes = { } +-- +-- for i=1,nofsizetables do +-- local s = sizetables[i] +-- for j=firstindex,lastindex do +-- if not shapes[j] then +-- shapes[j] = { +-- i +-- } +-- end +-- end +-- end +-- +-- inspect(shapes) +-- +-- end +-- end + +-- function readers.ebdt(f,fontdata,specification) +-- if specification.glyphs then +-- end +-- end + +-- function readers.ebsc(f,fontdata,specification) +-- if specification.glyphs then +-- end +-- end + +-- function readers.eblc(f,fontdata,specification) +-- if specification.glyphs then +-- end +-- end + -- + AVAR : optional -- + CFF2 : otf outlines -- - CVAR : ttf hinting, not needed diff --git a/tex/context/base/mkiv/font-ocl.lua b/tex/context/base/mkiv/font-ocl.lua index 68d9ac650..2cb0c1eb7 100644 --- a/tex/context/base/mkiv/font-ocl.lua +++ b/tex/context/base/mkiv/font-ocl.lua @@ -10,6 +10,7 @@ if not modules then modules = { } end modules ['font-ocl'] = { local tostring, next, format = tostring, next, string.format local round, max = math.round, math.round +local sortedkeys, sortedhash = table.sortedkeys, table.sortedhash local formatters = string.formatters local tounicode = fonts.mappings.tounicode @@ -175,14 +176,8 @@ fonts.handlers.otf.features.register { } } -local otfsvg = otf.svg or { } -otf.svg = otfsvg -otf.svgenabled = true - do - local nofstreams = 0 - -- local f_setstream = formatters[ [[io.savedata("svg-glyph-%05i",%q)]] ] -- local f_getstream = formatters[ [[svg-glyph-%05i]] ] @@ -194,47 +189,125 @@ do -- end -- end - local f_name = formatters[ [[svg-glyph-%05i]] ] - local f_used = context and formatters[ [[original:///%s]] ] or formatters[ [[%s]] ] + local nofstreams = 0 + local f_name = formatters[ [[pdf-glyph-%05i]] ] + local f_used = context and formatters[ [[original:///%s]] ] or formatters[ [[%s]] ] + local hashed = { } + local cache = { } + + function otf.storepdfdata(pdf) + local done = hashed[pdf] + if not done then + nofstreams = nofstreams + 1 + local o, n = epdf.openMemStream(pdf,#pdf,f_name(nofstreams)) + cache[n] = o -- we need to keep in mem + done = f_used(n) + hashed[pdf] = done + end + return nil, done, nil + end - local cache = { } + -- maybe more efficient but much slower (and we hash already) + -- + -- if context then + -- + -- local storepdfdata = otf.storepdfdata + -- local initialized = false + -- + -- function otf.storepdfdata(pdf) + -- if not initialized then + -- if resolvers.setmemstream then + -- local f_setstream = formatters[ [[resolvers.setmemstream("pdf-glyph-%05i",%q,true)]] ] + -- local f_getstream = formatters[ [[memstream:///pdf-glyph-%05i]] ] + -- local f_nilstream = formatters[ [[resolvers.resetmemstream("pdf-glyph-%05i",true)]] ] + -- storepdfdata = function(pdf) + -- local done = hashed[pdf] + -- local set = nil + -- local reset = nil + -- if not done then + -- nofstreams = nofstreams + 1 + -- set = f_setstream(nofstreams,pdf) + -- done = f_getstream(nofstreams) + -- reset = f_nilstream(nofstreams) + -- hashed[pdf] = done + -- end + -- return set, done, reset + -- end + -- otf.storepdfdata = storepdfdata + -- end + -- initialized = true + -- end + -- return storepdfdata(pdf) + -- end + -- + -- end - function otfsvg.storepdfdata(pdf) - nofstreams = nofstreams + 1 - local o, n = epdf.openMemStream(pdf,#pdf,f_name(nofstreams)) - cache[n] = o -- we need to keep in mem - return nil, f_used(n), nil - end +end - if context then - - local storepdfdata = otfsvg.storepdfdata - local initialized = false - - function otfsvg.storepdfdata(pdf) - if not initialized then - if resolvers.setmemstream then - local f_setstream = formatters[ [[resolvers.setmemstream("svg-glyph-%05i",%q,true)]] ] - local f_getstream = formatters[ [[memstream:///svg-glyph-%05i]] ] - local f_nilstream = formatters[ [[resolvers.resetmemstream("svg-glyph-%05i",true)]] ] - storepdfdata = function(pdf) - nofstreams = nofstreams + 1 - return - f_setstream(nofstreams,pdf), - f_getstream(nofstreams), - f_nilstream(nofstreams) - end - otfsvg.storepdfdata = storepdfdata +local function pdftovirtual(tfmdata,pdfshapes,kind) -- kind = sbix|svg + if not tfmdata or not pdfshapes or not kind then + return + end + -- + local characters = tfmdata.characters + local properties = tfmdata.properties + local parameters = tfmdata.parameters + local hfactor = parameters.hfactor + -- + properties.virtualized = true + -- + tfmdata.fonts = { + { id = 0 } + } + -- + local getactualtext = otf.getactualtext + local storepdfdata = otf.storepdfdata + -- + -- local nop = { "nop" } + -- + for unicode, character in sortedhash(characters) do -- sort is nicer for svg + local index = character.index + if index then + local pdf = pdfshapes[index] + local typ = type(pdf) + local data = nil + local dx = nil + local dy = nil + if typ == "table" then + data = pdf.data + dx = pdf.dx or 0 + dy = pdf.dy or 0 + elseif typ == "string" then + data = pdf + dx = 0 + dy = 0 + end + if data then + local setcode, name, nilcode = storepdfdata(data) + if name then + local bt, et = getactualtext(unicode) + local wd = character.width or 0 + local ht = character.height or 0 + local dp = character.depth or 0 + character.commands = { + { "special", "pdf:direct:" .. bt }, + { "down", dp + dy * hfactor }, + { "right", dx * hfactor }, + -- setcode and { "lua", setcode } or nop, + { "image", { filename = name, width = wd, height = ht, depth = dp } }, + -- nilcode and { "lua", nilcode } or nop, + { "special", "pdf:direct:" .. et }, + } + character[kind] = true end - initialized = true end - return storepdfdata(pdf) end - end - end +local otfsvg = otf.svg or { } +otf.svg = otfsvg +otf.svgenabled = true do @@ -323,7 +396,7 @@ do end statistics.stoptiming() if statistics.elapsedseconds then - report_svg("svg conversion time %s",statistics.elapsedseconds()) + report_svg("svg conversion time %s",statistics.elapsedseconds() or "-") end end return pdfshapes @@ -333,17 +406,12 @@ end local function initializesvg(tfmdata,kind,value) -- hm, always value if value and otf.svgenabled then - local characters = tfmdata.characters - local descriptions = tfmdata.descriptions - local properties = tfmdata.properties - -- - local svg = properties.svg + local svg = tfmdata.properties.svg local hash = svg and svg.hash local timestamp = svg and svg.timestamp if not hash then return end - -- local pdffile = containers.read(otf.pdfcache,hash) local pdfshapes = pdffile and pdffile.pdfshapes if not pdfshapes or pdffile.timestamp ~= timestamp then @@ -355,44 +423,7 @@ local function initializesvg(tfmdata,kind,value) -- hm, always value timestamp = timestamp, }) end - if not pdfshapes or not next(pdfshapes) then - return - end - -- - properties.virtualized = true - tfmdata.fonts = { - { id = 0 } - } - -- - local getactualtext = otf.getactualtext - local storepdfdata = otfsvg.storepdfdata - -- - local nop = { "nop" } - -- - for unicode, character in next, characters do - local index = character.index - if index then - local pdf = pdfshapes[index] - if pdf then - local setcode, name, nilcode = storepdfdata(pdf) - if name then - local bt, et = getactualtext(unicode) - local wd = character.width or 0 - local ht = character.height or 0 - local dp = character.depth or 0 - character.commands = { - { "special", "pdf:direct:" .. bt }, - { "down", dp }, - setcode and { "lua", setcode } or nop, - { "image", { filename = name, width = wd, height = ht, depth = dp } }, - nilcode and { "lua", nilcode } or nop, - { "special", "pdf:direct:" .. et }, - } - character.svg = true - end - end - end - end + pdftovirtual(tfmdata,pdfshapes,"svg") end end @@ -404,3 +435,114 @@ fonts.handlers.otf.features.register { node = initializesvg, } } + +-- This can be done differently e.g. with ffi and gm and we can share code anway. Using +-- batchmode in gm is not faster and as it accumulates we would need to flush all +-- individual shapes. + +local otfsbix = otf.sbix or { } +otf.sbix = otfsbix +otf.sbixenabled = true + +do + + -- for now png but also other bitmap formats + + local report_sbix = logs.reporter("fonts","sbix conversion") + + local loaddata = io.loaddata + local savedata = io.savedata + local remove = os.remove + + local runner = sandbox and sandbox.registerrunner { + name = "otfsbix", + program = "gm", + template = "convert -quality 100 temp-otf-sbix-shape.sbix temp-otf-sbix-shape.pdf > temp-otf-svg-shape.log", + -- reporter = report_sbix, + } + + if not runner then + -- + -- poor mans variant for generic: + -- + runner = function() + return os.execute("gm convert -quality 100 temp-otf-sbix-shape.sbix temp-otf-sbix-shape.pdf > temp-otf-svg-shape.log") + end + end + + -- Alternatively we can create a single pdf file with -adjoin and then pick up pages from + -- that file but creating thousands of small files is no fun either. + + function otfsbix.topdf(sbixshapes) + local pdfshapes = { } + local sbixfile = "temp-otf-sbix-shape.sbix" + local pdffile = "temp-otf-sbix-shape.pdf" + local nofdone = 0 + local indices = sortedkeys(sbixshapes) -- can be sparse + local nofindices = #indices + report_sbix("processing %i sbix containers",nofindices) + statistics.starttiming() + for i=1,nofindices do + local index = indices[i] + local entry = sbixshapes[index] + local data = entry.data + local x = entry.x + local y = entry.y + savedata(sbixfile,data) + runner() + pdfshapes[index] = { + x = x ~= 0 and x or nil, + y = y ~= 0 and y or nil, + data = loaddata(pdffile), + } + nofdone = nofdone + 1 + if nofdone % 100 == 0 then + report_sbix("%i shapes processed",nofdone) + end + end + report_sbix("processing %i pdf results",nofindices) + remove(sbixfile) + remove(pdffile) + statistics.stoptiming() + if statistics.elapsedseconds then + report_sbix("sbix conversion time %s",statistics.elapsedseconds() or "-") + end + return pdfshapes + -- end + end + +end + +local function initializesbix(tfmdata,kind,value) -- hm, always value + if value and otf.sbixenabled then + local sbix = tfmdata.properties.sbix + local hash = sbix and sbix.hash + local timestamp = sbix and sbix.timestamp + if not hash then + return + end + local pdffile = containers.read(otf.pdfcache,hash) + local pdfshapes = pdffile and pdffile.pdfshapes + if not pdfshapes or pdffile.timestamp ~= timestamp then + local sbixfile = containers.read(otf.sbixcache,hash) + local sbixshapes = sbixfile and sbixfile.sbixshapes + pdfshapes = sbixshapes and otfsbix.topdf(sbixshapes) or { } + containers.write(otf.pdfcache, hash, { + pdfshapes = pdfshapes, + timestamp = timestamp, + }) + end + -- + pdftovirtual(tfmdata,pdfshapes,"sbix") + end +end + +fonts.handlers.otf.features.register { + name = "sbix", + description = "sbix glyphs", + manipulators = { + base = initializesbix, + node = initializesbix, + } +} + diff --git a/tex/context/base/mkiv/font-otc.lua b/tex/context/base/mkiv/font-otc.lua index bed2adf85..1866591b4 100644 --- a/tex/context/base/mkiv/font-otc.lua +++ b/tex/context/base/mkiv/font-otc.lua @@ -10,7 +10,6 @@ local format, insert, sortedkeys, tohash = string.format, table.insert, table.so local type, next = type, next local lpegmatch = lpeg.match local utfbyte, utflen, utfsplit = utf.byte, utf.len, utf.split -local settings_to_array = utilities.parsers.settings_to_array -- we assume that the other otf stuff is loaded already @@ -1040,6 +1039,9 @@ registerotffeature { description = 'block certain ligatures', } +local settings_to_array = utilities.parsers and utilities.parsers.settings_to_array + or function(s) return string.split(s,",") end -- for generic + local function blockligatures(str) local t = settings_to_array(str) diff --git a/tex/context/base/mkiv/font-otl.lua b/tex/context/base/mkiv/font-otl.lua index 9e4e255e3..c0b152a5b 100644 --- a/tex/context/base/mkiv/font-otl.lua +++ b/tex/context/base/mkiv/font-otl.lua @@ -53,11 +53,13 @@ local fonts = fonts local otf = fonts.handlers.otf otf.version = 3.028 -- beware: also sync font-mis.lua and in mtx-fonts -otf.cache = containers.define("fonts", "otl", otf.version, true) -otf.svgcache = containers.define("fonts", "svg", otf.version, true) -otf.pdfcache = containers.define("fonts", "pdf", otf.version, true) +otf.cache = containers.define("fonts", "otl", otf.version, true) +otf.svgcache = containers.define("fonts", "svg", otf.version, true) +otf.sbixcache = containers.define("fonts", "sbix", otf.version, true) +otf.pdfcache = containers.define("fonts", "pdf", otf.version, true) otf.svgenabled = false +otf.sbixenabled = false local otfreaders = otf.readers @@ -127,8 +129,10 @@ function otf.load(filename,sub,instance) starttiming(otfreaders) data = otfreaders.loadfont(filename,sub or 1,instance) -- we can pass the number instead (if it comes from a name search) if data then - local resources = data.resources - local svgshapes = resources.svgshapes + -- todo: make this a plugin + local resources = data.resources + local svgshapes = resources.svgshapes + local sbixshapes = resources.sbixshapes if svgshapes then resources.svgshapes = nil if otf.svgenabled then @@ -144,6 +148,22 @@ function otf.load(filename,sub,instance) } end end + if sbixshapes then + resources.sbixshapes = nil + if otf.sbixenabled then + local timestamp = os.date() + -- work in progress ... a bit boring to do + containers.write(otf.sbixcache,hash, { + sbixshapes = sbixshapes, + timestamp = timestamp, + }) + data.properties.sbix = { + hash = hash, + timestamp = timestamp, + } + end + end + -- otfreaders.compact(data) otfreaders.rehash(data,"unicodes") otfreaders.addunicodetable(data) diff --git a/tex/context/base/mkiv/font-otr.lua b/tex/context/base/mkiv/font-otr.lua index 3935ca735..fcfe6e824 100644 --- a/tex/context/base/mkiv/font-otr.lua +++ b/tex/context/base/mkiv/font-otr.lua @@ -133,15 +133,6 @@ end local tableversion = 0.004 readers.tableversion = tableversion local privateoffset = fonts.constructors and fonts.constructors.privateoffset or 0xF0000 -- 0x10FFFF -local reportedskipped = { } - - -local function reportskippedtable(tag) - if not reportedskipped[tag] then - report("loading of table %a skipped (reported once only)",tag) - reportedskipped[tag] = true - end -end -- We have quite some data tables. We are somewhat ff compatible with names but as I used -- the information from the microsoft site there can be differences. Eventually I might end @@ -720,6 +711,15 @@ local function gotodatatable(f,fontdata,tag,criterium) end end +local function reportskippedtable(f,fontdata,tag,criterium) + if criterium and f then + local datatable = fontdata.tables[tag] + if datatable then + report("loading of table %a skipped",tag) + end + end +end + local function setvariabledata(fontdata,tag,data) local variabledata = fontdata.variabledata if variabledata then @@ -729,8 +729,9 @@ local function setvariabledata(fontdata,tag,data) end end -helpers.gotodatatable = gotodatatable -helpers.setvariabledata = setvariabledata +helpers.gotodatatable = gotodatatable +helpers.setvariabledata = setvariabledata +helpers.reportskippedtable = reportskippedtable -- The name table is probably the first one to load. After all this one provides -- useful information about what we deal with. The complication is that we need @@ -1181,9 +1182,7 @@ readers.vmtx = function(f,fontdata,specification) end readers.vorg = function(f,fontdata,specification) - if specification.glyphs then - -- reportskippedtable("vorg") - end + reportskippedtable(f,fontdata,"vorg",specification.glyphs) end -- The post table relates to postscript (printing) but has some relevant properties for other @@ -1254,9 +1253,7 @@ readers.post = function(f,fontdata,specification) end readers.cff = function(f,fontdata,specification) - if specification.glyphs then - reportskippedtable("cff") - end + reportskippedtable(f,fontdata,"cff",specification.glyphs) end -- Not all cmaps make sense .. e.g. dfont is obsolete and probably more are not relevant. Let's see @@ -1745,35 +1742,55 @@ end -- although we not need it in our usage (yet). We can remove the locations table when we're done. function readers.loca(f,fontdata,specification) - if specification.glyphs then - reportskippedtable("loca") - end + reportskippedtable(f,fontdata,"loca",specification.glyphs) end function readers.glyf(f,fontdata,specification) -- part goes to cff module - if specification.glyphs then - reportskippedtable("glyf") - end + reportskippedtable(f,fontdata,"glyf",specification.glyphs) end --- Experimental (we need fonts). +-- The MicroSoft variant is pretty clean and is supported (implemented elsewhere) +-- just because I wanted to see how such a font looks like. function readers.colr(f,fontdata,specification) - if specification.glyphs then - reportskippedtable("colr") - end + reportskippedtable(f,fontdata,"colr",specification.glyphs) end - function readers.cpal(f,fontdata,specification) - if specification.glyphs then - reportskippedtable("cpal") - end + reportskippedtable(f,fontdata,"cpal",specification.glyphs) end +-- This one is also supported, if only because I could locate a proper font for +-- testing. + function readers.svg(f,fontdata,specification) - if specification.glyphs then - reportskippedtable("svg") - end + reportskippedtable(f,fontdata,"svg",specification.glyphs) +end + +-- There is a font from apple to test the next one. Will there be more? Anyhow, +-- it's relatively easy to support, so I did it. + +function readers.sbix(f,fontdata,specification) + reportskippedtable(f,fontdata,"sbix",specification.glyphs) +end + +-- I'm only willing to look into the next variant if I see a decent and complete (!) +-- font and more can show up. It makes no sense to waste time on ideas. Okay, the +-- apple font also has these tables. + +function readers.cbdt(f,fontdata,specification) + reportskippedtable(f,fontdata,"cbdt",specification.glyphs) +end +function readers.cblc(f,fontdata,specification) + reportskippedtable(f,fontdata,"cblc",specification.glyphs) +end +function readers.ebdt(f,fontdata,specification) + reportskippedtable(f,fontdata,"ebdt",specification.glyphs) +end +function readers.ebsc(f,fontdata,specification) + reportskippedtable(f,fontdata,"ebsc",specification.glyphs) +end +function readers.eblc(f,fontdata,specification) + reportskippedtable(f,fontdata,"eblc",specification.glyphs) end -- Here we have a table that we really need for later processing although a more advanced gpos table @@ -1819,27 +1836,19 @@ function readers.kern(f,fontdata,specification) end function readers.gdef(f,fontdata,specification) - if specification.details then - reportskippedtable("gdef") - end + reportskippedtable(f,fontdata,"gdef",specification.details) end function readers.gsub(f,fontdata,specification) - if specification.details then - reportskippedtable("gsub") - end + reportskippedtable(f,fontdata,"gsub",specification.details) end function readers.gpos(f,fontdata,specification) - if specification.details then - reportskippedtable("gpos") - end + reportskippedtable(f,fontdata,"gpos",specification.details) end function readers.math(f,fontdata,specification) - if specification.glyphs then - reportskippedtable("math") - end + reportskippedtable(f,fontdata,"math",specification.details) end -- Now comes the loader. The order of reading these matters as we need to know @@ -2109,8 +2118,16 @@ local function readdata(f,offset,specification) readtable("colr",f,fontdata,specification) readtable("cpal",f,fontdata,specification) + readtable("svg" ,f,fontdata,specification) + readtable("sbix",f,fontdata,specification) + + readtable("cbdt",f,fontdata,specification) + readtable("cblc",f,fontdata,specification) + readtable("ebdt",f,fontdata,specification) + readtable("eblc",f,fontdata,specification) + readtable("kern",f,fontdata,specification) readtable("gsub",f,fontdata,specification) readtable("gpos",f,fontdata,specification) @@ -2321,6 +2338,7 @@ function readers.loadfont(filename,n,instance) mathconstants = fontdata.mathconstants, colorpalettes = fontdata.colorpalettes, svgshapes = fontdata.svgshapes, + sbixshapes = fontdata.sbixshapes, variabledata = fontdata.variabledata, foundtables = fontdata.foundtables, }, diff --git a/tex/context/base/mkiv/l-pdfview.lua b/tex/context/base/mkiv/l-pdfview.lua index 6302fd6f6..d2add9188 100644 --- a/tex/context/base/mkiv/l-pdfview.lua +++ b/tex/context/base/mkiv/l-pdfview.lua @@ -44,7 +44,7 @@ if os.type == "windows" then ['okular'] = [[start "test" okular.exe --unique "%filename%"]], ['pdfxcview'] = [[start "test" pdfxcview.exe /A "nolock=yes=OpenParameters" "%filename%"]], ['sumatra'] = [[start "test" sumatrapdf.exe -reuse-instance -bg-color 0xCCCCCC "%filename%"]], - ['auto'] = [[start "%filename%"]], + ['auto'] = [[start "" "%filename%"]], } closecalls= { ['default'] = [[pdfclose --file "%filename%"]], @@ -91,7 +91,7 @@ else ['okular'] = [[okular --unique "%filename%"]], ['sumatra'] = [[wine "sumatrapdf.exe" -reuse-instance -bg-color 0xCCCCCC "%filename%"]], ['pdfxcview'] = [[wine "pdfxcview.exe" /A "nolock=yes=OpenParameters" "%filename%"]], - ['auto'] = [[open "%filename%"]], + ['auto'] = [[open "%filename%"]], -- linux: xdg-open } closecalls= { ['default'] = [[pdfclose --file "%filename%"]], diff --git a/tex/context/base/mkiv/lang-ini.lua b/tex/context/base/mkiv/lang-ini.lua index 62786d9ab..6de951998 100644 --- a/tex/context/base/mkiv/lang-ini.lua +++ b/tex/context/base/mkiv/lang-ini.lua @@ -46,6 +46,7 @@ local postexhyphenchar = lang.postexhyphenchar -- global per language local sethjcode = lang.sethjcode local uccodes = characters.uccodes +local lccodes = characters.lccodes lang.exceptions = lang.hyphenation local new_langage = lang.new @@ -159,7 +160,7 @@ local function sethjcodes(instance,loaded,what,factor) -- local function setcode(l) local u = uccodes[l] - local s = 1 + local s = l if hjcounts then local c = hjcounts[l] if c then @@ -182,7 +183,7 @@ local function sethjcodes(instance,loaded,what,factor) h[l] = s if u ~= l and type(u) == "number" then sethjcode(instance,u,s) - h[u] = s + h[u] = lccodes[l] end end -- diff --git a/tex/context/base/mkiv/luat-run.lua b/tex/context/base/mkiv/luat-run.lua index d0f894292..372bbcbfa 100644 --- a/tex/context/base/mkiv/luat-run.lua +++ b/tex/context/base/mkiv/luat-run.lua @@ -23,6 +23,10 @@ local report_tempfiles = logs.reporter("resolvers","tempfiles") luatex = luatex or { } local luatex = luatex +if not luatex.synctex then + luatex.synctex = table.setmetatableindex(function() return function() end end) +end + local startactions = { } local stopactions = { } local dumpactions = { } @@ -68,6 +72,7 @@ local function stop_shipout_page() for i=1,#pageactions do pageactions[i]() end + luatex.synctex.flush() end local function report_output_pages() @@ -142,27 +147,6 @@ end luatex.registerstopactions(luatex.cleanuptempfiles) --- for the moment here - -local report_system = logs.reporter("system") -local synctex = 0 - -directives.register("system.synctex", function(v) - synctex = tonumber(v) or (toboolean(v,true) and 1) or (v == "zipped" and 1) or (v == "unzipped" and -1) or 0 - if synctex ~= 0 then - report_system("synctex functionality is enabled (%s), expect runtime overhead!",tostring(synctex)) - else - report_system("synctex functionality is disabled!") - end - tex.normalsynctex = synctex -end) - -statistics.register("synctex tracing",function() - if synctex ~= 0 then - return "synctex has been enabled (extra log file generated)" - end -end) - -- filenames local types = { @@ -184,6 +168,10 @@ local total = 0 local stack = { } local all = false +function luatex.currentfile() + return stack[#stack] or tex.jobname +end + local function report_start(left,name) if not left then -- skip @@ -200,6 +188,7 @@ local function report_start(left,name) level = level + 1 -- report_open("%i > %i > %s",level,total,name or "?") report_open("level %i, order %i, name %a",level,total,name or "?") + luatex.synctex.setfilename(name) end end diff --git a/tex/context/base/mkiv/lxml-aux.lua b/tex/context/base/mkiv/lxml-aux.lua index 9a829795d..ee0909cbf 100644 --- a/tex/context/base/mkiv/lxml-aux.lua +++ b/tex/context/base/mkiv/lxml-aux.lua @@ -762,7 +762,7 @@ local obsolete = xml.obsolete xml.strip_whitespace = xml.strip obsolete.strip_whitespace = xml.strip xml.collect_elements = xml.collect obsolete.collect_elements = xml.collect xml.delete_element = xml.delete obsolete.delete_element = xml.delete -xml.replace_element = xml.replace obsolete.replace_element = xml.replacet +xml.replace_element = xml.replace obsolete.replace_element = xml.replace xml.each_element = xml.each obsolete.each_element = xml.each xml.process_elements = xml.process obsolete.process_elements = xml.process xml.insert_element_after = xml.insertafter obsolete.insert_element_after = xml.insertafter diff --git a/tex/context/base/mkiv/node-nut.lua b/tex/context/base/mkiv/node-nut.lua index ed3c06c28..b23709ff0 100644 --- a/tex/context/base/mkiv/node-nut.lua +++ b/tex/context/base/mkiv/node-nut.lua @@ -853,3 +853,11 @@ function nuts.copy_properties(source,target,what) end return newprops -- for checking end + +-- here: + +nodes.set_synctex_line = node.set_synctex_line +nodes.set_synctex_tag = node.set_synctex_tag + +nuts.get_synctex_fields = direct.get_synctex_fields +nuts.set_synctex_fields = direct.set_synctex_fields diff --git a/tex/context/base/mkiv/node-syn.lua b/tex/context/base/mkiv/node-syn.lua new file mode 100644 index 000000000..31243cd60 --- /dev/null +++ b/tex/context/base/mkiv/node-syn.lua @@ -0,0 +1,501 @@ +if not modules then modules = { } end modules ['node-syn'] = { + version = 1.001, + comment = "companion to node-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- Because we have these fields in some node that are used by sunctex, I decided (because +-- some users seem to like that feature) to implement a variant that might work out better +-- for ConTeXt. This is experimental code. I don't use it myself so it will take a while +-- to mature. There will be some helpers that one can use in more complex situations like +-- included xml files. +-- +-- It is unclear how the output gets interpreted. For instance, we only need to be able to +-- go back to a place where text is entered, but still we need all that redundant box +-- wrapping. +-- +-- Possible optimizations: pack whole lines. + +local type, rawset = type, rawset +local concat = table.concat +local formatters = string.formatters + +local trace = false trackers.register("system.syntex.visualize", function(v) trace = v end) + +local nuts = nodes.nuts +local tonut = nuts.tonut +local tonode = nuts.tonode + +local getid = nuts.getid +local getlist = nuts.getlist +local setlist = nuts.setlist +local getnext = nuts.getnext +local getwhd = nuts.getwhd +local getwidth = nuts.getwidth +local getsubtype = nuts.getsubtype +local getattr = nuts.getattr + +local nodecodes = nodes.nodecodes +local kerncodes = nodes.kerncodes + +local glue_code = nodecodes.glue +local kern_code = nodecodes.kern +local kern_disc = nodecodes.disc +local rule_code = nodecodes.rule +----- math_code = nodecodes.math +local hlist_code = nodecodes.hlist +local vlist_code = nodecodes.vlist +local glyph_code = nodecodes.glyph +local fontkern_code = kerncodes.fontkern + +local insert_before = nuts.insert_before +local insert_after = nuts.insert_after + +local nodepool = nuts.pool +local new_latelua = nodepool.latelua +local new_rule = nodepool.rule +local new_hlist = nodepool.hlist + +local getdimensions = nuts.dimensions +local getrangedimensions = nuts.rangedimensions + +local a_fontkern = attributes.private("fontkern") + +local get_synctex_fields = nuts.get_synctex_fields +local set_synctex_fields = nuts.set_synctex_fields +local set_syntex_tag = nodes.set_synctex_tag + +local getpos = function() + getpos = backends.codeinjections.getpos + return getpos() + end + +local f_glue = formatters["g%i,%i:%i,%i"] +local f_glyph = formatters["x%i,%i:%i,%i"] +local f_kern = formatters["k%i,%i:%i,%i:%i"] +local f_rule = formatters["r%i,%i:%i,%i:%i,%i,%i"] +local f_hlist = formatters["[%i,%i:%i,%i:%i,%i,%i"] +local f_vlist = formatters["(%i,%i:%i,%i:%i,%i,%i"] +local s_hlist = "]" +local s_vlist = ")" +local f_hvoid = formatters["h%i,%i:%i,%i:%i,%i,%i"] +local f_vvoid = formatters["v%i,%i:%i,%i:%i,%i,%i"] + +local characters = fonts.hashes.characters + +local synctex = { } +luatex.synctex = synctex + +-- the file name stuff + +local noftags = 0 +local stnums = { } +local sttags = table.setmetatableindex(function(t,name) + noftags = noftags + 1 + t[name] = noftags + stnums[noftags] = name + return noftags +end) + +function synctex.setfilename(name) + if set_syntex_tag and name then + set_syntex_tag(sttags[name]) + end +end + +function synctex.resetfilename() + if set_syntex_tag then + local name = luatex.currentfile() + if name then + set_syntex_tag(name) + end + end +end + +-- the node stuff + +local result = { } +local r = 0 +local f = nil +local nofsheets = 0 +local nofobjects = 0 +local last = 0 +local filesdone = 0 +local enabled = false +local compact = true + +local function writeanchor() + local size = f:seek("end") + f:write("!" .. (size-last) .. "\n") + last = size +end + +local function writefiles() + local total = #stnums + if filesdone < total then + for i=filesdone+1,total do + f:write("Input:"..i..":"..stnums[i].."\n") + end + filesdone = total + end +end + +local function flushpreamble() + local jobname = tex.jobname + stnums[0] = jobname + f = io.open(file.replacesuffix(jobname,"syncctx"),"w") + f:write("SyncTeX Version:1\n") + f:write("Input:0:"..jobname.."\n") + writefiles() + f:write("Output:pdf\n") + f:write("Magnification:1000\n") + f:write("Unit:1\n") + f:write("X Offset:0\n") + f:write("Y Offset:0\n") + f:write("Content:\n") + flushpreamble = writefiles +end + +local function flushpostamble() + writeanchor() + f:write("Postamble:\n") + f:write("Count:"..nofobjects.."\n") + writeanchor() + f:write("Post scriptum:\n") + f:close() + enabled = false +end + +local pageheight = 0 -- todo: set before we do this! + +local function b_hlist(head,current,t,l,w,h,d) + return insert_before(head,current,new_latelua(function() + local x, y = getpos() + r = r + 1 + result[r] = f_hlist(t,l,x,tex.pageheight-y,w,h,d) + nofobjects = nofobjects + 1 + end)) +end + +local function b_vlist(head,current,t,l,w,h,d) + return insert_before(head,current,new_latelua(function() + local x, y = getpos() + r = r + 1 + result[r] = f_vlist(t,l,x,tex.pageheight-y,w,h,d) + nofobjects = nofobjects + 1 + end)) +end + +local function e_hlist(head,current) + return insert_after(head,current,new_latelua(function() + r = r + 1 + result[r] = s_hlist + nofobjects = nofobjects + 1 + end)) +end + +local function e_vlist(head,current) + return insert_after(head,current,new_latelua(function() + r = r + 1 + result[r] = s_vlist + nofobjects = nofobjects + 1 + end)) +end + +local function x_hlist(head,current,t,l,w,h,d) + return insert_before(head,current,new_latelua(function() + local x, y = getpos() + r = r + 1 + result[r] = f_hvoid(t,l,x,tex.pageheight-y,w,h,d) + nofobjects = nofobjects + 1 + end)) +end + +local function x_vlist(head,current,t,l,w,h,d) + return insert_before(head,current,new_latelua(function() + local x, y = getpos() + r = r + 1 + result[r] = f_vvoid(t,l,x,tex.pageheight-y,w,h,d) + nofobjects = nofobjects + 1 + end)) +end + +-- local function x_glyph(head,current,t,l) +-- return insert_before(head,current,new_latelua(function() +-- local x, y = getpos() +-- r = r + 1 +-- result[r] = f_glyph(t,l,x,tex.pageheight-y) +-- nofobjects = nofobjects + 1 +-- end)) +-- end + +-- local function x_glue(head,current,t,l) +-- return insert_before(head,current,new_latelua(function() +-- local x, y = getpos() +-- r = r + 1 +-- result[r] = f_glue(t,l,x,tex.pageheight-y) +-- nofobjects = nofobjects + 1 +-- end)) +-- end + +-- local function x_kern(head,current,t,l,k) +-- return insert_before(head,current,new_latelua(function() +-- local x, y = getpos() +-- r = r + 1 +-- result[r] = f_kern(t,l,x,tex.pageheight-y,k) +-- nofobjects = nofobjects + 1 +-- end)) +-- end + +-- local function x_rule(head,current,t,l,w,h,d) +-- return insert_before(head,current,new_latelua(function() +-- local x, y = getpos() +-- r = r + 1 +-- result[r] = f_rule(t,l,x,tex.pageheight-y,w,h,d) +-- nofobjects = nofobjects + 1 +-- end)) +-- end + +local function collect(head,t,l) + local current = head + while current do + local id = getid(current) + if id == glyph_code then + local first = current + local last = current + while true do + id = getid(current) + if id == glyph_code or id == disc_code then + last = current + elseif id == kern_code and (getsubtype(current) == fontkern_code or getattr(current,a_fontkern)) then + last = current + else + if id == glue_code then + -- we could go on when we're in the same t/l run + local tc, lc = get_synctex_fields(current) + if tc > 0 then + t, l = tc, lc + end + id = nil -- so no test later on + end + local w, h, d = getdimensions(first,getnext(last)) + -- local w, h, d = getrangedimensions(head,first,getnext(last)) + if trace then + -- color is already handled so no colors + head = insert_before(head,first,new_hlist(new_rule(w,32768,32768))) + end +if h < 655360 then + h = 655360 +end +if d < 327680 then + d = 327680 +end + head = x_hlist(head,first,t,l,w,h,d) + break + end + current = getnext(current) + if not current then + local w, h, d = getdimensions(first,getnext(last)) + -- local w, h, d = getrangedimensions(head,first,getnext(last)) + if trace then + -- color is already handled so no colors + head = insert_before(head,first,new_hlist(new_rule(w,32768,32768))) + end +if h < 655360 then + h = 655360 +end +if d < 327680 then + d = 327680 +end + head = x_hlist(head,first,t,l,w,h,d) + return head + end + end + end + if id == hlist_code then + local list = getlist(current) + local tc, lc = get_synctex_fields(current) + if tc > 0 then + t, l = tc, lc + end + if compact then + if list then + local l = collect(list,t,l) + if l ~= list then + setlist(current,l) + end + end + else + local w, h, d = getwhd(current) + if w == 0 or (h == 0 and d == 0) then + if list then + local l = collect(list,t,l) + if l ~= list then + setlist(current,l) + end + end + elseif list then + -- head = b_hlist(head,current,t,l,w,h,d) + head = b_hlist(head,current,0,0,w,h,d) + local l = collect(list,t,l) + if l ~= list then + setlist(current,l) + end + head, current = e_hlist(head,current) + else + -- head = x_hlist(head,current,t,l,w,h,d) + head = x_hlist(head,current,0,0,w,h,d) + end + end + elseif id == vlist_code then + local list = getlist(current) + local tc, lc = get_synctex_fields(current) + if tc > 0 then + t, l = tc, lc + end + if compact then + if list then + local l = collect(list,t,l) + if l ~= list then + setlist(current,l) + end + end + else + local w, h, d = getwhd(current) + if w == 0 or (h == 0 and d == 0) then + if list then + local l = collect(list,t,l) + if l ~= list then + setlist(current,l) + end + end + elseif list then + -- head = b_vlist(head,current,t,l,w,h,d) + head = b_vlist(head,current,0,0,w,h,d) + local l = collect(list,t,l) + if l ~= list then + setlist(current,l) + end + head, current = e_vlist(head,current) + else + -- head = x_vlist(head,current,t,l,w,h,d) + head = x_vlist(head,current,0,0,w,h,d) + end + end + elseif id == glue_code then + local tc, lc = get_synctex_fields(current) + if tc > 0 then + t, l = tc, lc + end + -- head = x_glue(head,current,t,l) + -- elseif id == kern_code then + -- local tc, lc = get_synctex_fields(current) + -- if tc > 0 then + -- t, l = tc, lc + -- end + -- -- local k = getwidth(current) + -- -- if k ~= 0 then + -- -- head = x_kern(head,current,t,l,k) + -- -- end + -- elseif id == rule_code then + -- local tc, lc = get_synctex_fields(current) + -- if tc > 0 then + -- t, l = tc, lc + -- end + -- -- if t > 0 and l > 0 then + -- -- local w, h, d = getwhd(current) + -- -- head = x_rule(head,current,t,l,w,h,d) + -- -- end + end + current = getnext(current) + end + return head +end + +-- range of same numbers + +function synctex.collect(head) + if enabled then + result, r = { }, 0 + head = collect(tonut(head),0,0) + return tonode(head), true + else + return head, false + end +end + +-- also no solution for bad first file resolving in sumatra + +function synctex.flush() + if enabled then + nofsheets = nofsheets + 1 -- could be realpageno + flushpreamble() + writeanchor() + f:write("{"..nofsheets.."\n") + if compact then + f:write(f_vlist(0,0,0,0,tex.pagewidth,tex.pageheight,0)) + f:write("\n") + end + f:write(concat(result,"\n")) + if compact then + f:write("\n") + f:write(s_vlist) + end + f:write("\n") + writeanchor() + f:write("}"..nofsheets.."\n") + nofobjects = nofobjects + 2 + result, r = { }, 0 + end +end + +function synctex.enable() + if not enabled and node.set_synctex_mode then + enabled = true + node.set_synctex_mode(1) + tex.normalsynctex = 0 + nodes.tasks.appendaction("shipouts", "after", "nodes.synctex.collect") + end +end + +function synctex.finish() + if enabled then + flushpostamble() + end +end + +-- not the best place + +luatex.registerstopactions(synctex.finish) + +nodes.tasks.appendaction("shipouts", "after", "luatex.synctex.collect") + +-- moved here + +local report_system = logs.reporter("system") +local synctex = false + +directives.register("system.synctex", function(v) + if v == "context" then + luatex.synctex.enable() + tex.normalsynctex = 0 + synctex = true + else + v = tonumber(v) or (toboolean(v,true) and 1) or (v == "zipped" and 1) or (v == "unzipped" and -1) or 0 + tex.normalsynctex = v + synctex = v ~= 0 + end + if synctex then + report_system("synctex functionality is enabled (%s), expect runtime overhead!",tostring(v)) + else + report_system("synctex functionality is disabled!") + end +end) + +statistics.register("synctex tracing",function() + if synctex or tex.normalsynctex ~= 0 then + return "synctex has been enabled (extra log file generated)" + end +end) diff --git a/tex/context/base/mkiv/pack-rul.mkiv b/tex/context/base/mkiv/pack-rul.mkiv index ff39200b8..eec7b8cb3 100644 --- a/tex/context/base/mkiv/pack-rul.mkiv +++ b/tex/context/base/mkiv/pack-rul.mkiv @@ -941,7 +941,9 @@ \def\pack_framed_start_framed_nop_indeed[#1]% {\pack_framed_initialize \bgroup - \setupcurrentframed[#1]% here ! + \iffirstargument + \setupcurrentframed[#1]% here ! + \fi \pack_framed_process_indeed \bgroup \ignorespaces} diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf Binary files differindex 32aee579a..94d382b63 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 ba8f9d5b7..c66f8765b 100644 --- a/tex/context/base/mkiv/status-lua.pdf +++ b/tex/context/base/mkiv/status-lua.pdf diff --git a/tex/context/base/mkiv/tabl-frm.mkiv b/tex/context/base/mkiv/tabl-frm.mkiv new file mode 100644 index 000000000..639d6f06d --- /dev/null +++ b/tex/context/base/mkiv/tabl-frm.mkiv @@ -0,0 +1,209 @@ +%D \module +%D [ file=tabl-frm, +%D version=2017.04.11, +%D title=\CONTEXT\ Table Macros, +%D subtitle=Framed Tables, +%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. + +%D For Thomas Schmitz who needed 3000 pages long tables. + +\unprotect + +\writestatus{loading}{ConTeXt Table Macros / Framed Tables} + +\installcorenamespace{framedtable} +\installcorenamespace{framedtablerow} +\installcorenamespace{framedtablecolumn} + +\newcount\c_tabl_framed_c +\newcount\c_tabl_framed_r +\newdimen\d_tabl_framed_h +\newdimen\d_tabl_framed_d +\newdimen\b_tabl_framed + +\initializeboxstack\??framedtable + +\defineframed[\??framedtable] +\defineframed[\??framedtablerow][\??framedtable] +\defineframed[\??framedtablecolumn][\??framedtable] + +\setupframed + [\??framedtable] + [\c!distance=\zeropoint, + \c!before=, + \c!after=, + \c!inbetween=] + +\setupframed + [\??framedtablerow] + [\c!strut=\v!no, + \c!offset=\v!overlay] + +% \defineframedtable[foo] +% \defineframedtable[bar][foo] + +\unexpanded\def\defineframedtable + {\dodoubleempty\tabl_framed_define} + +\def\tabl_framed_define[#1][#2]% + {\ifsecondargument + \defineframed[\??framedtable#1][\??framedtable#2]% + \else\iffirstargument + \defineframed[\??framedtable#1][\??framedtable]% + \fi\fi} + +% \setupframedtable[foo][...] + +\unexpanded\def\setupframedtable + {\dodoubleempty\tabl_framed_setup} + +\def\tabl_framed_setup[#1][#2]% + {\ifsecondargument + \ifcsname\??framed:\??framedtable#1\endcsname \else + \defineframed[\??framedtable#1][\??framedtable]% + \fi + \setupframed[\??framedtable#1][#2]% + \else + \setupframed[\??framedtable][#1]% + \fi} + +% \setupframedtable[1][...] +% \setupframedtable[foo][1][...] + +\unexpanded\def\setupframedtablerow + {\dotripleempty\tabl_framed_setup_row} + +\def\tabl_framed_setup_row[#1][#2][#3]% + {\ifthirdargument + \ifcsname\??framed:\??framedtable#1\endcsname \else + \defineframed[\??framedtable#1][\??framedtable]% + \fi + \ifcsname\??framed:\??framedtablerow#1:#2\endcsname \else + \defineframed[\??framedtablerow#1:#2][\??framedtable#1]% + \fi + \setupframed[\??framedtablerow#1:#2][#3]% + \else\ifsecondargument + \ifcsname\??framed:\??framedtablerow:#1\endcsname \else + \defineframed[\??framedtablerow:#1][\??framedtable]% + \fi + \setupframed[\??framedtablerow:#1][#2]% + \fi\fi} + +\unexpanded\def\setupframedtablecolumn + {\dotripleempty\tabl_framed_setup_column} + +\def\tabl_framed_setup_column[#1][#2][#3]% + {\ifthirdargument + \ifcsname\??framed:\??framedtable#1\endcsname \else + \defineframed[\??framedtable#1][\??framedtable]% + \fi + \ifcsname\??framed:\??framedtablecolumn#1:#2\endcsname \else + \defineframed[\??framedtablecolumn#1:#2][\??framedtable#1]% + \fi + \setupframed[\??framedtablecolumn#1:#2][#3]% + \else\ifsecondargument + \ifcsname\??framed:\??framedtablecolumn:#1\endcsname \else + \defineframed[\??framedtablecolumn:#1][\??framedtable]% + \fi + \setupframed[\??framedtablecolumn:#1][#2]% + \fi\fi} + +\unexpanded\def\startframedtable + {\dodoubleempty\tabl_framed_start} + +\unexpanded\def\tabl_framed_start[#1][#2]% + {\begingroup + \forgetall + \doifelseassignment{#1}% + {\let\currentframedtable\empty + \setupframed[\??framedtable][#1]}% + {\edef\currentframedtable{#1}% + \setupframed[\??framedtable][#2]}% + \edef\currentframed{\??framedtable\currentframedtable}% + \c_tabl_framed_r\zerocount + \d_tabl_framed_d\framedparameter\c!distance + \framedparameter\c!before} + +\unexpanded\def\stopframedtable + {\framedparameter\c!after + \endgroup} + +\unexpanded\def\startframedrow + {\advance\c_tabl_framed_r\plusone + \c_tabl_framed_c\zerocount + \d_tabl_framed_h\zeropoint + \bgroup + \edef\currentframed{\number\c_tabl_framed_r}% + \edef\currentframed + {\??framedtablerow\currentframedtable + \ifcsname\??framedtablerow\currentframedtable:\currentframed\endcsname + :\currentframed + \else\ifcsname\??framedtablerow\currentframedtable:\v!each\endcsname + :\v!each + \fi\fi}% + \dosingleempty\pack_framed_start_framed_nop_indeed} + +\unexpanded\def\stopframedrow + {\dofastloopcs\c_tabl_framed_c\tabl_framed_flush_row + \stopframed + \nointerlineskip + \vskip\zeropoint\relax + \framedparameter\c!inbetween} + +\unexpanded\def\tabl_framed_flush_row + {\vpack to \d_tabl_framed_h{\flushbox\??framedtable{\number\fastloopindex}\vfill}% + \ifdim\d_tabl_framed_d=\zeropoint\else\kern\d_tabl_framed_d\fi} + +\unexpanded\def\startframedcell + {\advance\c_tabl_framed_c\plusone + \setbox\b_tabl_framed\hpack\bgroup + %\bgroup + \edef\currentframed{\number\c_tabl_framed_c}% + \edef\currentframed + {\??framedtablecolumn\currentframedtable + \ifcsname\??framedtablecolumn\currentframedtable:\currentframed\endcsname + :\currentframed + \else\ifcsname\??framedtablecolumn\currentframedtable:\v!each\endcsname + :\v!each + \fi\fi}% + \dosingleempty\pack_framed_start_framed_nop_indeed} + +\unexpanded\def\stopframedcell + {\stopframed + %\egroup + \ifdim\ht\b_tabl_framed>\d_tabl_framed_h + \d_tabl_framed_h\ht\b_tabl_framed + \fi + \savebox\??framedtable{\number\c_tabl_framed_c}{\box\b_tabl_framed}} + +\protect \endinput + +\starttext + +\setupframedtablecolumn [1] [width=3cm,background=color,backgroundcolor=red] +\setupframedtablecolumn [2] [width=4cm,background=color,backgroundcolor=green,align=normal] +% \setupframedtablerow [each] [background=color,backgroundcolor=blue,strut=no] +% \setupframedtablerow [each] [strut=no,offset=overlay] + +\startframedtable[inbetween=\kern-0.4pt,distance=-0.4pt] + +\testfeatureonce{10000}{ +% \testfeatureonce{10}{ + \startframedrow + \startframedcell%[backgroundcolor=yellow] + test + \stopframedcell + \startframedcell + test \par test + \stopframedcell + \stopframedrow +} +\stopframedtable + +\stoptext diff --git a/tex/context/base/mkiv/tabl-ltb.mkiv b/tex/context/base/mkiv/tabl-ltb.mkiv index b0e3f52e4..3147fa1cc 100644 --- a/tex/context/base/mkiv/tabl-ltb.mkiv +++ b/tex/context/base/mkiv/tabl-ltb.mkiv @@ -474,7 +474,8 @@ \ifconditional\c_tabl_lines_preroll \else \box\b_tabl_lines_cell % the columncounter is one ahead ! - \dorecurse\c_tabl_lines_step{\strut\hfil}% +% \dorecurse\c_tabl_lines_step{\strut\hfil}% +\strut \hskip\scratchskip \fi \fi} diff --git a/tex/context/base/mkiv/typo-bld.lua b/tex/context/base/mkiv/typo-bld.lua index 04cc4db8d..153218eef 100644 --- a/tex/context/base/mkiv/typo-bld.lua +++ b/tex/context/base/mkiv/typo-bld.lua @@ -37,6 +37,7 @@ local texnest = tex.nest local texlists = tex.lists local nodes = nodes +local nodeidstostring = nodes.idstostring local nodepool = nodes.pool local new_baselineskip = nodepool.baselineskip local new_lineskip = nodepool.lineskip diff --git a/tex/context/base/mkiv/util-sci.lua b/tex/context/base/mkiv/util-sci.lua index 33e520719..e028d2f95 100644 --- a/tex/context/base/mkiv/util-sci.lua +++ b/tex/context/base/mkiv/util-sci.lua @@ -17,7 +17,20 @@ utilities.scite = scite local report = logs.reporter("scite") -local lexerroot = file.dirname(resolvers.find_file("scite-context-lexer.lua")) +do + local lexerroot = "c:/data/system/scite/wscite/context/lexers" + if not lexerroot then + lexerroot = file.dirname(resolvers.find_file("scite-context-lexer.lua")) + end + if lfs.isdir(lexerroot) then + package.extraluapath(lexerroot) + package.extraluapath(lexerroot.."/themes") + package.extraluapath(lexerroot.."/data") + report("using lexer root %a",lexerroot) + else + report("no valid lexer root") + end +end local knownlexers = { tex = "tex", mkiv = "tex", mkvi = "tex", mkxi = "tex", mkix = "tex", mkii = "tex", cld = "tex", @@ -35,20 +48,16 @@ lexer = nil -- main lexer, global (for the moment needed for themes) local function loadscitelexer() if not lexer then - dir.push(lexerroot) - lexer = dofile("scite-context-lexer.lua") - dofile("themes/scite-context-theme.lua") - dir.pop() + lexer = require("scite-context-lexer") + require("scite-context-theme") -- uses lexer end return lexer end local loadedlexers = setmetatableindex(function(t,k) local l = knownlexers[k] or k - dir.push(lexerroot) loadscitelexer() local v = lexer.load(formatters["scite-context-lexer-%s"](l)) - dir.pop() t[l] = v t[k] = v return v @@ -58,8 +67,8 @@ scite.loadedlexers = loadedlexers scite.knownlexers = knownlexers scite.loadscitelexer = loadscitelexer -local f_fore_bold = formatters['.%s { display: inline ; font-weight: bold ; color: #%s%s%s ; }'] -local f_fore_none = formatters['.%s { display: inline ; font-weight: normal ; color: #%s%s%s ; }'] +local f_fore_bold = formatters['.%s { display: inline ; font-weight: bold ; color: #%02X%02X%02X ; }'] +local f_fore_none = formatters['.%s { display: inline ; font-weight: normal ; color: #%02X%02X%02X ; }'] local f_none_bold = formatters['.%s { display: inline ; font-weight: bold ; }'] local f_none_none = formatters['.%s { display: inline ; font-weight: normal ; }'] local f_div_class = formatters['<div class="%s">%s</div>'] @@ -92,7 +101,7 @@ local function exportcsslexing() if not css then loadscitelexer() local function black(f) - return (f[1] == f[2]) and (f[2] == f[3]) and (f[3] == '00') + return (#f == 0 and f[1] == 0) or ((f[1] == f[2]) and (f[2] == f[3]) and (f[3] == 0)) end local result, r = { }, 0 for k, v in table.sortedhash(lexer.context.styles) do @@ -100,17 +109,10 @@ local function exportcsslexing() local fore = v.fore r = r + 1 if fore and not black(fore) then - if bold then - result[r] = f_fore_bold(k,fore[1],fore[2],fore[3]) - else - result[r] = f_fore_none(k,fore[1],fore[2],fore[3]) - end + local cr, cg, cb = fore[1], fore[2], fore[3] + result[r] = (bold and f_fore_bold or f_fore_none)(k,cr,cg or cr,cb or cr) else - if bold then - result[r] = f_none_bold(k) - else - result[r] = f_none_none(k) - end + result[r] = (bold and f_none_bold or f_none_none)(k) end end css = concat(result,"\n") diff --git a/tex/context/interface/mkiv/i-context.pdf b/tex/context/interface/mkiv/i-context.pdf Binary files differindex ff174700c..5716030ad 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 90fa626d6..61f901149 100644 --- a/tex/context/interface/mkiv/i-readme.pdf +++ b/tex/context/interface/mkiv/i-readme.pdf diff --git a/tex/context/modules/mkiv/m-scite.mkiv b/tex/context/modules/mkiv/m-scite.mkiv index 256a78b39..a7d9f8b5c 100644 --- a/tex/context/modules/mkiv/m-scite.mkiv +++ b/tex/context/modules/mkiv/m-scite.mkiv @@ -56,7 +56,7 @@ buffers.scite = scite -- context output: -local f_def_color = formatters["\\definecolor[slxc%s][h=%s%s%s]%%"] +local f_def_color = formatters["\\definecolor[slxc%s][h=%02X%02X%02X]%%"] local f_fore_none = formatters["\\unexpanded\\def\\slx%s#1{{\\slxc%s#1}}%%"] local f_fore_bold = formatters["\\unexpanded\\def\\slx%s#1{{\\slxc%s\\bf#1}}%%"] local f_none_bold = formatters["\\unexpanded\\def\\slx%s#1{{\\bf#1}}%%"] @@ -99,14 +99,14 @@ local function exportcolors() if not colors then scite.loadscitelexer() local function black(f) - return (f[1] == f[2]) and (f[2] == f[3]) and (f[3] == '00') + return (f[1] == f[2]) and (f[2] == f[3]) and (f[3] == 0) end local result, r = { f_mapping }, 1 for k, v in table.sortedhash(lexer.context.styles) do local fore = v.fore if fore and not black(fore) then r = r + 1 - result[r] = f_def_color(k,fore[1],fore[2],fore[3]) + result[r] = f_def_color(k,fore[1],fore[2] or fore[1],fore[3] or fore[1]) end end r = r + 1 diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index 68bcd8007..c671651ef 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 : 04/08/17 12:09:31 +-- merge date : 04/16/17 12:32:21 do -- begin closure to overcome local limits and interference @@ -8171,14 +8171,7 @@ local function readlongdatetime(f) end local tableversion=0.004 readers.tableversion=tableversion -local privateoffset=fonts.constructors and fonts.constructors.privateoffset or 0xF0000 -local reportedskipped={} -local function reportskippedtable(tag) - if not reportedskipped[tag] then - report("loading of table %a skipped (reported once only)",tag) - reportedskipped[tag]=true - end -end +local privateoffset=fonts.constructors and fonts.constructors.privateoffset or 0xF0000 local reservednames={ [0]="copyright", "family", "subfamily", @@ -8382,6 +8375,14 @@ local function gotodatatable(f,fontdata,tag,criterium) end end end +local function reportskippedtable(f,fontdata,tag,criterium) + if criterium and f then + local datatable=fontdata.tables[tag] + if datatable then + report("loading of table %a skipped",tag) + end + end +end local function setvariabledata(fontdata,tag,data) local variabledata=fontdata.variabledata if variabledata then @@ -8392,6 +8393,7 @@ local function setvariabledata(fontdata,tag,data) end helpers.gotodatatable=gotodatatable helpers.setvariabledata=setvariabledata +helpers.reportskippedtable=reportskippedtable local platformnames={ postscriptname=true, fullname=true, @@ -8763,8 +8765,7 @@ readers.vmtx=function(f,fontdata,specification) end end readers.vorg=function(f,fontdata,specification) - if specification.glyphs then - end + reportskippedtable(f,fontdata,"vorg",specification.glyphs) end readers.post=function(f,fontdata,specification) local tableoffset=gotodatatable(f,fontdata,"post",true) @@ -8825,9 +8826,7 @@ readers.post=function(f,fontdata,specification) end end readers.cff=function(f,fontdata,specification) - if specification.glyphs then - reportskippedtable("cff") - end + reportskippedtable(f,fontdata,"cff",specification.glyphs) end local formatreaders={} local duplicatestoo=true @@ -9246,29 +9245,37 @@ function readers.cmap(f,fontdata,specification) end end function readers.loca(f,fontdata,specification) - if specification.glyphs then - reportskippedtable("loca") - end + reportskippedtable(f,fontdata,"loca",specification.glyphs) end function readers.glyf(f,fontdata,specification) - if specification.glyphs then - reportskippedtable("glyf") - end + reportskippedtable(f,fontdata,"glyf",specification.glyphs) end function readers.colr(f,fontdata,specification) - if specification.glyphs then - reportskippedtable("colr") - end + reportskippedtable(f,fontdata,"colr",specification.glyphs) end function readers.cpal(f,fontdata,specification) - if specification.glyphs then - reportskippedtable("cpal") - end + reportskippedtable(f,fontdata,"cpal",specification.glyphs) end function readers.svg(f,fontdata,specification) - if specification.glyphs then - reportskippedtable("svg") - end + reportskippedtable(f,fontdata,"svg",specification.glyphs) +end +function readers.sbix(f,fontdata,specification) + reportskippedtable(f,fontdata,"sbix",specification.glyphs) +end +function readers.cbdt(f,fontdata,specification) + reportskippedtable(f,fontdata,"cbdt",specification.glyphs) +end +function readers.cblc(f,fontdata,specification) + reportskippedtable(f,fontdata,"cblc",specification.glyphs) +end +function readers.ebdt(f,fontdata,specification) + reportskippedtable(f,fontdata,"ebdt",specification.glyphs) +end +function readers.ebsc(f,fontdata,specification) + reportskippedtable(f,fontdata,"ebsc",specification.glyphs) +end +function readers.eblc(f,fontdata,specification) + reportskippedtable(f,fontdata,"eblc",specification.glyphs) end function readers.kern(f,fontdata,specification) local tableoffset=gotodatatable(f,fontdata,"kern",specification.kerns) @@ -9308,24 +9315,16 @@ function readers.kern(f,fontdata,specification) end end function readers.gdef(f,fontdata,specification) - if specification.details then - reportskippedtable("gdef") - end + reportskippedtable(f,fontdata,"gdef",specification.details) end function readers.gsub(f,fontdata,specification) - if specification.details then - reportskippedtable("gsub") - end + reportskippedtable(f,fontdata,"gsub",specification.details) end function readers.gpos(f,fontdata,specification) - if specification.details then - reportskippedtable("gpos") - end + reportskippedtable(f,fontdata,"gpos",specification.details) end function readers.math(f,fontdata,specification) - if specification.glyphs then - reportskippedtable("math") - end + reportskippedtable(f,fontdata,"math",specification.details) end local function getinfo(maindata,sub,platformnames,rawfamilynames,metricstoo,instancenames) local fontdata=sub and maindata.subfonts and maindata.subfonts[sub] or maindata @@ -9560,6 +9559,11 @@ local function readdata(f,offset,specification) readtable("colr",f,fontdata,specification) readtable("cpal",f,fontdata,specification) readtable("svg",f,fontdata,specification) + readtable("sbix",f,fontdata,specification) + readtable("cbdt",f,fontdata,specification) + readtable("cblc",f,fontdata,specification) + readtable("ebdt",f,fontdata,specification) + readtable("eblc",f,fontdata,specification) readtable("kern",f,fontdata,specification) readtable("gsub",f,fontdata,specification) readtable("gpos",f,fontdata,specification) @@ -9753,6 +9757,7 @@ function readers.loadfont(filename,n,instance) mathconstants=fontdata.mathconstants, colorpalettes=fontdata.colorpalettes, svgshapes=fontdata.svgshapes, + sbixshapes=fontdata.sbixshapes, variabledata=fontdata.variabledata, foundtables=fontdata.foundtables, }, @@ -15269,6 +15274,72 @@ function readers.svg(f,fontdata,specification) end fontdata.hascolor=true end +function readers.sbix(f,fontdata,specification) + local tableoffset=gotodatatable(f,fontdata,"sbix",specification.glyphs) + if tableoffset then + local version=readushort(f) + local flags=readushort(f) + local nofstrikes=readulong(f) + local strikes={} + local nofglyphs=fontdata.nofglyphs + for i=1,nofstrikes do + strikes[i]=readulong(f) + end + local shapes={} + local done=0 + for i=1,nofstrikes do + local strikeoffset=strikes[i]+tableoffset + setposition(f,strikeoffset) + strikes[i]={ + ppem=readushort(f), + ppi=readushort(f), + offset=strikeoffset + } + end + sort(strikes,function(a,b) + if b.ppem==a.ppem then + return b.ppi<a.ppi + else + return b.ppem<a.ppem + end + end) + local glyphs={} + for i=1,nofstrikes do + local strike=strikes[i] + local strikeppem=strike.ppem + local strikeppi=strike.ppi + local strikeoffset=strike.offset + setposition(f,strikeoffset) + for i=0,nofglyphs do + glyphs[i]=readulong(f) + end + local glyphoffset=glyphs[0] + for i=0,nofglyphs-1 do + local nextoffset=glyphs[i+1] + if not shapes[i] then + local datasize=nextoffset-glyphoffset + if datasize>0 then + setposition(f,strikeoffset+glyphoffset) + shapes[i]={ + x=readshort(f), + y=readshort(f), + tag=readtag(f), + data=readstring(f,datasize-8), + ppem=strikeppem, + ppi=strikeppi, + } + done=done+1 + if done==nofglyphs then + break + end + end + end + glyphoffset=nextoffset + end + end + fontdata.sbixshapes=shapes + end +end function readers.stat(f,fontdata,specification) local tableoffset=gotodatatable(f,fontdata,"stat",true) if tableoffset then @@ -17755,8 +17826,10 @@ local otf=fonts.handlers.otf otf.version=3.028 otf.cache=containers.define("fonts","otl",otf.version,true) otf.svgcache=containers.define("fonts","svg",otf.version,true) +otf.sbixcache=containers.define("fonts","sbix",otf.version,true) otf.pdfcache=containers.define("fonts","pdf",otf.version,true) otf.svgenabled=false +otf.sbixenabled=false local otfreaders=otf.readers local hashes=fonts.hashes local definers=fonts.definers @@ -17812,6 +17885,7 @@ function otf.load(filename,sub,instance) if data then local resources=data.resources local svgshapes=resources.svgshapes + local sbixshapes=resources.sbixshapes if svgshapes then resources.svgshapes=nil if otf.svgenabled then @@ -17826,6 +17900,20 @@ function otf.load(filename,sub,instance) } end end + if sbixshapes then + resources.sbixshapes=nil + if otf.sbixenabled then + local timestamp=os.date() + containers.write(otf.sbixcache,hash,{ + sbixshapes=sbixshapes, + timestamp=timestamp, + }) + data.properties.sbix={ + hash=hash, + timestamp=timestamp, + } + end + end otfreaders.compact(data) otfreaders.rehash(data,"unicodes") otfreaders.addunicodetable(data) @@ -25817,6 +25905,7 @@ if not modules then modules={} end modules ['font-ocl']={ } local tostring,next,format=tostring,next,string.format local round,max=math.round,math.round +local sortedkeys,sortedhash=table.sortedkeys,table.sortedhash local formatters=string.formatters local tounicode=fonts.mappings.tounicode local otf=fonts.handlers.otf @@ -25944,44 +26033,78 @@ fonts.handlers.otf.features.register { node=initializecolr, } } -local otfsvg=otf.svg or {} -otf.svg=otfsvg -otf.svgenabled=true do local nofstreams=0 - local f_name=formatters[ [[svg-glyph-%05i]] ] + local f_name=formatters[ [[pdf-glyph-%05i]] ] local f_used=context and formatters[ [[original:///%s]] ] or formatters[ [[%s]] ] + local hashed={} local cache={} - function otfsvg.storepdfdata(pdf) - nofstreams=nofstreams+1 - local o,n=epdf.openMemStream(pdf,#pdf,f_name(nofstreams)) - cache[n]=o - return nil,f_used(n),nil + function otf.storepdfdata(pdf) + local done=hashed[pdf] + if not done then + nofstreams=nofstreams+1 + local o,n=epdf.openMemStream(pdf,#pdf,f_name(nofstreams)) + cache[n]=o + done=f_used(n) + hashed[pdf]=done + end + return nil,done,nil end - if context then - local storepdfdata=otfsvg.storepdfdata - local initialized=false - function otfsvg.storepdfdata(pdf) - if not initialized then - if resolvers.setmemstream then - local f_setstream=formatters[ [[resolvers.setmemstream("svg-glyph-%05i",%q,true)]] ] - local f_getstream=formatters[ [[memstream:///svg-glyph-%05i]] ] - local f_nilstream=formatters[ [[resolvers.resetmemstream("svg-glyph-%05i",true)]] ] - storepdfdata=function(pdf) - nofstreams=nofstreams+1 - return - f_setstream(nofstreams,pdf), - f_getstream(nofstreams), - f_nilstream(nofstreams) - end - otfsvg.storepdfdata=storepdfdata +end +local function pdftovirtual(tfmdata,pdfshapes,kind) + if not tfmdata or not pdfshapes or not kind then + return + end + local characters=tfmdata.characters + local properties=tfmdata.properties + local parameters=tfmdata.parameters + local hfactor=parameters.hfactor + properties.virtualized=true + tfmdata.fonts={ + { id=0 } + } + local getactualtext=otf.getactualtext + local storepdfdata=otf.storepdfdata + for unicode,character in sortedhash(characters) do + local index=character.index + if index then + local pdf=pdfshapes[index] + local typ=type(pdf) + local data=nil + local dx=nil + local dy=nil + if typ=="table" then + data=pdf.data + dx=pdf.dx or 0 + dy=pdf.dy or 0 + elseif typ=="string" then + data=pdf + dx=0 + dy=0 + end + if data then + local setcode,name,nilcode=storepdfdata(data) + if name then + local bt,et=getactualtext(unicode) + local wd=character.width or 0 + local ht=character.height or 0 + local dp=character.depth or 0 + character.commands={ + { "special","pdf:direct:"..bt }, + { "down",dp+dy*hfactor }, + { "right",dx*hfactor }, + { "image",{ filename=name,width=wd,height=ht,depth=dp } }, + { "special","pdf:direct:"..et }, + } + character[kind]=true end - initialized=true end - return storepdfdata(pdf) end end end +local otfsvg=otf.svg or {} +otf.svg=otfsvg +otf.svgenabled=true do local report_svg=logs.reporter("fonts","svg conversion") local loaddata=io.loaddata @@ -26054,7 +26177,7 @@ do end statistics.stoptiming() if statistics.elapsedseconds then - report_svg("svg conversion time %s",statistics.elapsedseconds()) + report_svg("svg conversion time %s",statistics.elapsedseconds() or "-") end end return pdfshapes @@ -26062,10 +26185,7 @@ do end local function initializesvg(tfmdata,kind,value) if value and otf.svgenabled then - local characters=tfmdata.characters - local descriptions=tfmdata.descriptions - local properties=tfmdata.properties - local svg=properties.svg + local svg=tfmdata.properties.svg local hash=svg and svg.hash local timestamp=svg and svg.timestamp if not hash then @@ -26082,40 +26202,7 @@ local function initializesvg(tfmdata,kind,value) timestamp=timestamp, }) end - if not pdfshapes or not next(pdfshapes) then - return - end - properties.virtualized=true - tfmdata.fonts={ - { id=0 } - } - local getactualtext=otf.getactualtext - local storepdfdata=otfsvg.storepdfdata - local nop={ "nop" } - for unicode,character in next,characters do - local index=character.index - if index then - local pdf=pdfshapes[index] - if pdf then - local setcode,name,nilcode=storepdfdata(pdf) - if name then - local bt,et=getactualtext(unicode) - local wd=character.width or 0 - local ht=character.height or 0 - local dp=character.depth or 0 - character.commands={ - { "special","pdf:direct:"..bt }, - { "down",dp }, - setcode and { "lua",setcode } or nop, - { "image",{ filename=name,width=wd,height=ht,depth=dp } }, - nilcode and { "lua",nilcode } or nop, - { "special","pdf:direct:"..et }, - } - character.svg=true - end - end - end - end + pdftovirtual(tfmdata,pdfshapes,"svg") end end fonts.handlers.otf.features.register { @@ -26126,6 +26213,91 @@ fonts.handlers.otf.features.register { node=initializesvg, } } +local otfsbix=otf.sbix or {} +otf.sbix=otfsbix +otf.sbixenabled=true +do + local report_sbix=logs.reporter("fonts","sbix conversion") + local loaddata=io.loaddata + local savedata=io.savedata + local remove=os.remove + local runner=sandbox and sandbox.registerrunner { + name="otfsbix", + program="gm", + template="convert -quality 100 temp-otf-sbix-shape.sbix temp-otf-sbix-shape.pdf > temp-otf-svg-shape.log", + } + if not runner then + runner=function() + return os.execute("gm convert -quality 100 temp-otf-sbix-shape.sbix temp-otf-sbix-shape.pdf > temp-otf-svg-shape.log") + end + end + function otfsbix.topdf(sbixshapes) + local pdfshapes={} + local sbixfile="temp-otf-sbix-shape.sbix" + local pdffile="temp-otf-sbix-shape.pdf" + local nofdone=0 + local indices=sortedkeys(sbixshapes) + local nofindices=#indices + report_sbix("processing %i sbix containers",nofindices) + statistics.starttiming() + for i=1,nofindices do + local index=indices[i] + local entry=sbixshapes[index] + local data=entry.data + local x=entry.x + local y=entry.y + savedata(sbixfile,data) + runner() + pdfshapes[index]={ + x=x~=0 and x or nil, + y=y~=0 and y or nil, + data=loaddata(pdffile), + } + nofdone=nofdone+1 + if nofdone%100==0 then + report_sbix("%i shapes processed",nofdone) + end + end + report_sbix("processing %i pdf results",nofindices) + remove(sbixfile) + remove(pdffile) + statistics.stoptiming() + if statistics.elapsedseconds then + report_sbix("sbix conversion time %s",statistics.elapsedseconds() or "-") + end + return pdfshapes + end +end +local function initializesbix(tfmdata,kind,value) + if value and otf.sbixenabled then + local sbix=tfmdata.properties.sbix + local hash=sbix and sbix.hash + local timestamp=sbix and sbix.timestamp + if not hash then + return + end + local pdffile=containers.read(otf.pdfcache,hash) + local pdfshapes=pdffile and pdffile.pdfshapes + if not pdfshapes or pdffile.timestamp~=timestamp then + local sbixfile=containers.read(otf.sbixcache,hash) + local sbixshapes=sbixfile and sbixfile.sbixshapes + pdfshapes=sbixshapes and otfsbix.topdf(sbixshapes) or {} + containers.write(otf.pdfcache,hash,{ + pdfshapes=pdfshapes, + timestamp=timestamp, + }) + end + pdftovirtual(tfmdata,pdfshapes,"sbix") + end +end +fonts.handlers.otf.features.register { + name="sbix", + description="sbix glyphs", + manipulators={ + base=initializesbix, + node=initializesbix, + } +} end -- closure @@ -26142,7 +26314,6 @@ local format,insert,sortedkeys,tohash=string.format,table.insert,table.sortedkey local type,next=type,next local lpegmatch=lpeg.match local utfbyte,utflen,utfsplit=utf.byte,utf.len,utf.split -local settings_to_array=utilities.parsers.settings_to_array local trace_loading=false trackers.register("otf.loading",function(v) trace_loading=v end) local report_otf=logs.reporter("fonts","otf loading") local fonts=fonts @@ -26974,6 +27145,8 @@ registerotffeature { name='blockligatures', description='block certain ligatures', } +local settings_to_array=utilities.parsers and utilities.parsers.settings_to_array + or function(s) return string.split(s,",") end local function blockligatures(str) local t=settings_to_array(str) for i=1,#t do @@ -28783,8 +28956,9 @@ if not modules then modules={} end modules ['font-def']={ local lower,gsub=string.lower,string.gsub local tostring,next=tostring,next local lpegmatch=lpeg.match -local suffixonly,removesuffix=file.suffix,file.removesuffix +local suffixonly,removesuffix,basename=file.suffix,file.removesuffix,file.basename local formatters=string.formatters +local sortedhash,sortedkeys=table.sortedhash,table.sortedkeys local allocate=utilities.storage.allocate local trace_defining=false trackers .register("fonts.defining",function(v) trace_defining=v end) local directive_embedall=false directives.register("fonts.embedall",function(v) directive_embedall=v end) @@ -28904,9 +29078,9 @@ function resolvers.name(specification) features.normal=normal end normal.instance=instance -if not callbacks.supported.glyph_stream_provider then - normal.variableshapes=true -end + if not callbacks.supported.glyph_stream_provider then + normal.variableshapes=true + end end local suffix=lower(suffixonly(resolved)) if fonts.formats[suffix] then @@ -28985,6 +29159,60 @@ local function checkembedding(tfmdata) end tfmdata.embedding=embedding end +local function checkfeatures(tfmdata) + local resources=tfmdata.resources + local shared=tfmdata.shared + if resources and shared then + local features=resources.features + local usedfeatures=shared.features + if features and usedfeatures then + local usedlanguage=usedfeatures.language or "dflt" + local usedscript=usedfeatures.script or "dflt" + local function check(what) + if what then + local foundlanguages={} + for feature,scripts in next,what do + if usedscript=="auto" or scripts["*"] then + elseif not scripts[usedscript] then + else + for script,languages in next,scripts do + if languages["*"] then + elseif not languages[usedlanguage] then + report_defining("font %!font:name!, feature %a, script %a, no language %a", + tfmdata,feature,script,usedlanguage) + end + end + end + for script,languages in next,scripts do + for language in next,languages do + foundlanguages[language]=true + end + end + end + if false then + foundlanguages["*"]=nil + foundlanguages=sortedkeys(foundlanguages) + for feature,scripts in sortedhash(what) do + for script,languages in next,scripts do + if not languages["*"] then + for i=1,#foundlanguages do + local language=foundlanguages[i] + if not languages[language] then + report_defining("font %!font:name!, feature %a, script %a, no language %a", + tfmdata,feature,script,language) + end + end + end + end + end + end + end + end + check(features.gsub) + check(features.gpos) + end + end +end function definers.loadfont(specification) local hash=constructors.hashinstance(specification) local tfmdata=loadedfonts[hash] @@ -29018,6 +29246,7 @@ function definers.loadfont(specification) checkembedding(tfmdata) loadedfonts[hash]=tfmdata designsizes[specification.hash]=tfmdata.parameters.designsize + checkfeatures(tfmdata) end end if not tfmdata then @@ -29110,7 +29339,7 @@ function definers.read(specification,size,id) local parameters=tfmdata.parameters or {} report_defining("using %a font with id %a, name %a, size %a, bytes %a, encoding %a, fullname %a, filename %a", properties.format or "unknown",id,properties.name,parameters.size,properties.encodingbytes, - properties.encodingname,properties.fullname,file.basename(properties.filename)) + properties.encodingname,properties.fullname,basename(properties.filename)) end statistics.stoptiming(fonts) return tfmdata |