From b7b69c20fae6b104e134dae90ac34a35221b82ed Mon Sep 17 00:00:00 2001 From: Context Git Mirror Bot Date: Thu, 2 Oct 2014 23:15:04 +0200 Subject: 2014-10-02 23:09:00 --- doc/context/manuals/allkind/mkiv-publications.pdf | Bin 457944 -> 457924 bytes scripts/context/lua/mtx-epub.lua | 5 +- scripts/context/lua/mtxrun.lua | 28 +- scripts/context/stubs/mswin/mtxrun.lua | 28 +- scripts/context/stubs/unix/mtxrun | 28 +- scripts/context/stubs/win64/mtxrun.lua | 28 +- tex/context/base/back-exp.lua | 20 +- tex/context/base/back-exp.mkiv | 23 +- tex/context/base/back-pdf.mkiv | 2 +- tex/context/base/cont-new.mkiv | 2 +- tex/context/base/context-version.pdf | Bin 4391 -> 4390 bytes tex/context/base/context.mkiv | 2 +- tex/context/base/file-job.lua | 16 +- tex/context/base/font-afm.lua | 85 ++- tex/context/base/font-agl.lua | 2 + tex/context/base/font-con.lua | 84 ++- tex/context/base/font-ctx.lua | 34 +- tex/context/base/font-enh.lua | 28 +- tex/context/base/font-ext.lua | 10 +- tex/context/base/font-gds.lua | 2 +- tex/context/base/font-hsh.lua | 32 +- tex/context/base/font-map.lua | 473 ++++++++++++--- tex/context/base/font-mis.lua | 2 +- tex/context/base/font-nod.lua | 14 +- tex/context/base/font-otb.lua | 94 +-- tex/context/base/font-otf.lua | 354 ++++++++--- tex/context/base/font-otn.lua | 25 +- tex/context/base/font-otp.lua | 6 + tex/context/base/font-tfm.lua | 5 + tex/context/base/grph-epd.lua | 3 + tex/context/base/grph-epd.mkiv | 2 +- tex/context/base/grph-inc.lua | 24 +- tex/context/base/l-table.lua | 2 +- tex/context/base/lang-def.mkiv | 3 +- tex/context/base/lang-txt.lua | 59 +- tex/context/base/lpdf-ano.lua | 134 +++-- tex/context/base/lpdf-epa.lua | 215 ++++++- tex/context/base/lpdf-epd.lua | 407 ++++++++++--- tex/context/base/m-pstricks.mkii | 2 +- tex/context/base/math-fbk.lua | 22 +- tex/context/base/math-tag.lua | 3 +- tex/context/base/mult-de.mkii | 2 +- tex/context/base/mult-def.lua | 4 +- tex/context/base/mult-def.mkiv | 2 + tex/context/base/mult-en.mkii | 2 +- tex/context/base/mult-fr.mkii | 2 +- tex/context/base/mult-it.mkii | 2 +- tex/context/base/mult-nl.mkii | 2 +- tex/context/base/mult-pe.mkii | 2 +- tex/context/base/mult-ro.mkii | 2 +- tex/context/base/publ-dat.lua | 2 +- tex/context/base/publ-imp-apa.mkvi | 265 +++++---- tex/context/base/publ-ini.lua | 8 +- tex/context/base/publ-ini.mkiv | 13 +- tex/context/base/scrp-ini.lua | 5 +- tex/context/base/status-files.pdf | Bin 24767 -> 24682 bytes tex/context/base/status-lua.pdf | Bin 325265 -> 332148 bytes tex/context/base/strc-bkm.lua | 295 ++++++--- tex/context/base/strc-doc.lua | 11 +- tex/context/base/strc-ref.lua | 2 + tex/context/base/syst-ini.mkiv | 2 +- tex/context/base/typo-dig.lua | 7 +- tex/context/base/typo-tal.lua | 10 +- tex/context/base/util-tpl.lua | 20 +- tex/context/fonts/treatments.lfg | 88 +-- tex/context/interface/keys-cs.xml | 2 +- tex/context/interface/keys-de.xml | 2 +- tex/context/interface/keys-en.xml | 2 +- tex/context/interface/keys-fr.xml | 2 +- tex/context/interface/keys-it.xml | 2 +- tex/context/interface/keys-nl.xml | 2 +- tex/context/interface/keys-pe.xml | 2 +- tex/context/interface/keys-ro.xml | 2 +- tex/generic/context/luatex/luatex-basics-gen.lua | 5 + tex/generic/context/luatex/luatex-fonts-merged.lua | 656 +++++++++++++++------ tex/generic/context/luatex/luatex-fonts-otn.lua | 25 +- 76 files changed, 2774 insertions(+), 984 deletions(-) diff --git a/doc/context/manuals/allkind/mkiv-publications.pdf b/doc/context/manuals/allkind/mkiv-publications.pdf index b00659d04..74bcb637e 100644 Binary files a/doc/context/manuals/allkind/mkiv-publications.pdf and b/doc/context/manuals/allkind/mkiv-publications.pdf differ diff --git a/scripts/context/lua/mtx-epub.lua b/scripts/context/lua/mtx-epub.lua index fa5a85134..6d8dfa63f 100644 --- a/scripts/context/lua/mtx-epub.lua +++ b/scripts/context/lua/mtx-epub.lua @@ -23,9 +23,8 @@ if not modules then modules = { } end modules ['mtx-epub'] = { -- OEBPS -- content.opf -- toc.ncx --- Images --- Styles --- Text +-- images +-- styles -- mimetype -- todo: diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua index fcfdc1f17..ff54a0927 100644 --- a/scripts/context/lua/mtxrun.lua +++ b/scripts/context/lua/mtxrun.lua @@ -1212,7 +1212,7 @@ do -- create closure to overcome 200 locals limit package.loaded["l-table"] = package.loaded["l-table"] or true --- original size: 33477, stripped down to: 21843 +-- original size: 33499, stripped down to: 21844 if not modules then modules={} end modules ['l-table']={ version=1.001, @@ -1259,7 +1259,7 @@ local function compare(a,b) if ta==tb then return a 0 then + for i=1,#files do + report_file("% 4i: %s",i,files[i]) + end + else + report_file("no files") end logsnewline() report_options("stop commandline files") diff --git a/tex/context/base/font-afm.lua b/tex/context/base/font-afm.lua index 46ea8a423..e5c9af759 100644 --- a/tex/context/base/font-afm.lua +++ b/tex/context/base/font-afm.lua @@ -40,6 +40,8 @@ local trace_defining = false trackers.register("fonts.defining", function(v local report_afm = logs.reporter("fonts","afm loading") +local setmetatableindex = table.setmetatableindex + local findbinfile = resolvers.findbinfile local definers = fonts.definers @@ -52,7 +54,7 @@ local pfb = constructors.newhandler("pfb") local afmfeatures = constructors.newfeatures("afm") local registerafmfeature = afmfeatures.register -afm.version = 1.410 -- incrementing this number one up will force a re-cache +afm.version = 1.500 -- incrementing this number one up will force a re-cache afm.cache = containers.define("fonts", "afm", afm.version, true) afm.autoprefixed = true -- this will become false some day (catches texnansi-blabla.*) @@ -79,6 +81,16 @@ registerafmfeature { } } +local remappednames = { + ff = { name = "f_f", unicode = { 0x66, 0x66 } }, + fi = { name = "f_i", unicode = { 0x66, 0x69 } }, + fj = { name = "f_j", unicode = { 0x66, 0x6A } }, + fk = { name = "f_k", unicode = { 0x66, 0x6B } }, + fl = { name = "f_l", unicode = { 0x66, 0x6C } }, + ffi = { name = "f_f_i", unicode = { 0x66, 0x66, 0x69 } }, + ffl = { name = "f_f_l", unicode = { 0x66, 0x66, 0x6C } }, +} + --[[ldx--

We start with the basic reader which we give a name similar to the built in and reader.

@@ -315,7 +327,7 @@ by adding ligatures and kern information to the afm derived data. That way we can set them faster when defining a font.

--ldx]]-- -local addkerns, addligatures, addtexligatures, unify, normalize -- we will implement these later +local addkerns, addligatures, addtexligatures, unify, normalize, fixnames -- we will implement these later function afm.load(filename) -- hm, for some reasons not resolved yet @@ -362,6 +374,7 @@ function afm.load(filename) addkerns(data) end normalize(data) + fixnames(data) report_afm("add tounicode data") fonts.mappings.addtounicode(data,filename) data.size = size @@ -369,6 +382,7 @@ function afm.load(filename) data.pfbsize = pfbsize data.pfbtime = pfbtime report_afm("saving %a in cache",name) + data.resources.unicodes = nil -- consistent with otf but here we save not much data = containers.write(afm.cache, name, data) data = containers.read(afm.cache,name) end @@ -432,13 +446,28 @@ unify = function(data, filename) resources.filename = resolvers.unresolve(filename) -- no shortcut resources.unicodes = unicodes -- name to unicode resources.marks = { } -- todo - resources.names = names -- name to index + -- resources.names = names -- name to index resources.private = private end normalize = function(data) end +fixnames = function(data) + for k, v in next, data.descriptions do + local n = v.name + local r = remappednames[n] + if r then + if trace_indexing then + report_afm("renaming characters %a to %a",n,r.name) + end + v.name = r.name + v.unicode = r.unicode + end + end +end + + --[[ldx--

These helpers extend the basic table with extra ligatures, texligatures and extra kerns. This saves quite some lookups later.

@@ -449,7 +478,7 @@ local addthem = function(rawdata,ligatures) local descriptions = rawdata.descriptions local resources = rawdata.resources local unicodes = resources.unicodes - local names = resources.names + -- local names = resources.names for ligname, ligdata in next, ligatures do local one = descriptions[unicodes[ligname]] if one then @@ -608,8 +637,8 @@ local function copytotfm(data) local filename = constructors.checkedfilename(resources) local fontname = metadata.fontname or metadata.fullname local fullname = metadata.fullname or metadata.fontname - local endash = unicodes['space'] - local emdash = unicodes['emdash'] + local endash = 0x0020 -- space + local emdash = 0x2014 local spacer = "space" local spaceunits = 500 -- @@ -669,7 +698,7 @@ local function copytotfm(data) parameters.x_height = charxheight else -- same as otf - local x = unicodes['x'] + local x = 0x0078 -- x if x then local x = descriptions[x] if x then @@ -729,7 +758,34 @@ function afm.setfeatures(tfmdata,features) end end -local function checkfeatures(specification) +local function addtables(data) + local resources = data.resources + local lookuptags = resources.lookuptags + local unicodes = resources.unicodes + if not lookuptags then + lookuptags = { } + resources.lookuptags = lookuptags + end + setmetatableindex(lookuptags,function(t,k) + local v = type(k) == "number" and ("lookup " .. k) or k + t[k] = v + return v + end) + if not unicodes then + unicodes = { } + resources.unicodes = unicodes + setmetatableindex(unicodes,function(t,k) + setmetatableindex(unicodes,nil) + for u, d in next, data.descriptions do + local n = d.name + if n then + t[n] = u + end + end + return rawget(t,k) + end) + end + constructors.addcoreunicodes(unicodes) -- do we really need this? end local function afmtotfm(specification) @@ -759,6 +815,7 @@ local function afmtotfm(specification) if not tfmdata then local rawdata = afm.load(afmname) if rawdata and next(rawdata) then + addtables(rawdata) adddimensions(rawdata) tfmdata = copytotfm(rawdata) if tfmdata and next(tfmdata) then @@ -808,6 +865,7 @@ those that make sense for this format.

local function prepareligatures(tfmdata,ligatures,value) if value then local descriptions = tfmdata.descriptions + local hasligatures = false for unicode, character in next, tfmdata.characters do local description = descriptions[unicode] local dligatures = description.ligatures @@ -823,17 +881,20 @@ local function prepareligatures(tfmdata,ligatures,value) type = 0 } end + hasligatures = true end end + tfmdata.properties.hasligatures = hasligatures end end local function preparekerns(tfmdata,kerns,value) if value then - local rawdata = tfmdata.shared.rawdata - local resources = rawdata.resources - local unicodes = resources.unicodes + local rawdata = tfmdata.shared.rawdata + local resources = rawdata.resources + local unicodes = resources.unicodes local descriptions = tfmdata.descriptions + local haskerns = false for u, chr in next, tfmdata.characters do local d = descriptions[u] local newkerns = d[kerns] @@ -849,8 +910,10 @@ local function preparekerns(tfmdata,kerns,value) kerns[uk] = v end end + haskerns = true end end + tfmdata.properties.haskerns = haskerns end end diff --git a/tex/context/base/font-agl.lua b/tex/context/base/font-agl.lua index 42a41a15d..122d1adc2 100644 --- a/tex/context/base/font-agl.lua +++ b/tex/context/base/font-agl.lua @@ -656,6 +656,8 @@ end -- We load this table only when needed. We could use a loading mechanism -- return the table but there are no more vectors like this so why bother. +-- +-- Well, we currently hav ethis table preloaded anyway. local agl = { names = names, -- unicode -> name diff --git a/tex/context/base/font-con.lua b/tex/context/base/font-con.lua index aca705523..dd4cfa56a 100644 --- a/tex/context/base/font-con.lua +++ b/tex/context/base/font-con.lua @@ -394,7 +394,8 @@ function constructors.scale(tfmdata,specification) targetparameters.forcedsize = forcedsize -- context specific targetparameters.extrafactor = extrafactor -- context specific -- - local tounicode = resources.tounicode + local tounicode = fonts.mappings.tounicode + -- local defaultwidth = resources.defaultwidth or 0 local defaultheight = resources.defaultheight or 0 local defaultdepth = resources.defaultdepth or 0 @@ -500,7 +501,8 @@ function constructors.scale(tfmdata,specification) local autoitalicamount = properties.autoitalicamount local stackmath = not properties.nostackmath local nonames = properties.noglyphnames - local nodemode = properties.mode == "node" + 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 -- if changed and not next(changed) then changed = false @@ -594,39 +596,20 @@ function constructors.scale(tfmdata,specification) -- we can have a dumb mode (basemode without math etc) that skips most -- for unicode, character in next, characters do - local chr, description, index, touni + local chr, description, index if changed then - -- basemode hack (we try to catch missing tounicodes, e.g. needed for ssty in math cambria) local c = changed[unicode] if c then - local ligatures = character.ligatures -- the original ligatures (as we cannot rely on remapping) description = descriptions[c] or descriptions[unicode] or character character = characters[c] or character index = description.index or c - if tounicode then - touni = tounicode[index] -- nb: index! - if not touni then -- goodie - local d = descriptions[unicode] or characters[unicode] - local i = d.index or unicode - touni = tounicode[i] -- nb: index! - end - end - if ligatures and not character.ligatures then - character.ligatures = ligatures -- the original targets (for now at least.. see libertine smallcaps) - end else description = descriptions[unicode] or character index = description.index or unicode - if tounicode then - touni = tounicode[index] -- nb: index! - end end else description = descriptions[unicode] or character index = description.index or unicode - if tounicode then - touni = tounicode[index] -- nb: index! - end end local width = description.width local height = description.height @@ -669,8 +652,10 @@ function constructors.scale(tfmdata,specification) } end end - if touni then - chr.tounicode = touni + local isunicode = description.unicode + if isunicode then + chr.unicode = isunicode + chr.tounicode = tounicode(isunicode) end if hasquality then -- we could move these calculations elsewhere (saves calculations) @@ -767,7 +752,7 @@ function constructors.scale(tfmdata,specification) end end end - if not nodemode then + if haskerns then local vk = character.kerns if vk then local s = sharedkerns[vk] @@ -778,6 +763,8 @@ function constructors.scale(tfmdata,specification) end chr.kerns = s end + end + if hasligatures then local vl = character.ligatures if vl then if true then @@ -1362,3 +1349,50 @@ function constructors.applymanipulators(what,tfmdata,features,trace,report) end end end + +function constructors.addcoreunicodes(unicodes) -- maybe make this a metatable if used at all + if not unicodes then + unicodes = { } + end + unicodes.space = 0x0020 + unicodes.hyphen = 0x002D + unicodes.zwj = 0x200D + unicodes.zwnj = 0x200C + return unicodes +end + +-- -- keep for a while: old tounicode code +-- +-- if changed then +-- -- basemode hack (we try to catch missing tounicodes, e.g. needed for ssty in math cambria) +-- local c = changed[unicode] +-- if c then +-- -- local ligatures = character.ligatures -- the original ligatures (as we cannot rely on remapping) +-- description = descriptions[c] or descriptions[unicode] or character +-- character = characters[c] or character +-- index = description.index or c +-- if tounicode then +-- touni = tounicode[index] -- nb: index! +-- if not touni then -- goodie +-- local d = descriptions[unicode] or characters[unicode] +-- local i = d.index or unicode +-- touni = tounicode[i] -- nb: index! +-- end +-- end +-- -- if ligatures and not character.ligatures then +-- -- character.ligatures = ligatures -- the original targets (for now at least.. see libertine smallcaps) +-- -- end +-- else +-- description = descriptions[unicode] or character +-- index = description.index or unicode +-- if tounicode then +-- touni = tounicode[index] -- nb: index! +-- end +-- end +-- else +-- description = descriptions[unicode] or character +-- index = description.index or unicode +-- if tounicode then +-- touni = tounicode[index] -- nb: index! +-- end +-- end diff --git a/tex/context/base/font-ctx.lua b/tex/context/base/font-ctx.lua index 5920501dd..51f152baf 100644 --- a/tex/context/base/font-ctx.lua +++ b/tex/context/base/font-ctx.lua @@ -57,6 +57,8 @@ local helpers = fonts.helpers local hashes = fonts.hashes local currentfont = font.current +local aglunicodes = fonts.encodings.agl.unicodes + local nuts = nodes.nuts local tonut = nuts.tonut @@ -82,6 +84,7 @@ local characters = hashes.characters local descriptions = hashes.descriptions local properties = hashes.properties local resources = hashes.resources +local unicodes = hashes.unicodes local csnames = hashes.csnames local lastmathids = hashes.lastmathids local exheights = hashes.exheights @@ -89,6 +92,9 @@ local emwidths = hashes.emwidths local designsizefilename = fontgoodies.designsizes.filename +local context_char = context.char +local context_getvalue = context.getvalue + local otffeatures = otf.features local otftables = otf.tables @@ -1439,12 +1445,27 @@ mappings.reset() -- resets the default file -- => commands + local function nametoslot(name) local t = type(name) + local s = nil if t == "string" then - return resources[true].unicodes[name] + local slot = unicodes[true][name] + if slot then + return slot + end + slot = aglunicodes[name] + if characters[true][slot] then + return slot + else + -- not in font + end elseif t == "number" then - return n + if characters[true][name] then + return slot + else + -- not in font + end end end @@ -1472,14 +1493,14 @@ do -- else too many locals local entities = characters.entities local lowered = { } -- delayed initialization - table.setmetatableindex(lowered,function(t,k) + setmetatableindex(lowered,function(t,k) for k, v in next, entities do local l = lower(k) if not entities[l] then lowered[l] = v end end - table.setmetatableindex(lowered,nil) + setmetatableindex(lowered,nil) return lowered[k] end) @@ -1523,7 +1544,7 @@ do -- else too many locals -- -- nicer: -- - -- table.setmetatableindex(methods,function(t,k) return methods.c end) + -- setmetatableindex(methods,function(t,k) return methods.c end) -- -- local splitter = (C(1) * P(":") + Cc("c")) * C(P(1)^1) / function(method,name) -- return methods[method](name) @@ -1712,9 +1733,6 @@ end -- interfaces -local context_char = context.char -local context_getvalue = context.getvalue - local commands_doifelse = commands.doifelse function commands.doifelsecurrentfonthasfeature(name) -- can be made faster with a supportedfeatures hash diff --git a/tex/context/base/font-enh.lua b/tex/context/base/font-enh.lua index 2bf0741f5..3439a434a 100644 --- a/tex/context/base/font-enh.lua +++ b/tex/context/base/font-enh.lua @@ -114,24 +114,24 @@ local registerotffeature = otffeatures.register -- unicodes = { -- a1 = 0x2701, -local tosixteen = fonts.mappings.tounicode16 +----- tosixteen = fonts.mappings.tounicode16 local function initializeunicoding(tfmdata) local goodies = tfmdata.goodies local newcoding = nil - local tounicode = false + -- local tounicode = false for i=1,#goodies do local remapping = goodies[i].remapping if remapping and remapping.unicodes then - newcoding = remapping.unicodes -- names to unicodes - tounicode = remapping.tounicode + newcoding = remapping.unicodes -- names to unicodes + -- tounicode = remapping.tounicode -- not used end end if newcoding then local characters = tfmdata.characters local descriptions = tfmdata.descriptions local oldcoding = tfmdata.resources.unicodes - local tounicodes = tfmdata.resources.tounicode -- index to unicode + -- local tounicodes = tfmdata.resources.tounicode -- index to unicode local originals = { } for name, newcode in next, newcoding do local oldcode = oldcoding[name] @@ -153,15 +153,15 @@ local function initializeunicoding(tfmdata) else oldcoding[name] = newcode end - if tounicode then - local description = descriptions[newcode] - if description then - local index = description.index - if not tounicodes[index] then - tounicodes[index] = tosixteen(newcode) -- shared (we could have a metatable) - end - end - end + -- if tounicode then + -- local description = descriptions[newcode] + -- if description then + -- local index = description.index + -- if not tounicodes[index] then + -- tounicodes[index] = tosixteen(newcode) -- shared (we could have a metatable) + -- end + -- end + -- end if trace_unicoding then if oldcode then report_unicoding("aliasing glyph %a from %U to %U",name,oldcode,newcode) diff --git a/tex/context/base/font-ext.lua b/tex/context/base/font-ext.lua index ede2151d6..68dab3c46 100644 --- a/tex/context/base/font-ext.lua +++ b/tex/context/base/font-ext.lua @@ -328,8 +328,10 @@ local function map_opbd_onto_protrusion(tfmdata,value,opbd) local characters = tfmdata.characters local descriptions = tfmdata.descriptions local properties = tfmdata.properties + local resources = tfmdata.resources local rawdata = tfmdata.shared.rawdata local lookuphash = rawdata.lookuphash + local lookuptags = resources.lookuptags local script = properties.script local language = properties.language local done, factor, left, right = false, 1, 1, 1 @@ -349,14 +351,14 @@ local function map_opbd_onto_protrusion(tfmdata,value,opbd) local data = lookuphash[lookup] if data then if trace_protrusion then - report_protrusions("setting left using lfbd lookup %a",lookup) + report_protrusions("setting left using lfbd lookup %a",lookuptags[lookup]) end for k, v in next, data do -- local p = - v[3] / descriptions[k].width-- or 1 ~= 0 too but the same local p = - (v[1] / 1000) * factor * left characters[k].left_protruding = p if trace_protrusion then - report_protrusions("lfbd -> %s -> %C -> %0.03f (% t)",lookup,k,p,v) + report_protrusions("lfbd -> %s -> %C -> %0.03f (% t)",lookuptags[lookup],k,p,v) end end done = true @@ -372,14 +374,14 @@ local function map_opbd_onto_protrusion(tfmdata,value,opbd) local data = lookuphash[lookup] if data then if trace_protrusion then - report_protrusions("setting right using rtbd lookup %a",lookup) + report_protrusions("setting right using rtbd lookup %a",lookuptags[lookup]) end for k, v in next, data do -- local p = v[3] / descriptions[k].width -- or 3 local p = (v[1] / 1000) * factor * right characters[k].right_protruding = p if trace_protrusion then - report_protrusions("rtbd -> %s -> %C -> %0.03f (% t)",lookup,k,p,v) + report_protrusions("rtbd -> %s -> %C -> %0.03f (% t)",lookuptags[lookup],k,p,v) end end end diff --git a/tex/context/base/font-gds.lua b/tex/context/base/font-gds.lua index 9e7cb841e..c2c506b7a 100644 --- a/tex/context/base/font-gds.lua +++ b/tex/context/base/font-gds.lua @@ -853,7 +853,7 @@ local function setkeepligatures(tfmdata,value) if letterspacing then local keptligatures = letterspacing.keptligatures if keptligatures then - local unicodes = tfmdata.resources.unicodes + local unicodes = tfmdata.resources.unicodes -- so we accept names local hash = { } for k, v in next, keptligatures do local u = unicodes[k] diff --git a/tex/context/base/font-hsh.lua b/tex/context/base/font-hsh.lua index 1b0dd08b8..2be84165a 100644 --- a/tex/context/base/font-hsh.lua +++ b/tex/context/base/font-hsh.lua @@ -35,6 +35,7 @@ local italics = hashes.italics or allocate() local lastmathids = hashes.lastmathids or allocate() local dynamics = hashes.dynamics or allocate() local unicodes = hashes.unicodes or allocate() +local originals = hashes.originals or allocate() hashes.characters = characters hashes.descriptions = descriptions @@ -52,6 +53,7 @@ hashes.italics = italics hashes.lastmathids = lastmathids hashes.dynamics = dynamics hashes.unicodes = unicodes +hashes.originals = originals local nodepool = nodes.pool local dummyglyph = nodepool.register(nodepool.glyph()) @@ -261,21 +263,31 @@ setmetatableindex(dynamics, function(t,k) end end) -setmetatableindex(unicodes, function(t,k) +setmetatableindex(unicodes, function(t,k) -- always a unicode + if k == true then + return unicodes[currentfont()] + else + local resources = resources[k] + local unicodes = resources and resources.unicodes or { } + t[k] = unicodes + return unicodes + end +end) + +setmetatableindex(originals, function(t,k) -- always a unicode if k == true then return originals[currentfont()] else - local resources = resources[k] - local originals = resources and resources.originals or { } - local characters = characters[k] - local unicodes = { } - setmetatableindex(unicodes,function(t,k) - local v = originals[characters[k].index] or k - t[k] = v + local resolved = { } + setmetatableindex(resolved,function(t,name) + local u = unicodes[k][name] + local d = u and descriptions[k][u] + local v = d and d.unicode or u or 0 -- so we return notdef (at least for the moment) + t[name] = u return v end) - t[k] = unicodes - return unicodes + t[k] = resolved + return resolved end end) diff --git a/tex/context/base/font-map.lua b/tex/context/base/font-map.lua index 429c73597..309435e0d 100644 --- a/tex/context/base/font-map.lua +++ b/tex/context/base/font-map.lua @@ -79,18 +79,46 @@ end local function tounicode16sequence(unicodes,name) local t = { } for l=1,#unicodes do - local unicode = unicodes[l] - if unicode < 0x10000 then - t[l] = format("%04X",unicode) + local u = unicodes[l] + if u < 0x10000 then + t[l] = format("%04X",u) elseif unicode < 0x1FFFFFFFFF then - t[l] = format("%04X%04X",floor(unicode/1024),unicode%1024+0xDC00) + t[l] = format("%04X%04X",floor(u/1024),u%1024+0xDC00) else - report_fonts ("can't convert %a in %a into tounicode",unicode,name) + report_fonts ("can't convert %a in %a into tounicode",u,name) + return end end return concat(t) end +local function tounicode(unicode,name) + if type(unicode) == "table" then + local t = { } + for l=1,#unicode do + local u = unicode[l] + if u < 0x10000 then + t[l] = format("%04X",u) + elseif u < 0x1FFFFFFFFF then + t[l] = format("%04X%04X",floor(u/1024),u%1024+0xDC00) + else + report_fonts ("can't convert %a in %a into tounicode",u,name) + return + end + end + return concat(t) + else + if unicode < 0x10000 then + return format("%04X",unicode) + elseif unicode < 0x1FFFFFFFFF then + return format("%04X%04X",floor(unicode/1024),unicode%1024+0xDC00) + else + report_fonts("can't convert %a in %a into tounicode",unicode,name) + end + end +end + + local function fromunicode16(str) if #str == 4 then return tonumber(str,16) @@ -136,6 +164,7 @@ end mappings.loadlumtable = loadlumtable mappings.makenameparser = makenameparser +mappings.tounicode = tounicode mappings.tounicode16 = tounicode16 mappings.tounicode16sequence = tounicode16sequence mappings.fromunicode16 = fromunicode16 @@ -158,6 +187,322 @@ local namesplitter = Ct(C((1 - ligseparator - varseparator)^1) * (ligseparator * -- test("such_so_more") -- test("such_so_more.that") +-- function mappings.addtounicode(data,filename) +-- local resources = data.resources +-- local properties = data.properties +-- local descriptions = data.descriptions +-- local unicodes = resources.unicodes +-- local lookuptypes = resources.lookuptypes +-- if not unicodes then +-- return +-- end +-- -- we need to move this code +-- unicodes['space'] = unicodes['space'] or 32 +-- unicodes['hyphen'] = unicodes['hyphen'] or 45 +-- unicodes['zwj'] = unicodes['zwj'] or 0x200D +-- unicodes['zwnj'] = unicodes['zwnj'] or 0x200C +-- -- the tounicode mapping is sparse and only needed for alternatives +-- local private = fonts.constructors.privateoffset +-- local unknown = format("%04X",utfbyte("?")) +-- local unicodevector = fonts.encodings.agl.unicodes -- loaded runtime in context +-- ----- namevector = fonts.encodings.agl.names -- loaded runtime in context +-- local tounicode = { } +-- local originals = { } +-- local missing = { } +-- resources.tounicode = tounicode +-- resources.originals = originals +-- local lumunic, uparser, oparser +-- local cidinfo, cidnames, cidcodes, usedmap +-- -- if false then -- will become an option +-- -- lumunic = loadlumtable(filename) +-- -- lumunic = lumunic and lumunic.tounicode +-- -- end +-- -- +-- cidinfo = properties.cidinfo +-- usedmap = cidinfo and fonts.cid.getmap(cidinfo) +-- -- +-- if usedmap then +-- oparser = usedmap and makenameparser(cidinfo.ordering) +-- cidnames = usedmap.names +-- cidcodes = usedmap.unicodes +-- end +-- uparser = makenameparser() +-- local ns, nl = 0, 0 +-- for unic, glyph in next, descriptions do +-- local index = glyph.index +-- local name = glyph.name +-- if unic == -1 or unic >= private or (unic >= 0xE000 and unic <= 0xF8FF) or unic == 0xFFFE or unic == 0xFFFF then +-- local unicode = lumunic and lumunic[name] or unicodevector[name] +-- if unicode then +-- originals[index] = unicode +-- tounicode[index] = tounicode16(unicode,name) +-- ns = ns + 1 +-- end +-- -- cidmap heuristics, beware, there is no guarantee for a match unless +-- -- the chain resolves +-- if (not unicode) and usedmap then +-- local foundindex = lpegmatch(oparser,name) +-- if foundindex then +-- unicode = cidcodes[foundindex] -- name to number +-- if unicode then +-- originals[index] = unicode +-- tounicode[index] = tounicode16(unicode,name) +-- ns = ns + 1 +-- else +-- local reference = cidnames[foundindex] -- number to name +-- if reference then +-- local foundindex = lpegmatch(oparser,reference) +-- if foundindex then +-- unicode = cidcodes[foundindex] +-- if unicode then +-- originals[index] = unicode +-- tounicode[index] = tounicode16(unicode,name) +-- ns = ns + 1 +-- end +-- end +-- if not unicode or unicode == "" then +-- local foundcodes, multiple = lpegmatch(uparser,reference) +-- if foundcodes then +-- originals[index] = foundcodes +-- if multiple then +-- tounicode[index] = tounicode16sequence(foundcodes) +-- nl = nl + 1 +-- unicode = true +-- else +-- tounicode[index] = tounicode16(foundcodes,name) +-- ns = ns + 1 +-- unicode = foundcodes +-- end +-- end +-- end +-- end +-- end +-- end +-- end +-- -- a.whatever or a_b_c.whatever or a_b_c (no numbers) a.b_ +-- -- +-- -- It is not trivial to find a solution that suits all fonts. We tried several alternatives +-- -- and this one seems to work reasonable also with fonts that use less standardized naming +-- -- schemes. The extra private test is tested by KE and seems to work okay with non-typical +-- -- fonts as well. +-- -- +-- -- The next time I look into this, I'll add an extra analysis step to the otf loader (we can +-- -- resolve some tounicodes by looking into the gsub data tables that are bound to glyphs. +-- -- +-- if not unicode or unicode == "" then +-- local split = lpegmatch(namesplitter,name) +-- local nsplit = split and #split or 0 +-- local t, n = { }, 0 +-- unicode = true +-- for l=1,nsplit do +-- local base = split[l] +-- local u = unicodes[base] or unicodevector[base] +-- if not u then +-- break +-- elseif type(u) == "table" then +-- if u[1] >= private then +-- unicode = false +-- break +-- end +-- n = n + 1 +-- t[n] = u[1] +-- else +-- if u >= private then +-- unicode = false +-- break +-- end +-- n = n + 1 +-- t[n] = u +-- end +-- end +-- if n == 0 then -- done then +-- -- nothing +-- elseif n == 1 then +-- local unicode = t[1] +-- originals[index] = unicode +-- tounicode[index] = tounicode16(unicode,name) +-- else +-- originals[index] = t +-- tounicode[index] = tounicode16sequence(t) +-- end +-- nl = nl + 1 +-- end +-- -- last resort (we might need to catch private here as well) +-- if not unicode or unicode == "" then +-- local foundcodes, multiple = lpegmatch(uparser,name) +-- if foundcodes then +-- if multiple then +-- originals[index] = foundcodes +-- tounicode[index] = tounicode16sequence(foundcodes,name) +-- nl = nl + 1 +-- unicode = true +-- else +-- originals[index] = foundcodes +-- tounicode[index] = tounicode16(foundcodes,name) +-- ns = ns + 1 +-- unicode = foundcodes +-- end +-- end +-- end +-- -- check using substitutes and alternates +-- -- +-- if not unicode then +-- missing[name] = true +-- end +-- -- if not unicode then +-- -- originals[index] = 0xFFFD +-- -- tounicode[index] = "FFFD" +-- -- end +-- end +-- end +-- if next(missing) then +-- local guess = { } +-- -- helper +-- local function check(gname,code,unicode) +-- local description = descriptions[code] +-- -- no need to add a self reference +-- local variant = description.name +-- if variant == gname then +-- return +-- end +-- -- the variant already has a unicode (normally that resultrs in a default tounicode to self) +-- local unic = unicodes[variant] +-- if unic == -1 or unic >= private or (unic >= 0xE000 and unic <= 0xF8FF) or unic == 0xFFFE or unic == 0xFFFF then +-- -- no default mapping and therefore maybe no tounicode yet +-- else +-- return +-- end +-- -- the variant already has a tounicode +-- local index = descriptions[code].index +-- if tounicode[index] then +-- return +-- end +-- -- add to the list +-- local g = guess[variant] +-- if g then +-- g[gname] = unicode +-- else +-- guess[variant] = { [gname] = unicode } +-- end +-- end +-- -- +-- for unicode, description in next, descriptions do +-- local slookups = description.slookups +-- if slookups then +-- local gname = description.name +-- for tag, data in next, slookups do +-- local lookuptype = lookuptypes[tag] +-- if lookuptype == "alternate" then +-- for i=1,#data do +-- check(gname,data[i],unicode) +-- end +-- elseif lookuptype == "substitution" then +-- check(gname,data,unicode) +-- end +-- end +-- end +-- local mlookups = description.mlookups +-- if mlookups then +-- local gname = description.name +-- for tag, list in next, mlookups do +-- local lookuptype = lookuptypes[tag] +-- if lookuptype == "alternate" then +-- for i=1,#list do +-- local data = list[i] +-- for i=1,#data do +-- check(gname,data[i],unicode) +-- end +-- end +-- elseif lookuptype == "substitution" then +-- for i=1,#list do +-- check(gname,list[i],unicode) +-- end +-- end +-- end +-- end +-- end +-- -- resolve references +-- local done = true +-- while done do +-- done = false +-- for k, v in next, guess do +-- if type(v) ~= "number" then +-- for kk, vv in next, v do +-- if vv == -1 or vv >= private or (vv >= 0xE000 and vv <= 0xF8FF) or vv == 0xFFFE or vv == 0xFFFF then +-- local uu = guess[kk] +-- if type(uu) == "number" then +-- guess[k] = uu +-- done = true +-- end +-- else +-- guess[k] = vv +-- done = true +-- end +-- end +-- end +-- end +-- end +-- -- generate tounicodes +-- for k, v in next, guess do +-- if type(v) == "number" then +-- guess[k] = tounicode16(v) +-- else +-- local t = nil +-- local l = lower(k) +-- local u = unicodes[l] +-- if not u then +-- -- forget about it +-- elseif u == -1 or u >= private or (u >= 0xE000 and u <= 0xF8FF) or u == 0xFFFE or u == 0xFFFF then +-- local du = descriptions[u] +-- local index = du.index +-- t = tounicode[index] +-- if t then +-- tounicode[index] = v +-- originals[index] = unicode +-- end +-- else +-- -- t = u +-- end +-- if t then +-- guess[k] = t +-- else +-- guess[k] = "FFFD" +-- end +-- end +-- end +-- local orphans = 0 +-- local guessed = 0 +-- for k, v in next, guess do +-- if v == "FFFD" then +-- orphans = orphans + 1 +-- guess[k] = false +-- else +-- guessed = guessed + 1 +-- guess[k] = true +-- end +-- end +-- -- resources.nounicode = guess -- only when we test things +-- if trace_loading and orphans > 0 or guessed > 0 then +-- report_fonts("%s glyphs with no related unicode, %s guessed, %s orphans",guessed+orphans,guessed,orphans) +-- end +-- end +-- if trace_mapping then +-- for unic, glyph in table.sortedhash(descriptions) do +-- local name = glyph.name +-- local index = glyph.index +-- local toun = tounicode[index] +-- if toun then +-- report_fonts("internal slot %U, name %a, unicode %U, tounicode %a",index,name,unic,toun) +-- else +-- report_fonts("internal slot %U, name %a, unicode %U",index,name,unic) +-- end +-- end +-- end +-- if trace_loading and (ns > 0 or nl > 0) then +-- report_fonts("%s tounicode entries added, ligatures %s",nl+ns,ns) +-- end +-- end + function mappings.addtounicode(data,filename) local resources = data.resources local properties = data.properties @@ -172,22 +517,13 @@ function mappings.addtounicode(data,filename) unicodes['hyphen'] = unicodes['hyphen'] or 45 unicodes['zwj'] = unicodes['zwj'] or 0x200D unicodes['zwnj'] = unicodes['zwnj'] or 0x200C - -- the tounicode mapping is sparse and only needed for alternatives local private = fonts.constructors.privateoffset local unknown = format("%04X",utfbyte("?")) local unicodevector = fonts.encodings.agl.unicodes -- loaded runtime in context ----- namevector = fonts.encodings.agl.names -- loaded runtime in context - local tounicode = { } - local originals = { } local missing = { } - resources.tounicode = tounicode - resources.originals = originals local lumunic, uparser, oparser local cidinfo, cidnames, cidcodes, usedmap - if false then -- will become an option - lumunic = loadlumtable(filename) - lumunic = lumunic and lumunic.tounicode - end -- cidinfo = properties.cidinfo usedmap = cidinfo and fonts.cid.getmap(cidinfo) @@ -205,9 +541,8 @@ function mappings.addtounicode(data,filename) if unic == -1 or unic >= private or (unic >= 0xE000 and unic <= 0xF8FF) or unic == 0xFFFE or unic == 0xFFFF then local unicode = lumunic and lumunic[name] or unicodevector[name] if unicode then - originals[index] = unicode - tounicode[index] = tounicode16(unicode,name) - ns = ns + 1 + glyph.unicode = unicode + ns = ns + 1 end -- cidmap heuristics, beware, there is no guarantee for a match unless -- the chain resolves @@ -216,9 +551,8 @@ function mappings.addtounicode(data,filename) if foundindex then unicode = cidcodes[foundindex] -- name to number if unicode then - originals[index] = unicode - tounicode[index] = tounicode16(unicode,name) - ns = ns + 1 + glyph.unicode = unicode + ns = ns + 1 else local reference = cidnames[foundindex] -- number to name if reference then @@ -226,23 +560,20 @@ function mappings.addtounicode(data,filename) if foundindex then unicode = cidcodes[foundindex] if unicode then - originals[index] = unicode - tounicode[index] = tounicode16(unicode,name) - ns = ns + 1 + glyph.unicode = unicode + ns = ns + 1 end end if not unicode or unicode == "" then local foundcodes, multiple = lpegmatch(uparser,reference) if foundcodes then - originals[index] = foundcodes + glyph.unicode = foundcodes if multiple then - tounicode[index] = tounicode16sequence(foundcodes) - nl = nl + 1 - unicode = true + nl = nl + 1 + unicode = true else - tounicode[index] = tounicode16(foundcodes,name) - ns = ns + 1 - unicode = foundcodes + ns = ns + 1 + unicode = foundcodes end end end @@ -289,11 +620,9 @@ function mappings.addtounicode(data,filename) if n == 0 then -- done then -- nothing elseif n == 1 then - originals[index] = t[1] - tounicode[index] = tounicode16(t[1],name) + glyph.unicode = t[1] else - originals[index] = t - tounicode[index] = tounicode16sequence(t) + glyph.unicode = t end nl = nl + 1 end @@ -301,16 +630,13 @@ function mappings.addtounicode(data,filename) if not unicode or unicode == "" then local foundcodes, multiple = lpegmatch(uparser,name) if foundcodes then + glyph.unicode = foundcodes if multiple then - originals[index] = foundcodes - tounicode[index] = tounicode16sequence(foundcodes,name) - nl = nl + 1 - unicode = true + nl = nl + 1 + unicode = true else - originals[index] = foundcodes - tounicode[index] = tounicode16(foundcodes,name) - ns = ns + 1 - unicode = foundcodes + ns = ns + 1 + unicode = foundcodes end end end @@ -319,14 +645,9 @@ function mappings.addtounicode(data,filename) if not unicode then missing[name] = true end - -- if not unicode then - -- originals[index] = 0xFFFD - -- tounicode[index] = "FFFD" - -- end end end if next(missing) then --- inspect(missing) local guess = { } -- helper local function check(gname,code,unicode) @@ -344,8 +665,7 @@ function mappings.addtounicode(data,filename) return end -- the variant already has a tounicode - local index = descriptions[code].index - if tounicode[index] then + if descriptions[code].unicode then return end -- add to the list @@ -413,52 +733,51 @@ function mappings.addtounicode(data,filename) end end end - -- generate tounicodes + -- wrap up + local orphans = 0 + local guessed = 0 for k, v in next, guess do if type(v) == "number" then - guess[k] = tounicode16(v) + descriptions[unicodes[k]].unicode = descriptions[v].unicode or v -- can also be a table + guessed = guessed + 1 else local t = nil local l = lower(k) local u = unicodes[l] if not u then - -- forget about it + orphans = orphans + 1 elseif u == -1 or u >= private or (u >= 0xE000 and u <= 0xF8FF) or u == 0xFFFE or u == 0xFFFF then - t = tounicode[descriptions[u].index] - else - -- t = u - end - if t then - guess[k] = t + local unicode = descriptions[u].unicode + if unicode then + descriptions[unicodes[k]].unicode = unicode + guessed = guessed + 1 + else + orphans = orphans + 1 + end else - guess[k] = "FFFD" + orphans = orphans + 1 end end end - local orphans = 0 - local guessed = 0 - for k, v in next, guess do - tounicode[descriptions[unicodes[k]].index] = v - if v == "FFFD" then - orphans = orphans + 1 - guess[k] = false - else - guessed = guessed + 1 - guess[k] = true - end - end - -- resources.nounicode = guess -- only when we test things if trace_loading and orphans > 0 or guessed > 0 then report_fonts("%s glyphs with no related unicode, %s guessed, %s orphans",guessed+orphans,guessed,orphans) end end if trace_mapping then for unic, glyph in table.sortedhash(descriptions) do - local name = glyph.name - local index = glyph.index - local toun = tounicode[index] - if toun then - report_fonts("internal slot %U, name %a, unicode %U, tounicode %a",index,name,unic,toun) + local name = glyph.name + local index = glyph.index + local unicode = glyph.unicode + if unicode then + if type(unicode) == "table" then + local unicodes = { } + for i=1,#unicode do + unicodes[i] = formatters("%U",unicode[i]) + end + report_fonts("internal slot %U, name %a, unicode %U, tounicode % t",index,name,unic,unicodes) + else + report_fonts("internal slot %U, name %a, unicode %U, tounicode %U",index,name,unic,unicode) + end else report_fonts("internal slot %U, name %a, unicode %U",index,name,unic) end diff --git a/tex/context/base/font-mis.lua b/tex/context/base/font-mis.lua index b934837f4..96d240300 100644 --- a/tex/context/base/font-mis.lua +++ b/tex/context/base/font-mis.lua @@ -22,7 +22,7 @@ local handlers = fonts.handlers handlers.otf = handlers.otf or { } local otf = handlers.otf -otf.version = otf.version or 2.762 +otf.version = otf.version or 2.801 otf.cache = otf.cache or containers.define("fonts", "otf", otf.version, true) function otf.loadcached(filename,format,sub) diff --git a/tex/context/base/font-nod.lua b/tex/context/base/font-nod.lua index 2311cebeb..da3d9def9 100644 --- a/tex/context/base/font-nod.lua +++ b/tex/context/base/font-nod.lua @@ -407,16 +407,18 @@ local function toutf(list,result,nofresult,stopcriterium) if fc then local fcc = fc[c] if fcc then - -- == fromunicode - local u = fcc.tounicode - if u then - for s in gmatch(u,"....") do + local u = fcc.unicode + if not u then + nofresult = nofresult + 1 + result[nofresult] = utfchar(c) + elseif type(u) == "table" then + for i=1,#u do nofresult = nofresult + 1 - result[nofresult] = utfchar(tonumber(s,16)) + result[nofresult] = utfchar(u[i]) end else nofresult = nofresult + 1 - result[nofresult] = utfchar(c) + result[nofresult] = utfchar(u) end else nofresult = nofresult + 1 diff --git a/tex/context/base/font-otb.lua b/tex/context/base/font-otb.lua index a68b57c8a..4e955a197 100644 --- a/tex/context/base/font-otb.lua +++ b/tex/context/base/font-otb.lua @@ -7,7 +7,7 @@ if not modules then modules = { } end modules ['font-otb'] = { } local concat = table.concat local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip -local type, next, tonumber, tostring = type, next, tonumber, tostring +local type, next, tonumber, tostring, rawget = type, next, tonumber, tostring, rawget local lpegmatch = lpeg.match local utfchar = utf.char @@ -63,40 +63,40 @@ local function gref(descriptions,n) end end -local function cref(feature,lookupname) +local function cref(feature,lookuptags,lookupname) if lookupname then - return formatters["feature %a, lookup %a"](feature,lookupname) + return formatters["feature %a, lookup %a"](feature,lookuptags[lookupname]) else return formatters["feature %a"](feature) end end -local function report_alternate(feature,lookupname,descriptions,unicode,replacement,value,comment) +local function report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,comment) report_prepare("%s: base alternate %s => %s (%S => %S)", - cref(feature,lookupname), + cref(feature,lookuptags,lookupname), gref(descriptions,unicode), replacement and gref(descriptions,replacement), value, comment) end -local function report_substitution(feature,lookupname,descriptions,unicode,substitution) +local function report_substitution(feature,lookuptags,lookupname,descriptions,unicode,substitution) report_prepare("%s: base substitution %s => %S", - cref(feature,lookupname), + cref(feature,lookuptags,lookupname), gref(descriptions,unicode), gref(descriptions,substitution)) end -local function report_ligature(feature,lookupname,descriptions,unicode,ligature) +local function report_ligature(feature,lookuptags,lookupname,descriptions,unicode,ligature) report_prepare("%s: base ligature %s => %S", - cref(feature,lookupname), + cref(feature,lookuptags,lookupname), gref(descriptions,ligature), gref(descriptions,unicode)) end -local function report_kern(feature,lookupname,descriptions,unicode,otherunicode,value) +local function report_kern(feature,lookuptags,lookupname,descriptions,unicode,otherunicode,value) report_prepare("%s: base kern %s + %s => %S", - cref(feature,lookupname), + cref(feature,lookuptags,lookupname), gref(descriptions,unicode), gref(descriptions,otherunicode), value) @@ -181,7 +181,7 @@ local function finalize_ligatures(tfmdata,ligatures) local characters = tfmdata.characters local descriptions = tfmdata.descriptions local resources = tfmdata.resources - local unicodes = resources.unicodes + local unicodes = resources.unicodes -- we use rawget in order to avoid bulding the table local private = resources.private local alldone = false while not alldone do @@ -217,12 +217,12 @@ local function finalize_ligatures(tfmdata,ligatures) local secondname = firstname .. "_" .. secondcode if i == size - 1 then target = unicode - if not unicodes[secondname] then + if not rawget(unicodes,secondname) then unicodes[secondname] = unicode -- map final ligature onto intermediates end okay = true else - target = unicodes[secondname] + target = rawget(unicodes,secondname) if not target then break end @@ -258,6 +258,7 @@ local function finalize_ligatures(tfmdata,ligatures) end end resources.private = private + return true end end @@ -265,10 +266,11 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis local characters = tfmdata.characters local descriptions = tfmdata.descriptions local resources = tfmdata.resources + local properties = tfmdata.properties local changed = tfmdata.changed - local unicodes = resources.unicodes local lookuphash = resources.lookuphash local lookuptypes = resources.lookuptypes + local lookuptags = resources.lookuptags local ligatures = { } local alternate = tonumber(value) or true and 1 @@ -279,39 +281,39 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis local trace_ligatures = trace_baseinit and trace_ligatures local actions = { - substitution = function(lookupdata,lookupname,description,unicode) + substitution = function(lookupdata,lookuptags,lookupname,description,unicode) if trace_singles then - report_substitution(feature,lookupname,descriptions,unicode,lookupdata) + report_substitution(feature,lookuptags,lookupname,descriptions,unicode,lookupdata) end changed[unicode] = lookupdata end, - alternate = function(lookupdata,lookupname,description,unicode) + alternate = function(lookupdata,lookuptags,lookupname,description,unicode) local replacement = lookupdata[alternate] if replacement then changed[unicode] = replacement if trace_alternatives then - report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"normal") + report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,"normal") end elseif defaultalt == "first" then replacement = lookupdata[1] changed[unicode] = replacement if trace_alternatives then - report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt) + report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,defaultalt) end elseif defaultalt == "last" then replacement = lookupdata[#data] if trace_alternatives then - report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt) + report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,defaultalt) end else if trace_alternatives then - report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"unknown") + report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,"unknown") end end end, - ligature = function(lookupdata,lookupname,description,unicode) + ligature = function(lookupdata,lookuptags,lookupname,description,unicode) if trace_ligatures then - report_ligature(feature,lookupname,descriptions,unicode,lookupdata) + report_ligature(feature,lookuptags,lookupname,descriptions,unicode,lookupdata) end ligatures[#ligatures+1] = { unicode, lookupdata } end, @@ -328,7 +330,7 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis local lookuptype = lookuptypes[lookupname] local action = actions[lookuptype] if action then - action(lookupdata,lookupname,description,unicode) + action(lookupdata,lookuptags,lookupname,description,unicode) end end end @@ -343,24 +345,25 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis local action = actions[lookuptype] if action then for i=1,#lookuplist do - action(lookuplist[i],lookupname,description,unicode) + action(lookuplist[i],lookuptags,lookupname,description,unicode) end end end end end end - - finalize_ligatures(tfmdata,ligatures) + properties.hasligatures = finalize_ligatures(tfmdata,ligatures) end local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist) -- todo what kind of kerns, currently all local characters = tfmdata.characters local descriptions = tfmdata.descriptions local resources = tfmdata.resources - local unicodes = resources.unicodes + local properties = tfmdata.properties + local lookuptags = resources.lookuptags local sharedkerns = { } local traceindeed = trace_baseinit and trace_kerns + local haskerns = false for unicode, character in next, characters do local description = descriptions[unicode] local rawkerns = description.kerns -- shared @@ -384,13 +387,13 @@ local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist newkerns = { [otherunicode] = value } done = true if traceindeed then - report_kern(feature,lookup,descriptions,unicode,otherunicode,value) + report_kern(feature,lookuptags,lookup,descriptions,unicode,otherunicode,value) end elseif not newkerns[otherunicode] then -- first wins newkerns[otherunicode] = value done = true if traceindeed then - report_kern(feature,lookup,descriptions,unicode,otherunicode,value) + report_kern(feature,lookuptags,lookup,descriptions,unicode,otherunicode,value) end end end @@ -399,12 +402,14 @@ local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist if done then sharedkerns[rawkerns] = newkerns character.kerns = newkerns -- no empty assignments + haskerns = true else sharedkerns[rawkerns] = false end end end end + properties.haskerns = haskerns end basemethods.independent = { @@ -434,13 +439,13 @@ local function make_1(present,tree,name) end end -local function make_2(present,tfmdata,characters,tree,name,preceding,unicode,done,lookupname) +local function make_2(present,tfmdata,characters,tree,name,preceding,unicode,done,lookuptags,lookupname) for k, v in next, tree do if k == "ligature" then local character = characters[preceding] if not character then if trace_baseinit then - report_prepare("weird ligature in lookup %a, current %C, preceding %C",lookupname,v,preceding) + report_prepare("weird ligature in lookup %a, current %C, preceding %C",lookuptags[lookupname],v,preceding) end character = makefake(tfmdata,name,present) end @@ -461,7 +466,7 @@ local function make_2(present,tfmdata,characters,tree,name,preceding,unicode,don else local code = present[name] or unicode local name = name .. "_" .. k - make_2(present,tfmdata,characters,v,name,code,k,done,lookupname) + make_2(present,tfmdata,characters,v,name,code,k,done,lookuptags,lookupname) end end end @@ -473,6 +478,7 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis local changed = tfmdata.changed local lookuphash = resources.lookuphash local lookuptypes = resources.lookuptypes + local lookuptags = resources.lookuptags local ligatures = { } local alternate = tonumber(value) or true and 1 @@ -489,7 +495,7 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis for unicode, data in next, lookupdata do if lookuptype == "substitution" then if trace_singles then - report_substitution(feature,lookupname,descriptions,unicode,data) + report_substitution(feature,lookuptags,lookupname,descriptions,unicode,data) end changed[unicode] = data elseif lookuptype == "alternate" then @@ -497,28 +503,28 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis if replacement then changed[unicode] = replacement if trace_alternatives then - report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"normal") + report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,"normal") end elseif defaultalt == "first" then replacement = data[1] changed[unicode] = replacement if trace_alternatives then - report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt) + report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,defaultalt) end elseif defaultalt == "last" then replacement = data[#data] if trace_alternatives then - report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt) + report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,defaultalt) end else if trace_alternatives then - report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"unknown") + report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,"unknown") end end elseif lookuptype == "ligature" then ligatures[#ligatures+1] = { unicode, data, lookupname } if trace_ligatures then - report_ligature(feature,lookupname,descriptions,unicode,data) + report_ligature(feature,lookuptags,lookupname,descriptions,unicode,data) end end end @@ -541,7 +547,7 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis for i=1,nofligatures do local ligature = ligatures[i] local unicode, tree, lookupname = ligature[1], ligature[2], ligature[3] - make_2(present,tfmdata,characters,tree,"ctx_"..unicode,unicode,unicode,done,lookupname) + make_2(present,tfmdata,characters,tree,"ctx_"..unicode,unicode,unicode,done,lookuptags,lookupname) end end @@ -552,11 +558,11 @@ local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist local characters = tfmdata.characters local descriptions = tfmdata.descriptions local resources = tfmdata.resources + local properties = tfmdata.properties local lookuphash = resources.lookuphash + local lookuptags = resources.lookuptags local traceindeed = trace_baseinit and trace_kerns - -- check out this sharedkerns trickery - for l=1,#lookuplist do local lookupname = lookuplist[l] local lookupdata = lookuphash[lookupname] @@ -571,7 +577,7 @@ local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist for otherunicode, kern in next, data do if not kerns[otherunicode] and kern ~= 0 then kerns[otherunicode] = kern - report_kern(feature,lookup,descriptions,unicode,otherunicode,kern) + report_kern(feature,lookuptags,lookup,descriptions,unicode,otherunicode,kern) end end else diff --git a/tex/context/base/font-otf.lua b/tex/context/base/font-otf.lua index c1bb4419c..58a72508a 100644 --- a/tex/context/base/font-otf.lua +++ b/tex/context/base/font-otf.lua @@ -24,7 +24,9 @@ local reversed, concat, remove, sortedkeys = table.reversed, table.concat, table local ioflush = io.flush local fastcopy, tohash, derivetable = table.fastcopy, table.tohash, table.derive local formatters = string.formatters +local P, R, S, C, Ct, lpegmatch = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Ct, lpeg.match +local setmetatableindex = table.setmetatableindex local allocate = utilities.storage.allocate local registertracker = trackers.register local registerdirective = directives.register @@ -33,13 +35,16 @@ local stoptiming = statistics.stoptiming local elapsedtime = statistics.elapsedtime local findbinfile = resolvers.findbinfile -local trace_private = false registertracker("otf.private", function(v) trace_private = v end) -local trace_loading = false registertracker("otf.loading", function(v) trace_loading = v end) -local trace_features = false registertracker("otf.features", function(v) trace_features = v end) -local trace_dynamics = false registertracker("otf.dynamics", function(v) trace_dynamics = v end) -local trace_sequences = false registertracker("otf.sequences", function(v) trace_sequences = v end) -local trace_markwidth = false registertracker("otf.markwidth", function(v) trace_markwidth = v end) -local trace_defining = false registertracker("fonts.defining", function(v) trace_defining = v end) +local trace_private = false registertracker("otf.private", function(v) trace_private = v end) +local trace_loading = false registertracker("otf.loading", function(v) trace_loading = v end) +local trace_features = false registertracker("otf.features", function(v) trace_features = v end) +local trace_dynamics = false registertracker("otf.dynamics", function(v) trace_dynamics = v end) +local trace_sequences = false registertracker("otf.sequences", function(v) trace_sequences = v end) +local trace_markwidth = false registertracker("otf.markwidth", function(v) trace_markwidth = v end) +local trace_defining = false registertracker("fonts.defining", function(v) trace_defining = v end) + +local compact_lookups = true registertracker("otf.compactlookups", function(v) compact_lookups = v end) +local purge_names = true registertracker("otf.purgenames", function(v) purge_names = v end) local report_otf = logs.reporter("fonts","otf loading") @@ -48,13 +53,17 @@ local otf = fonts.handlers.otf otf.glists = { "gsub", "gpos" } -otf.version = 2.762 -- beware: also sync font-mis.lua +otf.version = 2.801 -- beware: also sync font-mis.lua otf.cache = containers.define("fonts", "otf", otf.version, true) local fontdata = fonts.hashes.identifiers local chardata = characters and characters.data -- not used -local otffeatures = fonts.constructors.newfeatures("otf") +local definers = fonts.definers +local readers = fonts.readers +local constructors = fonts.constructors + +local otffeatures = constructors.newfeatures("otf") local registerotffeature = otffeatures.register local enhancers = allocate() @@ -62,13 +71,8 @@ otf.enhancers = enhancers local patches = { } enhancers.patches = patches -local definers = fonts.definers -local readers = fonts.readers -local constructors = fonts.constructors - local forceload = false local cleanup = 0 -- mk: 0=885M 1=765M 2=735M (regular run 730M) -local usemetatables = false -- .4 slower on mk but 30 M less mem so we might change the default -- will be directive local packdata = true local syncspace = true local forcenotdef = false @@ -93,7 +97,6 @@ formats.dfont = "truetype" registerdirective("fonts.otf.loader.cleanup", function(v) cleanup = tonumber(v) or (v and 1) or 0 end) registerdirective("fonts.otf.loader.force", function(v) forceload = v end) -registerdirective("fonts.otf.loader.usemetatables", function(v) usemetatables = v end) registerdirective("fonts.otf.loader.pack", function(v) packdata = v end) registerdirective("fonts.otf.loader.syncspace", function(v) syncspace = v end) registerdirective("fonts.otf.loader.forcenotdef", function(v) forcenotdef = v end) @@ -280,6 +283,9 @@ local ordered_enhancers = { "add duplicates", "cleanup tables", + + "compact lookups", + "purge names", } --[[ldx-- @@ -495,7 +501,7 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone }, helpers = { -- might go away tounicodelist = splitter, - tounicodetable = lpeg.Ct(splitter), + tounicodetable = Ct(splitter), }, } starttiming(data) @@ -538,6 +544,39 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone report_otf("loading from cache using hash %a",hash) end enhance("unpack",data,filename,nil,false) + -- + local resources = data.resources + local lookuptags = resources.lookuptags + local unicodes = resources.unicodes + if not lookuptags then + lookuptags = { } + resources.lookuptags = lookuptags + end + setmetatableindex(lookuptags,function(t,k) + local v = type(k) == "number" and ("lookup " .. k) or k + t[k] = v + return v + end) + if not unicodes then + unicodes = { } + resources.unicodes = unicodes + setmetatableindex(unicodes,function(t,k) + -- use rawget when no table has to be built + setmetatableindex(unicodes,nil) + for u, d in next, data.descriptions do + local n = d.name + if n then + t[n] = u + -- report_otf("accessing known name %a",k) + else + -- report_otf("accessing unknown name %a",k) + end + end + return rawget(t,k) + end) + end + constructors.addcoreunicodes(unicodes) -- do we really need this? + -- if applyruntimefixes then applyruntimefixes(filename,data) end @@ -579,41 +618,29 @@ actions["add dimensions"] = function(data,filename) local defaultheight = resources.defaultheight or 0 local defaultdepth = resources.defaultdepth or 0 local basename = trace_markwidth and file.basename(filename) - if usemetatables then - for _, d in next, descriptions do - local wd = d.width - if not wd then - d.width = defaultwidth - elseif trace_markwidth and wd ~= 0 and d.class == "mark" then - report_otf("mark %a with width %b found in %a",d.name or "",wd,basename) - -- d.width = -wd - end - setmetatable(d,mt) + for _, d in next, descriptions do + local bb, wd = d.boundingbox, d.width + if not wd then + -- or bb? + d.width = defaultwidth + elseif trace_markwidth and wd ~= 0 and d.class == "mark" then + report_otf("mark %a with width %b found in %a",d.name or "",wd,basename) + -- d.width = -wd end - else - for _, d in next, descriptions do - local bb, wd = d.boundingbox, d.width - if not wd then - d.width = defaultwidth - elseif trace_markwidth and wd ~= 0 and d.class == "mark" then - report_otf("mark %a with width %b found in %a",d.name or "",wd,basename) - -- d.width = -wd + -- if forcenotdef and not d.name then + -- d.name = ".notdef" + -- end + if bb then + local ht, dp = bb[4], -bb[2] + if ht == 0 or ht < 0 then + -- not set + else + d.height = ht end - -- if forcenotdef and not d.name then - -- d.name = ".notdef" - -- end - if bb then - local ht, dp = bb[4], -bb[2] - if ht == 0 or ht < 0 then - -- not set - else - d.height = ht - end - if dp == 0 or dp < 0 then - -- not set - else - d.depth = dp - end + if dp == 0 or dp < 0 then + -- not set + else + d.depth = dp end end end @@ -1301,9 +1328,9 @@ local function s_uncover(splitter,cache,cover) local uncovered = cache[cover] if not uncovered then uncovered = lpegmatch(splitter,cover) --- for i=1,#uncovered do --- uncovered[i] = { [uncovered[i]] = true } --- end + -- for i=1,#uncovered do + -- uncovered[i] = { [uncovered[i]] = true } + -- end cache[cover] = uncovered end return { uncovered } @@ -1317,9 +1344,14 @@ local function t_hashed(t,cache) local ti = t[i] local tih = cache[ti] if not tih then - tih = { } - for i=1,#ti do - tih[ti[i]] = true + local tn = #ti + if tn == 1 then + tih = { [ti[1]] = true } + else + tih = { } + for i=1,tn do + tih[ti[i]] = true + end end cache[ti] = tih end @@ -1335,12 +1367,17 @@ end local function s_hashed(t,cache) if t then - local ht = { } local tf = t[1] - for i=1,#tf do - ht[i] = { [tf[i]] = true } + local nf = #tf + if nf == 1 then + return { [tf[1]] = true } + else + local ht = { } + for i=1,nf do + ht[i] = { [tf[i]] = true } + end + return ht end - return ht else return nil end @@ -1791,7 +1828,7 @@ end -- future versions will remove _ -local valid = (lpeg.R("\x00\x7E") - lpeg.S("(){}[]<>%/ \n\r\f\v"))^0 * lpeg.P(-1) +local valid = (R("\x00\x7E") - S("(){}[]<>%/ \n\r\f\v"))^0 * P(-1) local function valid_ps_name(str) return str and str ~= "" and #str < 64 and lpegmatch(valid,str) and true or false @@ -1853,8 +1890,17 @@ actions["check metadata"] = function(data,filename,raw) end actions["cleanup tables"] = function(data,filename,raw) - data.resources.indices = nil -- not needed - data.helpers = nil + local duplicates = data.resources.duplicates + if duplicates then + for k, v in next, duplicates do + if #v == 1 then + duplicates[k] = v[1] + end + end + end + data.resources.indices = nil -- not needed + data.resources.unicodes = nil -- delayed + data.helpers = nil -- tricky as we have no unicodes any more end -- kern: ttf has a table with kerns @@ -1976,6 +2022,164 @@ actions["reorganize glyph anchors"] = function(data,filename,raw) -- when we rep end end +local bogusname = (P("uni") + P("u")) * R("AF","09")^4 + + (P("index") + P("glyph") + S("Ii") * P("dentity") * P(".")^0) * R("09")^1 +local uselessname = (1-bogusname)^0 * bogusname + +actions["purge names"] = function(data,filename,raw) -- not used yet + if purge_names then + local n = 0 + for u, d in next, data.descriptions do + if lpegmatch(uselessname,d.name) then + n = n + 1 + d.name = nil + end + -- d.comment = nil + end + if n > 0 then + report_otf("%s bogus names removed",n) + end + end +end + +actions["compact lookups"] = function(data,filename,raw) + if not compact_lookups then + report_otf("not compacting") + return + end + -- create keyhash + local last = 0 + local tags = table.setmetatableindex({ }, + function(t,k) + last = last + 1 + t[k] = last + return last + end + ) + -- + local descriptions = data.descriptions + local resources = data.resources + -- + for u, d in next, descriptions do + -- + -- -- we can also compact anchors and cursives (basechar basemark baselig mark) + -- + local slookups = d.slookups + if type(slookups) == "table" then + local s = { } + for k, v in next, slookups do + s[tags[k]] = v + end + d.slookups = s + end + -- + local mlookups = d.mlookups + if type(mlookups) == "table" then + local m = { } + for k, v in next, mlookups do + m[tags[k]] = v + end + d.mlookups = m + end + -- + local kerns = d.kerns + if type(kerns) == "table" then + local t = { } + for k, v in next, kerns do + t[tags[k]] = v + end + d.kerns = t + end + end + -- + local lookups = data.lookups + if lookups then + local l = { } + for k, v in next, lookups do + local rules = v.rules + if rules then + for i=1,#rules do + local l = rules[i].lookups + if type(l) == "table" then + for i=1,#l do + l[i] = tags[l[i]] + end + end + end + end + l[tags[k]] = v + end + data.lookups = l + end + -- + local lookups = resources.lookups + if lookups then + local l = { } + for k, v in next, lookups do + local s = v.subtables + if type(s) == "table" then + for i=1,#s do + s[i] = tags[s[i]] + end + end + l[tags[k]] = v + end + resources.lookups = l + end + -- + local sequences = resources.sequences + if sequences then + for i=1,#sequences do + local s = sequences[i] + local n = s.name + if n then + s.name = tags[n] + end + local t = s.subtables + if type(t) == "table" then + for i=1,#t do + t[i] = tags[t[i]] + end + end + end + end + -- + local lookuptypes = resources.lookuptypes + if lookuptypes then + local l = { } + for k, v in next, lookuptypes do + l[tags[k]] = v + end + resources.lookuptypes = l + end + -- + local anchor_to_lookup = resources.anchor_to_lookup + if anchor_to_lookup then + for anchor, lookups in next, anchor_to_lookup do + local l = { } + for lookup, value in next, lookups do + l[tags[lookup]] = value + end + anchor_to_lookup[anchor] = l + end + end + -- + local lookup_to_anchor = resources.lookup_to_anchor + if lookup_to_anchor then + local l = { } + for lookup, value in next, lookup_to_anchor do + l[tags[lookup]] = value + end + resources.lookup_to_anchor = l + end + -- + tags = table.swapped(tags) + -- + report_otf("%s lookup tags compacted",#tags) + -- + resources.lookuptags = tags +end + -- modes: node, base, none function otf.setfeatures(tfmdata,features) @@ -2116,8 +2320,8 @@ local function copytotfm(data,cache_id) parameters.charwidth = charwidth parameters.charxheight = charxheight -- - local space = 0x0020 -- unicodes['space'], unicodes['emdash'] - local emdash = 0x2014 -- unicodes['space'], unicodes['emdash'] + local space = 0x0020 + local emdash = 0x2014 if monospaced then if descriptions[space] then spaceunits, spacer = descriptions[space].width, "space" @@ -2166,7 +2370,7 @@ local function copytotfm(data,cache_id) if charxheight then parameters.x_height = charxheight else - local x = 0x78 -- unicodes['x'] + local x = 0x0078 if x then local x = descriptions[x] if x then @@ -2204,7 +2408,6 @@ local function copytotfm(data,cache_id) end report_otf() end - -- return { characters = characters, descriptions = descriptions, @@ -2234,14 +2437,23 @@ local function otftotfm(specification) if duplicates then local nofduplicates, nofduplicated = 0, 0 for parent, list in next, duplicates do - for i=1,#list do - local unicode = list[i] - if not descriptions[unicode] then - descriptions[unicode] = descriptions[parent] -- or copy + if type(list) == "table" then + local n = #list + for i=1,n do + local unicode = list[i] + if not descriptions[unicode] then + descriptions[unicode] = descriptions[parent] -- or copy + nofduplicated = nofduplicated + 1 + end + end + nofduplicates = nofduplicates + n + else + if not descriptions[list] then + descriptions[list] = descriptions[parent] -- or copy nofduplicated = nofduplicated + 1 end + nofduplicates = nofduplicates + 1 end - nofduplicates = nofduplicates + #list end if trace_otf and nofduplicated ~= nofduplicates then report_otf("%i extra duplicates copied out of %i",nofduplicated,nofduplicates) diff --git a/tex/context/base/font-otn.lua b/tex/context/base/font-otn.lua index c35dcf27c..32dc820d3 100644 --- a/tex/context/base/font-otn.lua +++ b/tex/context/base/font-otn.lua @@ -269,6 +269,7 @@ local currentfont = false local lookuptable = false local anchorlookups = false local lookuptypes = false +local lookuptags = false local handlers = { } local rlmode = 0 local featurevalue = false @@ -323,20 +324,20 @@ end local function cref(kind,chainname,chainlookupname,lookupname,index) -- not in the mood to alias f_ if index then - return formatters["feature %a, chain %a, sub %a, lookup %a, index %a"](kind,chainname,chainlookupname,lookupname,index) + return formatters["feature %a, chain %a, sub %a, lookup %a, index %a"](kind,chainname,chainlookupname,lookuptags[lookupname],index) elseif lookupname then - return formatters["feature %a, chain %a, sub %a, lookup %a"](kind,chainname,chainlookupname,lookupname) + return formatters["feature %a, chain %a, sub %a, lookup %a"](kind,chainname,chainlookupname,lookuptags[lookupname]) elseif chainlookupname then - return formatters["feature %a, chain %a, sub %a"](kind,chainname,chainlookupname) + return formatters["feature %a, chain %a, sub %a"](kind,lookuptags[chainname],lookuptags[chainlookupname]) elseif chainname then - return formatters["feature %a, chain %a"](kind,chainname) + return formatters["feature %a, chain %a"](kind,lookuptags[chainname]) else return formatters["feature %a"](kind) end end local function pref(kind,lookupname) - return formatters["feature %a, lookup %a"](kind,lookupname) + return formatters["feature %a, lookup %a"](kind,lookuptags[lookupname]) end -- We can assume that languages that use marks are not hyphenated. We can also assume @@ -1924,7 +1925,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end else local i = 1 - repeat + while true do if skipped then while true do local char = getchar(start) @@ -1965,12 +1966,14 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end end end - if start then + if i > nofchainlookups then + break + elseif start then start = getnext(start) else -- weird end - until i > nofchainlookups + end end else local replacements = ck[7] @@ -2169,6 +2172,7 @@ local function featuresprocessor(head,font,attr) anchorlookups = resources.lookup_to_anchor lookuptable = resources.lookups lookuptypes = resources.lookuptypes + lookuptags = resources.lookuptags currentfont = font rlmode = 0 @@ -2769,6 +2773,7 @@ local function prepare_contextchains(tfmdata) local rawdata = tfmdata.shared.rawdata local resources = rawdata.resources local lookuphash = resources.lookuphash + local lookuptags = resources.lookuptags local lookups = rawdata.lookups if lookups then for lookupname, lookupdata in next, rawdata.lookups do @@ -2782,7 +2787,7 @@ local function prepare_contextchains(tfmdata) report_prepare("unsupported format %a",format) elseif not validformat[lookuptype] then -- todo: dejavu-serif has one (but i need to see what use it has) - report_prepare("unsupported format %a, lookuptype %a, lookupname %a",format,lookuptype,lookupname) + report_prepare("unsupported format %a, lookuptype %a, lookupname %a",format,lookuptype,lookuptags[lookupname]) else local contexts = lookuphash[lookupname] if not contexts then @@ -2838,7 +2843,7 @@ local function prepare_contextchains(tfmdata) -- no rules end else - report_prepare("missing lookuptype for lookupname %a",lookupname) + report_prepare("missing lookuptype for lookupname %a",lookuptags[lookupname]) end end end diff --git a/tex/context/base/font-otp.lua b/tex/context/base/font-otp.lua index 60eee0738..63e4184c1 100644 --- a/tex/context/base/font-otp.lua +++ b/tex/context/base/font-otp.lua @@ -140,6 +140,11 @@ end -- return b -- end +-- beware: we cannot unpack and repack the same table because then sharing +-- interferes (we could catch this if needed) .. so for now: save, reload +-- and repack in such cases (never needed anyway) .. a tricky aspect is that +-- we then need to sort more thanks to random hashing + local function packdata(data) if data then -- stripdata(data) @@ -898,3 +903,4 @@ if otf.enhancers.register then end otf.enhancers.unpack = unpackdata -- used elsewhere +otf.enhancers.pack = packdata -- used elsewhere diff --git a/tex/context/base/font-tfm.lua b/tex/context/base/font-tfm.lua index 827d70586..14c130d10 100644 --- a/tex/context/base/font-tfm.lua +++ b/tex/context/base/font-tfm.lua @@ -114,6 +114,11 @@ local function read_from_tfm(specification) features.encoding = encoding end end + -- let's play safe: + properties.haskerns = true + properties.haslogatures = true + resources.unicodes = { } + resources.lookuptags = { } -- return tfmdata end diff --git a/tex/context/base/grph-epd.lua b/tex/context/base/grph-epd.lua index 4f9d46097..8dcb58b3d 100644 --- a/tex/context/base/grph-epd.lua +++ b/tex/context/base/grph-epd.lua @@ -22,4 +22,7 @@ function figures.mergegoodies(optionlist) if all or options[variables.layer] then codeinjections.mergeviewerlayers() end + if all or options[variables.bookmark] then + codeinjections.mergebookmarks() + end end diff --git a/tex/context/base/grph-epd.mkiv b/tex/context/base/grph-epd.mkiv index 58526fd44..444fa55a6 100644 --- a/tex/context/base/grph-epd.mkiv +++ b/tex/context/base/grph-epd.mkiv @@ -32,7 +32,7 @@ \c!offset=\v!overlay, \c!background={\v!foreground,system:graphics:epdf}] -\def\grph_epdf_add_overlay +\unexpanded\def\grph_epdf_add_overlay {\global\setbox\foundexternalfigure\vbox\bgroup \system_graphics_epdf{\box\foundexternalfigure}% \egroup} diff --git a/tex/context/base/grph-inc.lua b/tex/context/base/grph-inc.lua index f83c759b3..28ef5d462 100644 --- a/tex/context/base/grph-inc.lua +++ b/tex/context/base/grph-inc.lua @@ -38,6 +38,8 @@ The TeX-Lua mix is suboptimal. This has to do with the fact that we cannot run TeX code from within Lua. Some more functionality will move to Lua. ]]-- +-- todo: store loaded pages per pdf file someplace + local format, lower, find, match, gsub, gmatch = string.format, string.lower, string.find, string.match, string.gsub, string.gmatch local contains = table.contains local concat, insert, remove = table.concat, table.insert, table.remove @@ -67,6 +69,8 @@ local texsetbox = tex.setbox local hpack = node.hpack +local new_latelua = nodes.pool.latelua + local context = context local variables = interfaces.variables @@ -1172,6 +1176,13 @@ function checkers.generic(data) return data end +local nofimages = 0 +local pofimages = { } + +function figures.getrealpage(index) + return pofimages[index] or 0 +end + function includers.generic(data) local dr, du, ds = data.request, data.used, data.status -- here we set the 'natural dimensions' @@ -1195,7 +1206,18 @@ function includers.generic(data) if figure then local nr = figures.boxnumber -- it looks like we have a leak in attributes here .. todo - local box = hpack(images.node(figure)) -- images.node(figure) not longer valid + + nofimages = nofimages + 1 + ds.pageindex = nofimages + local image = images.node(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) -- images.node(figure) not longer valid + indexed[figure.index] = figure box.width, box.height, box.depth = figure.width, figure.height, 0 -- new, hm, tricky, we need to do that in tex (yet) texsetbox(nr,box) diff --git a/tex/context/base/l-table.lua b/tex/context/base/l-table.lua index e642106cc..3eb8b8514 100644 --- a/tex/context/base/l-table.lua +++ b/tex/context/base/l-table.lua @@ -54,7 +54,7 @@ local function compare(a,b) if ta == tb then return a < b else - return tostring(a) < tostring(b) + return tostring(a) < tostring(b) -- not that efficient end end diff --git a/tex/context/base/lang-def.mkiv b/tex/context/base/lang-def.mkiv index 5c1d6de9c..088f86eb8 100644 --- a/tex/context/base/lang-def.mkiv +++ b/tex/context/base/lang-def.mkiv @@ -510,7 +510,8 @@ \c!rightquote=’, \c!leftquotation=“, \c!rightquotation=”, - \c!date={서기,\v!year,년,\v!month,월,\v!day,일}] + % \c!date={서기,\space,\v!year,\labeltext{\v!year},\space,\v!month,\labeltext{\v!month},\space,\v!day,\labeltext{\v!day}}] + \c!date={\v!year,\labeltext{\v!year},\space,\v!month,\labeltext{\v!month},\space,\v!day,\labeltext{\v!day}}] % Greek diff --git a/tex/context/base/lang-txt.lua b/tex/context/base/lang-txt.lua index 4f9f242e6..0cfb5bcea 100644 --- a/tex/context/base/lang-txt.lua +++ b/tex/context/base/lang-txt.lua @@ -415,6 +415,27 @@ data.labels={ }, }, texts={ + ["year"]={ + labels={ + en="year", + nl="jaar", + kr="년", + }, + }, + ["month"]={ + labels={ + en="month", + nl="maand", + kr="월", + }, + }, + ["day"]={ + labels={ + en="day", + nl="dag", + kr="일", + }, + }, ["and"]={ labels={ af="", @@ -506,7 +527,7 @@ data.labels={ hu="április", it="aprile", ja="4", - kr="4월", + kr="4", la="Aprilis", lt="balandžio", nb="april", @@ -613,7 +634,7 @@ data.labels={ hu="augusztus", it="agosto", ja="8", - kr="8월", + kr="8", la="Augustus", lt="rugpjūčio", nb="august", @@ -756,7 +777,7 @@ data.labels={ hu="december", it="dicembre", ja="12", - kr="12월", + kr="12", la="December", lt="gruodžio", nb="desember", @@ -828,7 +849,7 @@ data.labels={ hu="február", it="febbraio", ja="2", - kr="2월", + kr="2", la="Februarius", lt="vasario", nb="februar", @@ -898,7 +919,7 @@ data.labels={ hu=",. ábra:", it="Fig. ", ja="図", - kr="그림", + kr="그림 ", la="Imago ", lt=", pav.", nb="Figur ", @@ -1053,6 +1074,7 @@ data.labels={ hr="vidi ispod", hu="lásd lejjebb", it="come mostrato sotto", + kr="이후로", la="", lt="kaip parodyta žemiau", nb="som vist under", @@ -1128,7 +1150,7 @@ data.labels={ hu="január", it="gennaio", ja="1", - kr="1월", + kr="1", la="Ianuarius", lt="sausio", nb="januar", @@ -1201,7 +1223,7 @@ data.labels={ hu="július", it="luglio", ja="7", - kr="7월", + kr="7", la="Iulius", lt="liepos", nb="juli", @@ -1273,7 +1295,7 @@ data.labels={ hu="június", it="giugno", ja="6", - kr="6월", + kr="6", la="Iunius", lt="birželio", nb="juni", @@ -1418,7 +1440,7 @@ data.labels={ hu="március", it="marzo", ja="3", - kr="3월", + kr="3", la="Martius", lt="kovo", nb="mars", @@ -1491,7 +1513,7 @@ data.labels={ hu="május", it="maggio", ja="5", - kr="5월", + kr="5", la="Maius", lt="gegužės", nb="mai", @@ -1600,7 +1622,7 @@ data.labels={ hu="november", it="novembre", ja="11", - kr="11월", + kr="11", la="November", lt="lapkričio", nb="november", @@ -1671,7 +1693,7 @@ data.labels={ hu="október", it="ottobre", ja="10", - kr="10월", + kr="10", la="October", lt="spalio", nb="oktober", @@ -1925,7 +1947,7 @@ data.labels={ hu="szeptember", it="settembre", ja="9", - kr="9월", + kr="9", la="September", lt="rugsėjo", nb="september", @@ -2143,7 +2165,7 @@ data.labels={ hu=",. táblázat:", it="Tabella ", ja="表", - kr="표", + kr="표 ", la="Tabula ", lt=", lentelė.", nb="Tabell ", @@ -2367,7 +2389,7 @@ data.labels={ hu="Ábrák", it="Figure", ja="図", - kr="그림", + kr="그림 ", la="Imagines", lt="Iliustracijos", nb="Figurer", @@ -2404,7 +2426,7 @@ data.labels={ hu="Grafikák", it="Grafici", ja="グラフ", - kr="그래픽", + kr="그래픽 ", la="Typi", lt="Graphics", nb="Bilde", @@ -2441,7 +2463,7 @@ data.labels={ hu="Index", it="Indice", ja="目次", - kr="색인", + kr="찾아보기", la="Indices", lt="Rodyklė", nb="Register", @@ -2549,6 +2571,7 @@ data.labels={ hr="Literatura", hu="Bibliográfia", it="Bibliografia", + kr="참고문헌", la="", lt="Literatūra", nb="", @@ -2585,7 +2608,7 @@ data.labels={ hu="Táblázatok", it="Tabelle", ja="机", - kr="표", + kr="표 ", la="Tabulae", lt="Lentelės", nb="Tabeller", diff --git a/tex/context/base/lpdf-ano.lua b/tex/context/base/lpdf-ano.lua index 14359e2c7..ab78ec0a1 100644 --- a/tex/context/base/lpdf-ano.lua +++ b/tex/context/base/lpdf-ano.lua @@ -1032,52 +1032,103 @@ function specials.action(var) end local function build(levels,start,parent,method) - local startlevel = levels[start][1] + local startlevel = levels[start].level local i, n = start, 0 local child, entry, m, prev, first, last, f, l while i and i <= #levels do - local li = levels[i] - local level, title, reference, open = li[1], li[2], li[3], li[4] - if level < startlevel then - pdfflushobject(child,entry) - return i, n, first, last - elseif level == startlevel then - if trace_bookmarks then - report_bookmark("%3i %w%s %s",reference.realpage,(level-1)*2,(open and "+") or "-",title) - end - local prev = child - child = pdfreserveobject() - if entry then - entry.Next = child and pdfreference(child) - pdfflushobject(prev,entry) - end - entry = pdfdictionary { - Title = pdfunicode(title), - Parent = parent, - Prev = prev and pdfreference(prev), - A = somedestination(reference.internal,reference.internal,reference.realpage), - } - -- entry.Dest = somedestination(reference.internal,reference.internal,reference.realpage) - if not first then first, last = child, child end - prev = child - last = prev - n = n + 1 + local current = levels[i] + if current.usedpage == false then + -- safeguard i = i + 1 - elseif i < #levels and level > startlevel then - i, m, f, l = build(levels,i,pdfreference(child),method) - entry.Count = (open and m) or -m - if m > 0 then - entry.First, entry.Last = pdfreference(f), pdfreference(l) - end else - -- missing intermediate level but ok - i, m, f, l = build(levels,i,pdfreference(child),method) - entry.Count = (open and m) or -m - if m > 0 then - entry.First, entry.Last = pdfreference(f), pdfreference(l) + local level = current.level + local title = current.title + local reference = current.reference + local opened = current.opened + local reftype = type(reference) + local variant = "unknown" + if reftype == "table" then + -- we're okay + variant = "list" + elseif reftype == "string" then + local resolved = references.identify("",reference) + local realpage = resolved and structures.references.setreferencerealpage(resolved) or 0 + if realpage > 0 then + variant = "realpage" + realpage = realpage + end + elseif reftype == "number" then + if reference > 0 then + variant = "realpage" + realpage = reference + end + else + -- error + end + if variant == "unknown" then + -- error, ignore + i = i + 1 + elseif level < startlevel then + if entry then + pdfflushobject(child,entry) + else + -- some error + end + return i, n, first, last + elseif level == startlevel then + if trace_bookmarks then + report_bookmark("%3i %w%s %s",reference.realpage,(level-1)*2,(opened and "+") or "-",title) + end + local prev = child + child = pdfreserveobject() + if entry then + entry.Next = child and pdfreference(child) + pdfflushobject(prev,entry) + end + local action = nil + if variant == "list" then + action = somedestination(reference.internal,reference.internal,reference.realpage) + elseif variant == "realpage" then + action = pagereferences[realpage] + end + entry = pdfdictionary { + Title = pdfunicode(title), + Parent = parent, + Prev = prev and pdfreference(prev), + A = action, + } + -- entry.Dest = somedestination(reference.internal,reference.internal,reference.realpage) + if not first then first, last = child, child end + prev = child + last = prev + n = n + 1 + i = i + 1 + elseif i < #levels and level > startlevel then + i, m, f, l = build(levels,i,pdfreference(child),method) + if entry then + entry.Count = (opened and m) or -m + if m > 0 then + entry.First = pdfreference(f) + entry.Last = pdfreference(l) + end + else + -- some error + end + else + -- missing intermediate level but ok + i, m, f, l = build(levels,i,pdfreference(child),method) + if entry then + entry.Count = (opened and m) or -m + if m > 0 then + entry.First = pdfreference(f) + entry.Last = pdfreference(l) + end + pdfflushobject(child,entry) + else + -- some error + end + return i, n, first, last end - pdfflushobject(child,entry) - return i, n, first, last end end pdfflushobject(child,entry) @@ -1085,8 +1136,7 @@ local function build(levels,start,parent,method) end function codeinjections.addbookmarks(levels,method) - if #levels > 0 then - structures.bookmarks.flatten(levels) -- dirty trick for lack of structure + if levels and #levels > 0 then local parent = pdfreserveobject() local _, m, first, last = build(levels,1,pdfreference(parent),method or "internal") local dict = pdfdictionary { diff --git a/tex/context/base/lpdf-epa.lua b/tex/context/base/lpdf-epa.lua index fd4d9eb7e..0440ba2cd 100644 --- a/tex/context/base/lpdf-epa.lua +++ b/tex/context/base/lpdf-epa.lua @@ -10,30 +10,40 @@ if not modules then modules = { } end modules ['lpdf-epa'] = { -- change. local type, tonumber = type, tonumber -local format, gsub = string.format, string.gsub +local format, gsub, lower = string.format, string.gsub, string.lower local formatters = string.formatters ----- lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns -local trace_links = false trackers.register("figures.links", function(v) trace_links = v end) -local report_link = logs.reporter("backend","merging") +local trace_links = false trackers.register("figures.links", function(v) trace_links = v end) +local trace_outlines = false trackers.register("figures.outliness", function(v) trace_outlines = v end) + +local report_link = logs.reporter("backend","link") +local report_outline = logs.reporter("backend","outline") local backends = backends local lpdf = lpdf local context = context +local nameonly = file.nameonly + local variables = interfaces.variables local codeinjections = backends.pdf.codeinjections ----- urlescaper = lpegpatterns.urlescaper ----- utftohigh = lpegpatterns.utftohigh local escapetex = characters.filters.utf.private.escape +local bookmarks = structures.bookmarks + local layerspec = { -- predefining saves time "epdflinks" } +local f_namespace = formatters["lpdf-epa-%s-"] + local function makenamespace(filename) - return format("lpdf-epa-%s-",file.removesuffix(file.basename(filename))) + filename = gsub(lower(nameonly(filename)),"[^%a%d]+","-") + return f_namespace(filename) end local function add_link(x,y,w,h,destination,what) @@ -71,7 +81,7 @@ local function link_goto(x,y,w,h,document,annotation,pagedata,namespace) if type(destination) == "string" then local destinations = document.destinations local wanted = destinations[destination] - destination = wanted and wanted.D + destination = wanted and wanted.D -- is this ok? isn't it destination already a string? if destination then what = "named" end end local pagedata = destination and destination[1] @@ -131,7 +141,7 @@ function codeinjections.mergereferences(specification) end if specification then local fullname = specification.fullname - local document = lpdf.epdf.load(fullname) + local document = lpdf.epdf.load(fullname) -- costs time if document then local pagenumber = specification.page or 1 local xscale = specification.yscale or 1 @@ -139,22 +149,33 @@ function codeinjections.mergereferences(specification) local size = specification.size or "crop" -- todo local pagedata = document.pages[pagenumber] local annotations = pagedata and pagedata.Annots +local namespace = makenamespace(fullname) +local reference = namespace .. pagenumber if annotations and annotations.n > 0 then - local namespace = format("lpdf-epa-%s-",file.removesuffix(file.basename(fullname))) - local reference = namespace .. pagenumber - local mediabox = pagedata.MediaBox - local llx, lly, urx, ury = mediabox[1], mediabox[2], mediabox[3], mediabox[4] - local width, height = xscale * (urx - llx), yscale * (ury - lly) -- \\overlaywidth, \\overlayheight +-- local namespace = makenamespace(fullname) +-- local reference = namespace .. pagenumber + local mediabox = pagedata.MediaBox + local llx = mediabox[1] + local lly = mediabox[2] + local urx = mediabox[3] + local ury = mediabox[4] + local width = xscale * (urx - llx) -- \\overlaywidth, \\overlayheight + local height = yscale * (ury - lly) -- \\overlaywidth, \\overlayheight context.definelayer( { "epdflinks" }, { height = height.."bp" , width = width.."bp" }) for i=1,annotations.n do local annotation = annotations[i] if annotation then - local subtype = annotation.Subtype + local subtype = annotation.Subtype local rectangle = annotation.Rect - local a_llx, a_lly, a_urx, a_ury = rectangle[1], rectangle[2], rectangle[3], rectangle[4] - local x, y = xscale * (a_llx - llx), yscale * (a_lly - lly) - local w, h = xscale * (a_urx - a_llx), yscale * (a_ury - a_lly) - if subtype == "Link" then + local a_llx = rectangle[1] + local a_lly = rectangle[2] + local a_urx = rectangle[3] + local a_ury = rectangle[4] + local x = xscale * (a_llx - llx) + local y = yscale * (a_lly - lly) + local w = xscale * (a_urx - a_llx) + local h = yscale * (a_ury - a_lly) + if subtype == "Link" then local a = annotation.A if a then local linktype = a.S @@ -168,7 +189,7 @@ function codeinjections.mergereferences(specification) report_link("unsupported link annotation %a",linktype) end else - report_link("mising link annotation") + report_link("missing link annotation") end elseif trace_links then report_link("unsupported annotation %a",subtype) @@ -178,21 +199,21 @@ function codeinjections.mergereferences(specification) end end context.flushlayer { "epdflinks" } - -- context("\\gdef\\figurereference{%s}",reference) -- global +end context.setgvalue("figurereference",reference) -- global if trace_links then report_link("setting figure reference to %a",reference) end specification.reference = reference return namespace - end +-- end end end return ""-- no namespace, empty, not nil end function codeinjections.mergeviewerlayers(specification) - -- todo: parse included page for layers + -- todo: parse included page for layers .. or only for whole document inclusion if true then return end @@ -204,7 +225,7 @@ function codeinjections.mergeviewerlayers(specification) local fullname = specification.fullname local document = lpdf.epdf.load(fullname) if document then - local namespace = format("lpdf:epa:%s:",file.removesuffix(file.basename(fullname))) + local namespace = makenamespace(fullname) local layers = document.layers if layers then for i=1,layers.n do @@ -232,3 +253,155 @@ function codeinjections.mergeviewerlayers(specification) end end +-- new: for taco + +function codeinjections.getbookmarks(filename) + + -- The first version built a nested tree and flattened that afterwards ... but I decided + -- to keep it simple and flat. + + local list = bookmarks.extras.get(filename) + + if list then + return list + else + list = { } + end + + local document = nil + + if lfs.isfile(filename) then + document = lpdf.epdf.load(filename) + else + report_outline("unknown file %a",filename) + bookmarks.extras.register(filename,list) + return list + end + + local outlines = document.Catalog.Outlines + local pages = document.pages + local nofpages = pages.n -- we need to access once in order to initialize + local destinations = document.destinations + + -- I need to check this destination analyzer with the one in annotations .. best share + -- code (and not it's inconsistent). On the todo list ... + + local function setdestination(current,entry) + local destination = nil + local action = current.A + if action then + local subtype = action.S + if subtype == "GoTo" then + destination = action.D + if type(destination) == "string" then + entry.destination = destination + destination = destinations[destination] + local pagedata = destination and destination[1] + if pagedata then + entry.realpage = pagedata.number + end + else + -- maybe + end + else + -- maybe + end + else + local destination = current.Dest + if destination then + if type(destination) == "string" then + local wanted = destinations[destination] + destination = wanted and wanted.D + if destination then + entry.destination = destination + end + else + local pagedata = destination and destination[1] + if pagedata and pagedata.Type == "Page" then + entry.realpage = pagedata.number + end + end + end + end + end + + local function traverse(current,depth) + while current do + local title = current.Title + if title then + local entry = { + level = depth, + title = title, + } + list[#list+1] = entry + setdestination(current,entry) + if trace_outlines then + report_outline("%w%s",2*depth,title) + end + end + local first = current.First + if first then + local current = first + while current do + local title = current.Title + if title and trace_outlines then + report_outline("%w%s",2*depth,title) + end + local entry = { + level = depth, + title = title, + } + setdestination(current,entry) + list[#list+1] = entry + traverse(current.First,depth+1) + current = current.Next + end + end + current = current.Next + end + end + + if outlines then + if trace_outlines then + report_outline("outline of %a:",document.filename) + report_outline() + end + traverse(outlines,0) + if trace_outlines then + report_outline() + end + elseif trace_outlines then + report_outline("no outline in %a",document.filename) + end + + bookmarks.extras.register(filename,list) + + return list + +end + +function codeinjections.mergebookmarks(specification) + -- codeinjections.getbookmarks(document) + if not specification then + specification = figures and figures.current() + specification = specification and specification.status + end + if specification then + local fullname = specification.fullname + local bookmarks = backends.codeinjections.getbookmarks(fullname) + local realpage = tonumber(specification.page) or 1 + for i=1,#bookmarks do + local b = bookmarks[i] + if not b.usedpage then + if b.realpage == realpage then + if trace_options then + report_outline("using %a at page %a of file %a",b.title,realpage,fullname) + end + b.usedpage = true + b.section = structures.sections.currentsectionindex() + b.pageindex = specification.pageindex + end + end + end + end +end diff --git a/tex/context/base/lpdf-epd.lua b/tex/context/base/lpdf-epd.lua index c37336d07..c13f09614 100644 --- a/tex/context/base/lpdf-epd.lua +++ b/tex/context/base/lpdf-epd.lua @@ -6,22 +6,28 @@ if not modules then modules = { } end modules ['lpdf-epd'] = { license = "see context related readme files" } --- This is an experimental layer around the epdf library. The reason for --- this layer is that I want to be independent of the library (which --- implements a selection of what a file provides) and also because I --- want an interface closer to Lua's table model while the API stays --- close to the original xpdf library. Of course, after prototyping a --- solution, we can optimize it using the low level epdf accessors. +-- This is an experimental layer around the epdf library. The reason for this layer is that +-- I want to be independent of the library (which implements a selection of what a file +-- provides) and also because I want an interface closer to Lua's table model while the API +-- stays close to the original xpdf library. Of course, after prototyping a solution, we can +-- optimize it using the low level epdf accessors. --- It will be handy when we have a __length and __next that can trigger --- the resolve till then we will provide .n as #. +-- It will be handy when we have a __length and __next that can trigger the resolve till then +-- we will provide .n as #. --- As there can be references to the parent we cannot expand a tree. I --- played with some expansion variants but it does to pay off. +-- As there can be references to the parent we cannot expand a tree. I played with some +-- expansion variants but it does to pay off. + +-- Maybe we need a close(). In fact, nilling the document root will result in a gc at some +-- point. --- Maybe we need a close(). -- We cannot access all destinations in one run. +-- We have much more checking then needed in the prepare functions because occasionally +-- we run into bugs in poppler or the epdf interface. It took us a while to realize that +-- there was a long standing gc issue the on long runs with including many pages could +-- crash the analyzer. + local setmetatable, rawset, rawget, tostring, tonumber = setmetatable, rawset, rawget, tostring, tonumber local lower, match, char, find, sub = string.lower, string.match, string.char, string.find, string.sub local concat = table.concat @@ -29,9 +35,39 @@ local toutf = string.toutf local report_epdf = logs.reporter("epdf") --- a bit of protection +-- v:getTypeName(), versus types[v:getType()], the last variant is about twice as fast + +local typenames = { [0] = + "boolean", + "integer", + "real", + "string", + "name", + "null", + "array", + "dictionary", + "stream", + "ref", + "cmd", + "error", + "eof", + "none", + "integer64", +} + +local typenumbers = table.swapped(typenames) -local limited = false +local null_code = typenumbers.null +local ref_code = typenumbers.ref + +local function fatal_error(...) + report_epdf(...) + -- we exit as we will crash anyway + report_epdf("aborting job in order to avoid crash") + os.exit() +end + +local limited = false -- abit of protection directives.register("system.inputmode", function(v) if not limited then @@ -57,29 +93,75 @@ lpdf.epdf = { } local checked_access +-- dictionaries + +-- local function prepare(document,d,t,n,k,mt) +-- for i=1,n do +-- local v = d:getVal(i) +-- local r = d:getValNF(i) +-- local key = d:getKey(i) +-- if r and r:getTypeName() == "ref" then +-- r = r:getRef().num +-- local c = document.cache[r] +-- if c then +-- -- +-- else +-- c = checked_access[v:getTypeName()](v,document,r) +-- if c then +-- document.cache[r] = c +-- document.xrefs[c] = r +-- end +-- end +-- t[key] = c +-- elseif v then +-- t[key] = checked_access[v:getTypeName()](v,document) +-- else +-- fatal_error("fatal error: no data for key %s in dictionary",key) +-- end +-- end +-- getmetatable(t).__index = nil -- ?? weird +-- setmetatable(t,mt) +-- return t[k] +-- end + local function prepare(document,d,t,n,k,mt) +-- print("start prepare dict, requesting key ",k,"out of",n) for i=1,n do local v = d:getVal(i) - local r = d:getValNF(i) - if r:getTypeName() == "ref" then - r = r:getRef().num - local c = document.cache[r] - if c then - -- + if v then + local r = d:getValNF(i) + local kind = v:getType() +-- print("checking",i,d:getKey(i),v:getTypeName()) + if kind == null_code then + -- report_epdf("warning: null value for key %a in dictionary",key) else - c = checked_access[v:getTypeName()](v,document,r) - if c then - document.cache[r] = c - document.xrefs[c] = r + local key = d:getKey(i) + if kind then + if r and r:getType() == ref_code then + local objnum = r:getRef().num + local cached = document.cache[objnum] + if not cached then + cached = checked_access[kind](v,document,objnum) + if c then + document.cache[objnum] = cached + document.xrefs[cached] = objnum + end + end + t[key] = cached + else + t[key] = checked_access[kind](v,document) + end + else + report_epdf("warning: nil value for key %a in dictionary",key) end end - t[d:getKey(i)] = c else - t[d:getKey(i)] = checked_access[v:getTypeName()](v,document) + fatal_error("error: invalid value at index %a in dictionary of %a",i,document.filename) end end +-- print("done") getmetatable(t).__index = nil -- ?? weird -setmetatable(t,mt) + setmetatable(t,mt) return t[k] end @@ -92,27 +174,62 @@ local function some_dictionary(d,document,r,mt) end end +-- arrays + local done = { } +-- local function prepare(document,a,t,n,k) +-- for i=1,n do +-- local v = a:get(i) +-- local r = a:getNF(i) +-- local kind = v:getTypeName() +-- if kind == "null" then +-- -- TH: weird, but appears possible +-- elseif r:getTypeName() == "ref" then +-- r = r:getRef().num +-- local c = document.cache[r] +-- if c then +-- -- +-- else +-- c = checked_access[kind](v,document,r) +-- document.cache[r] = c +-- document.xrefs[c] = r +-- end +-- t[i] = c +-- else +-- t[i] = checked_access[kind](v,document) +-- end +-- end +-- getmetatable(t).__index = nil +-- return t[k] +-- end + local function prepare(document,a,t,n,k) for i=1,n do local v = a:get(i) - local r = a:getNF(i) - if v:getTypeName() == "null" then - -- TH: weird, but appears possible - elseif r:getTypeName() == "ref" then - r = r:getRef().num - local c = document.cache[r] - if c then - -- + if v then + local kind = v:getType() + if kind == null_code then + -- report_epdf("warning: null value for index %a in array",i) + elseif kind then + local r = a:getNF(i) + if r and r:getType() == ref_code then + local objnum = r:getRef().num + local cached = document.cache[objnum] + if not cached then + cached = checked_access[kind](v,document,objnum) + document.cache[objnum] = cached + document.xrefs[cached] = objnum + end + t[i] = cached + else + t[i] = checked_access[kind](v,document) + end else - c = checked_access[v:getTypeName()](v,document,r) - document.cache[r] = c - document.xrefs[c] = r + report_epdf("warning: nil value for index %a in array",i) end - t[i] = c else - t[i] = checked_access[v:getTypeName()](v,document) + fatal_error("error: invalid value at index %a in array of %a",i,document.filename) end end getmetatable(t).__index = nil @@ -156,38 +273,167 @@ end -- we need epdf.boolean(v) in addition to v:getBool() [dictionary, array, stream, real, integer, string, boolean, name, ref, null] -checked_access = { - dictionary = function(d,document,r) - return some_dictionary(d:getDict(),document,r) - end, - array = function(a,document,r) - return some_array(a:getArray(),document,r) - end, - stream = function(v,document,r) - return some_stream(v,document,r) - end, - real = function(v) - return v:getReal() - end, - integer = function(v) - return v:getNum() - end, - string = function(v) - return toutf(v:getString()) - end, - boolean = function(v) - return v:getBool() - end, - name = function(v) - return v:getName() - end, - ref = function(v) - return v:getRef() - end, - null = function() - return nil - end, -} +-- checked_access = { +-- dictionary = function(d,document,r) +-- return some_dictionary(d:getDict(),document,r) +-- end, +-- array = function(a,document,r) +-- return some_array(a:getArray(),document,r) +-- end, +-- stream = function(v,document,r) +-- return some_stream(v,document,r) +-- end, +-- real = function(v) +-- return v:getReal() +-- end, +-- integer = function(v) +-- return v:getNum() +-- end, +-- -- integer64 = function(v) +-- -- return v:getNum() +-- -- end, +-- string = function(v) +-- return toutf(v:getString()) +-- end, +-- boolean = function(v) +-- return v:getBool() +-- end, +-- name = function(v) +-- return v:getName() +-- end, +-- ref = function(v) +-- return v:getRef() +-- end, +-- null = function() +-- return nil +-- end, +-- none = function() +-- -- why not null +-- return nil +-- end, +-- -- error = function() +-- -- -- shouldn't happen +-- -- return nil +-- -- end, +-- -- eof = function() +-- -- -- we don't care +-- -- return nil +-- -- end, +-- -- cmd = function() +-- -- -- shouldn't happen +-- -- return nil +-- -- end +-- } + +-- a bit of a speedup in case we want to play with large pdf's and have millions +-- of access .. it might not be worth the trouble + +-- we have dual access: by typenumber and by typename + +local function invalidaccess(k,document) + local fullname = type(document) == "table" and document.fullname + if fullname then + fatal_error("error, asking for key %a in checker of %a",k,fullname) + else + fatal_error("error, asking for key %a in checker",k) + end +end + +checked_access = table.setmetatableindex(function(t,k) + return function(v,document) + invalidaccess(k,document) + end +end) + +for i=0,#typenames do + checked_access[i] = function() + return function(v,document) + invalidaccess(i,document) + end + end +end + +checked_access[typenumbers.dictionary] = function(d,document,r) + local getDict = d.getDict + local getter = function(d,document,r) + return some_dictionary(getDict(d),document,r) + end + checked_access.dictionary = getter + checked_access[typenumbers.dictionary] = getter + return getter(d,document,r) +end + +checked_access[typenumbers.array] = function(a,document,r) + local getArray = a.getArray + local getter = function(a,document,r) + return some_array(getArray(a),document,r) + end + checked_access.array = getter + checked_access[typenumbers.array] = getter + return getter(a,document,r) +end + +checked_access[typenumbers.stream] = function(v,document,r) + return some_stream(v,document,r) -- or just an equivalent +end + +checked_access[typenumbers.real] = function(v) + local getReal = v.getReal + checked_access.real = getReal + checked_access[typenumbers.real] = getReal + return getReal(v) +end + +checked_access[typenumbers.integer] = function(v) + local getNum = v.getNum + checked_access.integer = getNum + checked_access[typenumbers.integer] = getNum + return getNum(v) +end + +checked_access[typenumbers.string] = function(v) + local getString = v.getString + local function getter(v) + return toutf(getString(v)) + end + checked_access.string = getter + checked_access[typenumbers.string] = getter + return toutf(getString(v)) +end + +checked_access[typenumbers.boolean] = function(v) + local getBool = v.getBool + checked_access.boolean = getBool + checked_access[typenumbers.boolean] = getBool + return getBool(v) +end + +checked_access[typenumbers.name] = function(v) + local getName = v.getName + checked_access.name = getName + checked_access[typenumbers.name] = getName + return getName(v) +end + +checked_access[typenumbers.ref] = function(v) + local getRef = v.getRef + checked_access.ref = getRef + checked_access[typenumbers.ref] = getRef + return getRef(v) +end + +checked_access[typenumbers.null] = function() + return nil +end + +checked_access[typenumbers.none] = function() + -- is actually an error + return nil +end + +for i=0,#typenames do + checked_access[typenames[i]] = checked_access[i] +end -- checked_access.real = epdf.real -- checked_access.integer = epdf.integer @@ -345,6 +591,14 @@ function lpdf.epdf.load(filename) xrefs = { }, data = data, } + -- table.setmetatablenewindex(document.cache,function(t,k,v) + -- if rawget(t,k) then + -- report_epdf("updating object %a in cache",k) + -- else + -- report_epdf("storing object %a in cache",k) + -- end + -- rawset(t,k,v) + -- end) local Catalog = some_dictionary(data:getXRef():getCatalog():getDict(),document) local Info = some_dictionary(data:getXRef():getDocInfo():getDict(),document) document.Catalog = Catalog @@ -362,10 +616,19 @@ function lpdf.epdf.load(filename) document = false end loaded[filename] = document + loaded[document] = document statistics.stoptiming(lpdf.epdf) -- print(statistics.elapsedtime(lpdf.epdf)) end - return document + return document or nil +end + +function lpdf.epdf.unload(filename) + local document = loaded[filename] + if document then + loaded[document] = nil + loaded[filename] = nil + end end -- for k, v in next, expand(t) do diff --git a/tex/context/base/m-pstricks.mkii b/tex/context/base/m-pstricks.mkii index bdcf13b24..d41f19871 100644 --- a/tex/context/base/m-pstricks.mkii +++ b/tex/context/base/m-pstricks.mkii @@ -43,7 +43,7 @@ {\input multido \relax \input pstricks \relax \input pst-plot \relax - \loadpstrickscolors{colo-rgb}} + \loadpstrickscolors{colo-rgb.mkii}} {\writestatus{pstricks}{using indirect method; enable write18}} \catcode`\|=\oldbarcode diff --git a/tex/context/base/math-fbk.lua b/tex/context/base/math-fbk.lua index 63a0e9f88..7c97249d6 100644 --- a/tex/context/base/math-fbk.lua +++ b/tex/context/base/math-fbk.lua @@ -20,7 +20,6 @@ local virtualcharacters = { } local identifiers = fonts.hashes.identifiers local lastmathids = fonts.hashes.lastmathids -local tounicode16 = fonts.mappings.tounicode16 -- we need a trick (todo): if we define scriptscript, script and text in -- that order we could use their id's .. i.e. we could always add a font @@ -346,11 +345,11 @@ local function accent_to_extensible(target,newchr,original,oldchr,height,depth,s end local correction = swap and { "down", (olddata.height or 0) - height } or { "down", olddata.height + (offset or 0)} local newdata = { - commands = { correction, { "slot", 1, oldchr } }, - width = olddata.width, - height = height, - depth = depth, - tounicode = tounicode16(unicode), + commands = { correction, { "slot", 1, oldchr } }, + width = olddata.width, + height = height, + depth = depth, + unicode = unicode, } local glyphdata = newdata local nextglyph = olddata.next @@ -401,9 +400,6 @@ local function accent_to_extensible(target,newchr,original,oldchr,height,depth,s end return glyphdata, true else --- if not olddata.tounicode then --- olddata.tounicode = tounicode16(unicode), --- end return olddata, false end end @@ -448,9 +444,9 @@ addextra(0xFE3DF, { description="EXTENSIBLE OF 0x03DF", unicodeslot=0xFE3DF, mat addextra(0xFE3DD, { description="EXTENSIBLE OF 0x03DD", unicodeslot=0xFE3DD, mathextensible = "r", mathstretch = "h", mathclass = "botaccent" } ) addextra(0xFE3B5, { description="EXTENSIBLE OF 0x03B5", unicodeslot=0xFE3B5, mathextensible = "r", mathstretch = "h", mathclass = "botaccent" } ) -virtualcharacters[0xFE3DF] = function(data) local c = data.target.characters[0x23DF] if c then c.tounicode = tounicode16(0x23DF) return c end end -virtualcharacters[0xFE3DD] = function(data) local c = data.target.characters[0x23DD] if c then c.tounicode = tounicode16(0x23DD) return c end end -virtualcharacters[0xFE3B5] = function(data) local c = data.target.characters[0x23B5] if c then c.tounicode = tounicode16(0x23B5) return c end end +virtualcharacters[0xFE3DF] = function(data) local c = data.target.characters[0x23DF] if c then c.unicode = 0x23DF return c end end +virtualcharacters[0xFE3DD] = function(data) local c = data.target.characters[0x23DD] if c then c.unicode = 0x23DD return c end end +virtualcharacters[0xFE3B5] = function(data) local c = data.target.characters[0x23B5] if c then c.unicode = 0x23B5 return c end end -- todo: add some more .. numbers might change @@ -524,7 +520,7 @@ local function actuarian(data) -- todo: add alttext -- compromise: lm has large hooks e.g. \actuarial{a} width = basewidth + 4 * linewidth, - tounicode = tounicode16(0x20E7), + unicode = 0x20E7, commands = { { "right", 2 * linewidth }, { "down", - baseheight - 3 * linewidth }, diff --git a/tex/context/base/math-tag.lua b/tex/context/base/math-tag.lua index 638c4629c..6b555650e 100644 --- a/tex/context/base/math-tag.lua +++ b/tex/context/base/math-tag.lua @@ -141,8 +141,7 @@ local function getunicode(n) -- instead of getchar local char = getchar(n) local font = font_of_family(getfield(n,"fam")) -- font_of_family local data = fontcharacters[font][char] - local unic = data.tounicode - return unic and fromunicode16(unic) or char + return data.unicode or char end process = function(start) -- we cannot use the processor as we have no finalizers (yet) diff --git a/tex/context/base/mult-de.mkii b/tex/context/base/mult-de.mkii index 1751f4780..53f0dfd6a 100644 --- a/tex/context/base/mult-de.mkii +++ b/tex/context/base/mult-de.mkii @@ -653,7 +653,7 @@ \setinterfaceconstant{coupling}{verknuepfung} \setinterfaceconstant{couplingway}{verkopplungsart} \setinterfaceconstant{criterium}{kriterium} -\setinterfaceconstant{css}{css} +\setinterfaceconstant{cssfile}{cssfile} \setinterfaceconstant{current}{aktuell} \setinterfaceconstant{cutspace}{cutspace} \setinterfaceconstant{dash}{strich} diff --git a/tex/context/base/mult-def.lua b/tex/context/base/mult-def.lua index ffb95f76b..b41053dd5 100644 --- a/tex/context/base/mult-def.lua +++ b/tex/context/base/mult-def.lua @@ -6508,8 +6508,8 @@ return { ["export"] = { ["en"]="export", }, - ["css"] = { - ["en"]="css", + ["cssfile"] = { + ["en"]="cssfile", }, ["xhtml"] = { ["en"]="xhtml", diff --git a/tex/context/base/mult-def.mkiv b/tex/context/base/mult-def.mkiv index 5761e6cfb..30a21d377 100644 --- a/tex/context/base/mult-def.mkiv +++ b/tex/context/base/mult-def.mkiv @@ -96,6 +96,8 @@ \def\v!long {long} \def\v!box {box} +\def\v!bookmark {bookmark} + \def\v!vfenced {vfenced} \def\v!bothtext {bothtext} diff --git a/tex/context/base/mult-en.mkii b/tex/context/base/mult-en.mkii index 72185f3ab..346f94cad 100644 --- a/tex/context/base/mult-en.mkii +++ b/tex/context/base/mult-en.mkii @@ -653,7 +653,7 @@ \setinterfaceconstant{coupling}{coupling} \setinterfaceconstant{couplingway}{couplingway} \setinterfaceconstant{criterium}{criterium} -\setinterfaceconstant{css}{css} +\setinterfaceconstant{cssfile}{cssfile} \setinterfaceconstant{current}{current} \setinterfaceconstant{cutspace}{cutspace} \setinterfaceconstant{dash}{dash} diff --git a/tex/context/base/mult-fr.mkii b/tex/context/base/mult-fr.mkii index 2a6d85c91..681c67bbc 100644 --- a/tex/context/base/mult-fr.mkii +++ b/tex/context/base/mult-fr.mkii @@ -653,7 +653,7 @@ \setinterfaceconstant{coupling}{couplage} \setinterfaceconstant{couplingway}{modecouplage} \setinterfaceconstant{criterium}{critere} -\setinterfaceconstant{css}{css} +\setinterfaceconstant{cssfile}{cssfile} \setinterfaceconstant{current}{courant} \setinterfaceconstant{cutspace}{cutspace} \setinterfaceconstant{dash}{pointille} diff --git a/tex/context/base/mult-it.mkii b/tex/context/base/mult-it.mkii index 9eb0139a1..4f9941a04 100644 --- a/tex/context/base/mult-it.mkii +++ b/tex/context/base/mult-it.mkii @@ -653,7 +653,7 @@ \setinterfaceconstant{coupling}{accoppiamento} \setinterfaceconstant{couplingway}{modoaccoppiamento} \setinterfaceconstant{criterium}{criterio} -\setinterfaceconstant{css}{css} +\setinterfaceconstant{cssfile}{cssfile} \setinterfaceconstant{current}{corrente} \setinterfaceconstant{cutspace}{cutspace} \setinterfaceconstant{dash}{dash} diff --git a/tex/context/base/mult-nl.mkii b/tex/context/base/mult-nl.mkii index 881b4f467..771d48c3c 100644 --- a/tex/context/base/mult-nl.mkii +++ b/tex/context/base/mult-nl.mkii @@ -653,7 +653,7 @@ \setinterfaceconstant{coupling}{koppeling} \setinterfaceconstant{couplingway}{koppelwijze} \setinterfaceconstant{criterium}{criterium} -\setinterfaceconstant{css}{css} +\setinterfaceconstant{cssfile}{cssfile} \setinterfaceconstant{current}{huidige} \setinterfaceconstant{cutspace}{snijwit} \setinterfaceconstant{dash}{streep} diff --git a/tex/context/base/mult-pe.mkii b/tex/context/base/mult-pe.mkii index 076342282..7fa8bb772 100644 --- a/tex/context/base/mult-pe.mkii +++ b/tex/context/base/mult-pe.mkii @@ -653,7 +653,7 @@ \setinterfaceconstant{coupling}{تزویج} \setinterfaceconstant{couplingway}{روش‌تزویج} \setinterfaceconstant{criterium}{criterium} -\setinterfaceconstant{css}{css} +\setinterfaceconstant{cssfile}{cssfile} \setinterfaceconstant{current}{جاری} \setinterfaceconstant{cutspace}{فضای‌برش} \setinterfaceconstant{dash}{دش} diff --git a/tex/context/base/mult-ro.mkii b/tex/context/base/mult-ro.mkii index ec372c6ba..0ed0df4f1 100644 --- a/tex/context/base/mult-ro.mkii +++ b/tex/context/base/mult-ro.mkii @@ -653,7 +653,7 @@ \setinterfaceconstant{coupling}{cuplare} \setinterfaceconstant{couplingway}{modcuplare} \setinterfaceconstant{criterium}{criteriu} -\setinterfaceconstant{css}{css} +\setinterfaceconstant{cssfile}{cssfile} \setinterfaceconstant{current}{curent} \setinterfaceconstant{cutspace}{cutspace} \setinterfaceconstant{dash}{dash} diff --git a/tex/context/base/publ-dat.lua b/tex/context/base/publ-dat.lua index f35ae2fa9..20f545d8b 100644 --- a/tex/context/base/publ-dat.lua +++ b/tex/context/base/publ-dat.lua @@ -322,7 +322,7 @@ local value = Cs((somevalue * ((spacing * hash * spacing)/"" * somevalue)^0 local forget = percent^1 * (1-lineending)^0 local spacing = spacing * forget^0 * spacing local assignment = spacing * key * spacing * equal * spacing * value * spacing -local shortcut = P("@") * (P("string") + P("STRING")) * spacing * left * ((assignment * Carg(1))/do_shortcut * comma^0)^0 * spacing * right +local shortcut = P("@") * (P("string") + P("STRING") + P("String")) * spacing * left * ((assignment * Carg(1))/do_shortcut * comma^0)^0 * spacing * right local definition = category * spacing * left * spacing * tag * spacing * comma * Ct((assignment * comma^0)^0) * spacing * right * Carg(1) / do_definition local comment = keyword * spacing * left * (1-right)^0 * spacing * right diff --git a/tex/context/base/publ-imp-apa.mkvi b/tex/context/base/publ-imp-apa.mkvi index 38ea0c74f..8732e782e 100644 --- a/tex/context/base/publ-imp-apa.mkvi +++ b/tex/context/base/publ-imp-apa.mkvi @@ -21,6 +21,20 @@ \startbtxrenderingdefinitions[apa] +%D Reference: +%D \startTEX +%D @Book{APA2010, +%D title ={Publication Manual of the American Psychological Association}, +%D year ={2010}, +%D edition ={Sixth}, +%D address ={Washington, DC}, +%D publisher={American Psychological Association}, +%D pages ={291}, +%D url ={http://www.apa.org/books/}, +%D } +%D \stopTEX + + %D In order to get journals expanded (or normalized or abbreviated) you need to load %D a list: %D @@ -35,22 +49,30 @@ [en] [apa:mastersthesis={Master's thesis}, apa:phdthesis={PhD thesis}, - apa:technicalreport={Technical report}, + apa:technicalreport={Tech. Rep.}, % Technical report + apa:supplement={Suppl.}, % Supplement apa:patent=patent, - apa:editor=editor, - apa:editors=editors, - apa:edition=edition, + apa:Translator={Trans.}, % Translator(s) + apa:editor={Ed.}, % editor + apa:editors={Eds.}, % editors + apa:edition={ed.}, % edition apa:volume=volume, - apa:Volume=Volume, + apa:Volume={Vol.}, % Volume + apa:Volumes={Vols.}, % Volumes apa:number=number, - apa:Number=Number, + apa:Number={No.}, % Number + apa:nd={n.d.}, % no date apa:in=in, apa:of=of, apa:In=In, + apa:Part={Pt.}, % Part apa:p=p, apa:pp=pp, apa:pages=pages, apa:and=and, + apa:Author=Author, % TODO, should be typeset in italic... + apa:Advanced={Advanced online publication}, + apa:Retrieved={Retrieved from}, apa:others={et al.}] \setupbtxlabeltext @@ -59,8 +81,8 @@ apa:phdthesis={Thèse de doctorat}, apa:technicalreport={Rapport technique}, apa:patent=brevet, - apa:editor=éditeur, - apa:editors=éditeurs, + apa:editor={Éd.}, % éditeur + apa:editors={Éds.}, % éditeurs apa:edition=édition, apa:volume=volume, apa:Volume=Volume, @@ -73,6 +95,9 @@ apa:pp=pp, apa:pages=pages, apa:and=et, + apa:Author=Auteur, + apa:Advanced={Publication en ligne anticipée}, + apa:Retrieved={Téléchargé de}, apa:others={et al.}] \setupbtxlabeltext @@ -95,6 +120,9 @@ apa:pp=S, apa:pages=Seiten, apa:and=und, + apa:Author=Autor, + apa:Advanced={Erweiterte Online-Publikation}, % Check this German! + apa:Retrieved={aus abgerufen}, % heruntergeladen? Check this German! apa:others={et al.}] %D The variables control the shared code for which we use a tex definition with @@ -123,39 +151,35 @@ otherwise=\btxperiod] \starttexdefinition btx:apa:wherefrom #field +% TODO: for publisher, if =author use "Author" \btxdoifelse {address} { - \getvariable{btx:apa:\currentbtxcategory}{left} - \btxdoifelse {country} { - \btxflush{address} + \btxspace + \btxflush{address} + \btxdoif {country} { \btxcomma \btxflush{country} - \btxdoif {#field} { - \btxcolon - \btxflush{field} - } - } { - \btxflush{address} - \btxdoif {#field} { - \btxcomma - \btxflush{#field} - } } - \getvariable{btx:apa:\currentbtxcategory}{right} + \btxdoif {#field} { + \btxcolon + \btxflush{#field} + } + \btxperiod } { \btxdoifelse {country} { - \getvariable{btx:apa:\currentbtxcategory}{left} + \btxspace \btxflush{country} \btxdoif {#field} { \btxcolon \btxflush{#field} } - \getvariable{btx:apa:\currentbtxcategory}{right} + \btxperiod } { \btxdoifelse {#field} { \getvariable{btx:apa:#field}{left} \btxflush{#field} \getvariable{btx:apa:#field}{right} } { + % check that this is needed! \getvariable{btx:apa:#field}{otherwise} } } @@ -172,25 +196,27 @@ \starttexdefinition btx:apa:title-and-series \btxdoif {title} { - %btxflush{converters.Word -> title} + \btxspace \btxflush{Word -> title} \btxdoif {series} { - \btxlparent + \btxlparenthesis \btxflush{series} - \btxrparent + \btxrparenthesis } \btxperiod } \stoptexdefinition +% can these two be elegantly collapsed somehow using #it, for example? + \starttexdefinition btx:apa:title-it-and-series \btxdoif {title} { - %texdefinition{btx:apa:italic}{converters.Word -> title} + \btxspace \texdefinition{btx:apa:italic}{Word -> title} \btxdoif {series} { - \btxlparent + \btxlparenthesis \btxflush{series} - \btxrparent + \btxrparenthesis } \btxperiod } @@ -198,19 +224,22 @@ \disablemode[btx:apa:edited-book] % hm, ugly -\starttexdefinition btx:apa:author-and-year - \btxdoif {author} { - \btxflushauthor{author} - } +\starttexdefinition btx:apa:suffixedyear \btxdoif {year} { - \btxlparent - % \btxflush{suffixedyear} + \btxlparenthesis \btxflush{year} \btxdoif {suffix} { \btxflush{suffix} } - \btxrparent + \btxrparenthesis + } +\stoptexdefinition + +\starttexdefinition btx:apa:author-and-year + \btxdoif {author} { + \btxflushauthor{author} } + \texdefinition{btx:apa:suffixedyear} \btxperiod \stoptexdefinition @@ -224,22 +253,15 @@ \btxrbracket } } - \btxdoif {year} { - \btxlparent - % \btxflush{suffixedyear} - \btxflush{year} - \btxdoif {suffix} { - \btxflush{suffix} - } - \btxrparent - } + \texdefinition{btx:apa:suffixedyear} \btxperiod \stoptexdefinition \starttexdefinition btx:apa:author-editors-crossref-year - \btxdoif {author} { + % TODO: if there is no author or editor, then use publisher... + \btxdoifelse {author} { \btxflushauthor{author} - } { + } { \btxdoifelse {editor} { \setmode{btx:apa:edited-book} \btxflushauthor{editor} @@ -259,15 +281,7 @@ } } } - \btxdoif {year} { - \btxlparent - % \btxflush{suffixedyear} - \btxflush{year} - \btxdoif {suffix} { - \btxflush{suffix} - } - \btxrparent - } + \texdefinition{btx:apa:suffixedyear} \btxperiod \stoptexdefinition @@ -288,21 +302,58 @@ \btxrbracket } } - \btxspace - \btxdoif {year} { - \btxlparent - % \btxflush{suffixedyear} - \btxflush{year} - \btxdoif {suffix} { - \btxflush{suffix} + \texdefinition{btx:apa:suffixedyear} + \btxperiod +\stoptexdefinition + +% No longer used (not conforming to APA style) +\starttexdefinition btx:apa:title-it + \btxdoif {title} { + \btxspace + \texdefinition{btx:apa:italic}{Word -> title} + \btxflush{Word -> title} + \btxperiod + } +\stoptexdefinition + +\starttexdefinition btx:apa:journal-volume-issue + \btxdoifelse {journal} { + % expandedjournal abbreviatedjournal + \texdefinition{btx:apa:italic}{expandedjournal -> journal} + } { + \btxdoif {crossref} { + \btxlabeltext{apa:In} + \btxspace + \btxflush{crossref} + } + } + \btxdoifelse {volume} { + \btxspace + \texdefinition{btx:apa:italic}{volume} + \btxdoif {issue} { + \btxlparenthesis + \btxflush{issue} + \btxrparenthesis + } + \btxcomma + } { + \btxdoifelse {doi} { + \btxspace + \btxlabeltext{apa:Advanced} + \btxperiod + } { + \btxdoif {url} { + \btxspace + \btxlabeltext{apa:Advanced} + \btxperiod + } } - \btxrparent } - \btxperiod \stoptexdefinition \starttexdefinition btx:apa:note \btxdoif {note} { + % Note: no punctuation \btxspace \btxflush{note} \btxperiod @@ -311,18 +362,48 @@ \starttexdefinition btx:apa:comment \btxdoif {comment} { + % Note: no punctuation \btxspace \btxflush{comment} \btxperiod } \stoptexdefinition -\starttexdefinition btx:apa:pages:p +% if interaction, we should make these active hyperlinks! + +\starttexdefinition btx:apa:doi-or-url + \btxdoifelse {doi} { + \btxspace + \hyphenatedurl{doi:\btxflush{doi}} + } { + \btxdoif {url} { + \btxspace + \btxlabeltext{apa:Retrieved} + \btxspace + \hyphenatedurl{\btxflush{url}} + } + } +\stoptexdefinition + +\starttexdefinition btx:apa:pages \btxdoif {pages} { \btxspace \btxflush{pages} + \btxperiod + } +\stoptexdefinition + +\starttexdefinition btx:apa:pages:p + \btxdoif {pages} { \btxspace - \btxlabeltext{apa:p} + \btxoneorrange {pages} { + \btxlabeltext{apa:p} + } { + \btxlabeltext{apa:pp} + } + \btxperiod + \btxnbsp + \btxflush{pages} \btxperiod } \stoptexdefinition @@ -331,22 +412,25 @@ \btxdoif {pages} { \btxspace \btxflush{pages} - \btxspace + \btxnbsp \btxlabeltext{apa:pp} \btxperiod } \stoptexdefinition +% this does not seem to comply with APA style - need to verify! + \starttexdefinition btx:apa:pages:pages \btxdoif {pages} { \btxcomma \btxlabeltext{apa:pages} \btxnbsp \btxflush{pages} + \btxperiod } \stoptexdefinition -\starttexdefinition btx:apa:edition:sentense +\starttexdefinition btx:apa:edition:sentence \btxdoif {edition} { \btxspace \btxflush{edition} @@ -371,37 +455,10 @@ \startsetups btx:apa:article \texdefinition{btx:apa:author-or-key-and-year} - \btxdoif {title} { - %btxflush{converters.Word -> title} - \btxflush{Word -> title} - \btxperiod - } - \btxdoifelse {journal} { - % expandedjournal abbreviatedjournal - \texdefinition{btx:apa:italic}{expandedjournal -> journal} - } { - \btxdoif {crossref} { - \btxlabeltext{apa:In} - \btxspace - \btxflush{crossref} - } - } - \btxdoifelse {volume} { - \btxspace - \texdefinition{btx:apa:italic}{volume} - \btxdoif {issue} { - \btxlparent - \btxflush{issue} - \btxrparent - } - \btxdoif {pages} { - \btxcomma - \btxflush{pages} - } - \btxperiod - } { - \texdefinition{btx:apa:pages:pp} - } + \texdefinition{btx:apa:title} + \texdefinition{btx:apa:journal-volume-issue} + \texdefinition{btx:apa:pages} + \texdefinition{btx:apa:doi-or-url} \texdefinition{btx:apa:note} \texdefinition{btx:apa:comment} \stopsetups @@ -481,7 +538,8 @@ } \texdefinition{btx:apa:edition:sentence} \texdefinition{btx:apa:wherefrom}{publisher} - \texdefinition{btx:apa:pages:p}% twice? + \texdefinition{btx:apa:pages:pp}% twice? + \texdefinition{btx:apa:doi-or-url} \texdefinition{btx:apa:note} \stopsetups @@ -775,6 +833,7 @@ \btxcomma \texdefinition{btx:apa:wherefrom}{institution} \texdefinition{btx:apa:pages:p} + \texdefinition{btx:apa:doi-or-url} \texdefinition{btx:apa:note} \stopsetups @@ -812,7 +871,7 @@ \texdefinition{btx:apa:title-and-series} \texdefinition{btx:apa:pages:p} \btxdoif {type} { - \btxlparent + \btxlparenthesis \btxflush{type} \btxrparent } diff --git a/tex/context/base/publ-ini.lua b/tex/context/base/publ-ini.lua index 63da84576..018126573 100644 --- a/tex/context/base/publ-ini.lua +++ b/tex/context/base/publ-ini.lua @@ -134,7 +134,11 @@ statistics.register("publications load time", function() local nofbytes = publicationsstats.nofbytes if nofbytes > 0 then return string.format("%s seconds, %s bytes, %s definitions, %s shortcuts", - statistics.elapsedtime(publications),nofbytes,publicationsstats.nofdefinitions,publicationsstats.nofshortcuts) + statistics.elapsedtime(publications), + nofbytes, + publicationsstats.nofdefinitions or 0, + publicationsstats.nofshortcuts or 0 + ) else return nil end @@ -562,7 +566,7 @@ function commands.oneorrange(dataset,tag,name) commands.doifelse(not d) -- so singular is default end -function commands.firstinrange(dataset,tag,name) +function commands.firstofrange(dataset,tag,name) local d = datasets[dataset].luadata[tag] -- details ? if d then d = d[name] diff --git a/tex/context/base/publ-ini.mkiv b/tex/context/base/publ-ini.mkiv index 46fe46543..161934384 100644 --- a/tex/context/base/publ-ini.mkiv +++ b/tex/context/base/publ-ini.mkiv @@ -229,6 +229,7 @@ \definebtxdataset [\v!standard] +% [\c!language=] % nothing set so use current % \usebtxdataset % [standard] @@ -346,8 +347,10 @@ \unexpanded\def\btxcomma {\removeunwantedspaces,\space} \unexpanded\def\btxcolon {\removeunwantedspaces:\space} \unexpanded\def\btxsemicolon {\removeunwantedspaces;\space} -\unexpanded\def\btxlparent {\removeunwantedspaces\space(} -\unexpanded\def\btxrparent {\removeunwantedspaces)\space} +\unexpanded\def\btxlparent {\removeunwantedspaces\space(} % obsolete +\unexpanded\def\btxrparent {\removeunwantedspaces)\space} % obsolete +\unexpanded\def\btxlparenthesis{\removeunwantedspaces\space(} +\unexpanded\def\btxrparenthesis{\removeunwantedspaces)\space} \unexpanded\def\btxlbracket {\removeunwantedspaces\space[} \unexpanded\def\btxrbracket {\removeunwantedspaces]\space} @@ -589,6 +592,7 @@ % \determinelistcharacteristics[\currentbtxrendering]% \btx_set_rendering_alternative \edef\currentbtxdataset{\btxrenderingparameter\c!dataset}% + \uselanguageparameter\btxdatasetparameter % new \let\currentlist\s!btx \let\currentbtxlist\currentbtxrendering \the\everysetupbtxlistplacement @@ -984,6 +988,7 @@ \def\publ_cite_handle_variant_indeed[#1]% {\usebtxcitevariantstyleandcolor\c!style\c!color + \uselanguageparameter\btxdatasetparameter % new \letbtxcitevariantparameter\c!alternative\currentbtxcitevariant \btxcitevariantparameter\v!left \ctxcommand{btxhandlecite{% @@ -1060,8 +1065,8 @@ %D Whatever helpers: \unexpanded\def\btxsingularplural#1{\ctxcommand{btxsingularorplural("\currentbtxdataset","\currentbtxtag","#1")}} -\unexpanded\def\btxoneorrange #1{\ctxcommand{btxoneorrange("\currentbtxdataset","\currentbtxtag","#1")}} -\unexpanded\def\btxfirstofrange #1{\ctxcommand{btxfirstofrange("\currentbtxdataset","\currentbtxtag","#1")}} +\unexpanded\def\btxoneorrange #1{\ctxcommand{oneorrange("\currentbtxdataset","\currentbtxtag","#1")}} +\unexpanded\def\btxfirstofrange #1{\ctxcommand{firstofrange("\currentbtxdataset","\currentbtxtag","#1")}} \let\btxsingularorplural\btxsingularplural diff --git a/tex/context/base/scrp-ini.lua b/tex/context/base/scrp-ini.lua index a6bfe4cf9..fa2bc771f 100644 --- a/tex/context/base/scrp-ini.lua +++ b/tex/context/base/scrp-ini.lua @@ -475,18 +475,19 @@ function scripts.injectors.handler(head) normal_process = handler.injector end if normal_process then + -- wrong: originals are indices ! local f = getfont(start) if f ~= lastfont then originals = fontdata[f].resources if resources then originals = resources.originals else - -- can't happen + originals = nil -- can't happen end lastfont = f end local c = getchar(start) - if originals then + if originals and type(originals) == "number" then c = originals[c] or c end local h = hash[c] diff --git a/tex/context/base/status-files.pdf b/tex/context/base/status-files.pdf index 540ac5255..5da0e7556 100644 Binary files a/tex/context/base/status-files.pdf and b/tex/context/base/status-files.pdf differ diff --git a/tex/context/base/status-lua.pdf b/tex/context/base/status-lua.pdf index 0b92a158c..09c5ba3ad 100644 Binary files a/tex/context/base/status-lua.pdf and b/tex/context/base/status-lua.pdf differ diff --git a/tex/context/base/strc-bkm.lua b/tex/context/base/strc-bkm.lua index c38ab3c2e..848fe8b93 100644 --- a/tex/context/base/strc-bkm.lua +++ b/tex/context/base/strc-bkm.lua @@ -13,7 +13,9 @@ if not modules then modules = { } end modules ['strc-bkm'] = { -- we should hook the placement into everystoptext ... needs checking -local format, concat, gsub = string.format, table.concat, string.gsub +-- todo: make an lpeg for stripped + +local format, concat, gsub, lower = string.format, table.concat, string.gsub, string.lower local utfvalues = utf.values local settings_to_hash = utilities.parsers.settings_to_hash @@ -101,54 +103,6 @@ function bookmarks.setup(spec) end end --- function bookmarks.place() --- if next(names) then --- local list = lists.filtercollected(names,"all",nil,lists.collected,forced) --- if #list > 0 then --- local levels, noflevels, lastlevel = { }, 0, 1 --- for i=1,#list do --- local li = list[i] --- local metadata = li.metadata --- local name = metadata.name --- if not metadata.nolist or forced[name] then -- and levelmap[name] then --- local titledata = li.titledata --- if titledata then --- local structural = levelmap[name] --- lastlevel = structural or lastlevel --- local title = titledata.bookmark --- if not title or title == "" then --- -- We could typeset the title and then convert it. --- if not structural then --- -- placeholder, todo: bookmarklabel --- title = name .. ": " .. (titledata.title or "?") --- else --- title = titledata.title or "?" --- end --- end --- if numbered[name] then --- local sectiondata = sections.collected[li.references.section] --- local numberdata = li.numberdata --- if sectiondata and numberdata and not numberdata.hidenumber then --- -- we could typeset the number and convert it --- title = concat(sections.typesetnumber(sectiondata,"direct",numberspec,sectiondata)) .. " " .. title --- end --- end --- noflevels = noflevels + 1 --- levels[noflevels] = { --- lastlevel, --- stripped(title), -- can be replaced by converter --- li.references, -- has internal and realpage --- allopen or opened[name] --- } --- end --- end --- end --- bookmarks.finalize(levels) --- end --- function bookmarks.place() end -- prevent second run --- end --- end - function bookmarks.place() if next(names) then local levels = { } @@ -172,11 +126,14 @@ function bookmarks.place() -- add block entry local blockdata = sections.sectionblockdata[block] noflevels = noflevels + 1 + local references = li.references levels[noflevels] = { - 1, -- toplevel - stripped(blockdata.bookmark ~= "" and blockdata.bookmark or block), - li.references, - allopen or opened[name] -- same as first entry + level = 1, -- toplevel + title = stripped(blockdata.bookmark ~= "" and blockdata.bookmark or block), + reference = references, + opened = allopen or opened[name], -- same as first entry + realpage = references and references.realpage or 0, -- handy for later + usedpage = true, } end blockdone = true @@ -206,11 +163,14 @@ function bookmarks.place() end end noflevels = noflevels + 1 + local references = li.references levels[noflevels] = { - lastlevel, - stripped(title), -- can be replaced by converter - li.references, -- has internal and realpage - allopen or opened[name] + level = lastlevel, + title = stripped(title), -- can be replaced by converter + reference = references, -- has internal and realpage + opened = allopen or opened[name], + realpage = references and references.realpage or 0, -- handy for later + usedpage = true, } end end @@ -222,43 +182,238 @@ function bookmarks.place() end function bookmarks.flatten(levels) + if not levels then + -- a plugin messed up + return { } + end -- This function promotes leading structurelements with a higher level -- to the next lower level. Such situations are the result of lack of -- structure: a subject preceding a chapter in a sectionblock. So, the -- following code runs over section blocks as well. (bookmarks-007.tex) local noflevels = #levels if noflevels > 1 then - local skip, start, one = false, 1, levels[1] - local first, block = one[1], one[3].block + local skip = false + local start = 1 + local one = levels[1] + local first = one.level + local block = one.reference.block for i=2,noflevels do - local li = levels[i] - local new, newblock = li[1], li[3].block + local current = levels[i] + local new = current.level + local reference = current.reference + local newblock = type(reference) == "table" and current.reference.block or block if newblock ~= block then - first, block, start, skip = new, newblock, i, false + first = new + block = newblock + start = i + skip = false elseif skip then -- go on elseif new > first then skip = true elseif new < first then for j=start,i-1 do - local lj = levels[j] - local old = lj[1] - lj[1] = new + local previous = levels[j] + local old = previous.level + previous.level = new if trace_bookmarks then - report_bookmarks("promoting entry %a from level %a to %a: %s",j,old,new,lj[2]) + report_bookmarks("promoting entry %a from level %a to %a: %s",j,old,new,previous.title) end end skip = true end end end + return levels +end + +local extras = { } +local lists = { } +local names = { } + +bookmarks.extras = extras + +local function cleanname(name) + return lower(file.basename(name)) +end + +function extras.register(name,levels) + if name and levels then + name = cleanname(name) + local found = names[name] + if found then + lists[found].levels = levels + else + lists[#lists+1] = { + name = name, + levels = levels, + } + names[name] = #lists + end + end +end + +function extras.get(name) + if name then + local found = names[cleanname(name)] + if found then + return lists[found].levels + end + else + return lists + end +end + +function extras.reset(name) + local l, n = { }, { } + if name then + name = cleanname(name) + for i=1,#lists do + local li = lists[i] + local ln = li.name + if name == ln then + -- skip + else + local m = #l + 1 + l[m] = li + n[ln] = m + end + end + end + lists, names = l, n +end + +local function checklists() + for i=1,#lists do + local levels = lists[i].levels + for j=1,#levels do + local entry = levels[j] + local pageindex = entry.pageindex + if pageindex then + entry.reference = figures.getrealpage(pageindex) + entry.pageindex = nil + end + end + end +end + +function extras.tosections(levels) + local sections = { } + local noflists = #lists + for i=1,noflists do + local levels = lists[i].levels + local data = { } + sections[i] = data + for j=1,#levels do + local entry = levels[j] + if entry.usedpage then + local section = entry.section + local d = data[section] + if d then + d[#d+1] = entry + else + data[section] = { entry } + end + end + end + end + return sections +end + +function extras.mergesections(levels,sections) + if not sections or #sections == 0 then + return levels + elseif not levels then + return { } + else + local merge = { } + local noflists = #lists + if #levels == 0 then + local level = 0 + local section = 0 + for i=1,noflists do + local entries = sections[i][0] + if entries then + for i=1,#entries do + local entry = entries[i] + merge[#merge+1] = entry + entry.level = entry.level + level + end + end + end + else + for j=1,#levels do + local entry = levels[j] + merge[#merge+1] = entry + local section = entry.reference.section + local level = entry.level + entry.section = section -- for tracing + for i=1,noflists do + local entries = sections[i][section] + if entries then + for i=1,#entries do + local entry = entries[i] + merge[#merge+1] = entry + entry.level = entry.level + level + end + end + end + end + end + return merge + end +end + +function bookmarks.merge(levels,mode) + return extras.mergesections(levels,extras.tosections()) end +local sequencers = utilities.sequencers +local appendgroup = sequencers.appendgroup +local appendaction = sequencers.appendaction + +local bookmarkactions = sequencers.new { + arguments = "levels,method", + returnvalues = "levels", + results = "levels", +} + +appendgroup(bookmarkactions,"before") -- user +appendgroup(bookmarkactions,"system") -- private +appendgroup(bookmarkactions,"after" ) -- user + +appendaction(bookmarkactions,"system",bookmarks.flatten) +appendaction(bookmarkactions,"system",bookmarks.merge) + function bookmarks.finalize(levels) - -- This function can be overloaded by an optional converter - -- that uses nodes.toutf on a typeset stream. This is something - -- that we will support when the main loop has become a coroutine. - codeinjections.addbookmarks(levels,bookmarks.method) + local method = bookmarks.method or "internal" + checklists() -- so that plugins have the adapted page number + levels = bookmarkactions.runner(levels,method) + if levels and #levels > 0 then + -- normally this is not needed + local purged = { } + for i=1,#levels do + local l = levels[i] + if l.usedpage ~= false then + purged[#purged+1] = l + end + end + -- + codeinjections.addbookmarks(purged,method) + else + -- maybe a plugin messed up + end +end + +function bookmarks.installhandler(what,where,func) + if not func then + where, func = "after", where + end + if where == "before" or where == "after" then + sequencers.appendaction(bookmarkactions,where,func) + else + report_tex("installing bookmark %a handlers in %a is not possible",what,tostring(where)) + end end -- interface diff --git a/tex/context/base/strc-doc.lua b/tex/context/base/strc-doc.lua index 38830a4e7..7d3be1620 100644 --- a/tex/context/base/strc-doc.lua +++ b/tex/context/base/strc-doc.lua @@ -136,20 +136,27 @@ function sections.currentid() return #tobesaved end +local lastsaved = 0 + function sections.save(sectiondata) -- local sectionnumber = helpers.simplify(section.sectiondata) -- maybe done earlier local numberdata = sectiondata.numberdata local ntobesaved = #tobesaved if not numberdata or sectiondata.metadata.nolist then - return ntobesaved + -- stay else ntobesaved = ntobesaved + 1 tobesaved[ntobesaved] = numberdata if not collected[ntobesaved] then collected[ntobesaved] = numberdata end - return ntobesaved end + lastsaved = ntobesaved + return ntobesaved +end + +function sections.currentsectionindex() + return lastsaved -- only for special controlled situations end function sections.load() diff --git a/tex/context/base/strc-ref.lua b/tex/context/base/strc-ref.lua index 8a2a668c0..fb1c98c32 100644 --- a/tex/context/base/strc-ref.lua +++ b/tex/context/base/strc-ref.lua @@ -2179,6 +2179,8 @@ local function setreferencerealpage(actions) end end +references.setreferencerealpage = setreferencerealpage + -- we store some analysis data alongside the indexed array -- at this moment only the real reference page is analyzed -- normally such an analysis happens in the backend code diff --git a/tex/context/base/syst-ini.mkiv b/tex/context/base/syst-ini.mkiv index ff74efecc..29a97b6bd 100644 --- a/tex/context/base/syst-ini.mkiv +++ b/tex/context/base/syst-ini.mkiv @@ -1020,7 +1020,7 @@ %D \PDFTEX, we default to \DVI. Why? \pdfoutput \zerocount -\pdfminorversion \plussix +\pdfminorversion \plusseven \pdfgentounicode \plusone \pdfinclusioncopyfonts \plusone \pdfinclusionerrorlevel \zerocount diff --git a/tex/context/base/typo-dig.lua b/tex/context/base/typo-dig.lua index 67849c6d4..f5b8a6ddd 100644 --- a/tex/context/base/typo-dig.lua +++ b/tex/context/base/typo-dig.lua @@ -103,15 +103,14 @@ end actions[1] = function(head,start,attr) local font = getfont(start) local char = getchar(start) - local unic = chardata[font][char].tounicode - local what = unic and tonumber(unic,16) or char - if charbase[what].category == "nd" then + local unic = chardata[font][char].unicode or char + if charbase[unic].category == "nd" then -- ignore unic tables local oldwidth = getfield(start,"width") local newwidth = getdigitwidth(font) if newwidth ~= oldwidth then if trace_digits then report_digits("digit trigger %a, instance %a, char %C, unicode %U, delta %s", - attr%100,div(attr,100),char,what,newwidth-oldwidth) + attr%100,div(attr,100),char,unic,newwidth-oldwidth) end head, start = nodes.aligned(head,start,start,newwidth,"middle") return head, start, true diff --git a/tex/context/base/typo-tal.lua b/tex/context/base/typo-tal.lua index 1e9c815b3..d41a63dd5 100644 --- a/tex/context/base/typo-tal.lua +++ b/tex/context/base/typo-tal.lua @@ -12,6 +12,8 @@ if not modules then modules = { } end modules ['typo-tal'] = { -- Currently we have two methods: text and number with some downward compatible -- defaulting. +-- We can speed up by saving the current fontcharacters[font] + lastfont. + local next, type = next, type local div = math.div local utfbyte = utf.byte @@ -23,7 +25,7 @@ local glyph_code = nodecodes.glyph local glue_code = nodecodes.glue local fontcharacters = fonts.hashes.characters -local unicodes = fonts.hashes.unicodes +----- unicodes = fonts.hashes.unicodes local categories = characters.categories -- nd local variables = interfaces.variables @@ -135,7 +137,8 @@ function characteralign.handler(originalhead,where) if id == glyph_code then local char = getchar(current) local font = getfont(current) - local unicode = unicodes[font][char] + -- local unicode = unicodes[font][char] + local unicode = fontcharacters[font][char].unicode or char -- ignore tables if not unicode then -- no unicode so forget about it elseif unicode == separator then @@ -213,7 +216,8 @@ function characteralign.handler(originalhead,where) if id == glyph_code then local char = getchar(current) local font = getfont(current) - local unicode = unicodes[font][char] + -- local unicode = unicodes[font][char] + local unicode = fontcharacters[font][char].unicode or char -- ignore tables if not unicode then -- no unicode so forget about it elseif unicode == separator then diff --git a/tex/context/base/util-tpl.lua b/tex/context/base/util-tpl.lua index 67d058221..bd0e261a9 100644 --- a/tex/context/base/util-tpl.lua +++ b/tex/context/base/util-tpl.lua @@ -52,7 +52,7 @@ local sqlescape = lpeg.replacer { -- { "\t", "\\t" }, } -local sqlquoted = lpeg.Cs(lpeg.Cc("'") * sqlescape * lpeg.Cc("'")) +local sqlquoted = Cs(Cc("'") * sqlescape * Cc("'")) lpegpatterns.sqlescape = sqlescape lpegpatterns.sqlquoted = sqlquoted @@ -111,13 +111,21 @@ local luaescaper = escapers.lua local quotedluaescaper = quotedescapers.lua local function replacekeyunquoted(s,t,how,recurse) -- ".. \" " - local escaper = how and escapers[how] or luaescaper - return escaper(replacekey(s,t,how,recurse)) + if how == false then + return replacekey(s,t,how,recurse) + else + local escaper = how and escapers[how] or luaescaper + return escaper(replacekey(s,t,how,recurse)) + end end local function replacekeyquoted(s,t,how,recurse) -- ".. \" " - local escaper = how and quotedescapers[how] or quotedluaescaper - return escaper(replacekey(s,t,how,recurse)) + if how == false then + return replacekey(s,t,how,recurse) + else + local escaper = how and quotedescapers[how] or quotedluaescaper + return escaper(replacekey(s,t,how,recurse)) + end end local single = P("%") -- test %test% test : resolves test @@ -188,3 +196,5 @@ end -- inspect(utilities.templates.replace("test %one% test", { one = "%two%", two = "two" })) -- inspect(utilities.templates.resolve({ one = "%two%", two = "two", three = "%three%" })) +-- inspect(utilities.templates.replace("test %one% test", { one = "%two%", two = "two" },false,true)) +-- inspect(utilities.templates.replace("test %one% test", { one = "%two%", two = "two" },false)) diff --git a/tex/context/fonts/treatments.lfg b/tex/context/fonts/treatments.lfg index 07bb51def..40bac427c 100644 --- a/tex/context/fonts/treatments.lfg +++ b/tex/context/fonts/treatments.lfg @@ -25,50 +25,50 @@ local fix_unifraktur = { end, } -local fix_lmmonoregular = { - -- - -- there are now some extra safeguards for idris - -- - comment = "wrong widths of some glyphs", - fixes = function(data) - report("fixing some wrong widths") - local unicodes = data.resources.unicodes - local descriptions = data.descriptions - local function getdescription(name) - local unicode = unicodes[name] - if not unicode then - report("no valid unicode for %a",name) - return - end - local description = descriptions[unicode] - if not description then - report("no glyph names %a in font",name) - return - end - return description - end - local zero = getdescription("zero") - if not zero then - return - end - local defaultwidth = zero.width - local function setwidth(name) - local data = getdescription(name) - if data then - data.width = defaultwidth - end - end - setwidth("six") - setwidth("nine") - setwidth("caron") - setwidth("perthousand") - setwidth("numero") - setwidth("caron.cap") - setwidth("six.taboldstyle") - setwidth("nine.taboldstyle") - setwidth("dollar.oldstyle") - end -} +-- local fix_lmmonoregular = { +-- -- +-- -- there are now some extra safeguards for idris +-- -- +-- comment = "wrong widths of some glyphs", +-- fixes = function(data) +-- report("fixing some wrong widths") +-- local unicodes = data.resources.unicodes +-- local descriptions = data.descriptions +-- local function getdescription(name) +-- local unicode = unicodes[name] +-- if not unicode then +-- report("no valid unicode for %a",name) +-- return +-- end +-- local description = descriptions[unicode] +-- if not description then +-- report("no glyph names %a in font",name) +-- return +-- end +-- return description +-- end +-- local zero = getdescription("zero") +-- if not zero then +-- return +-- end +-- local defaultwidth = zero.width +-- local function setwidth(name) +-- local data = getdescription(name) +-- if data then +-- data.width = defaultwidth +-- end +-- end +-- setwidth("six") +-- setwidth("nine") +-- setwidth("caron") +-- setwidth("perthousand") +-- setwidth("numero") +-- setwidth("caron.cap") +-- setwidth("six.taboldstyle") +-- setwidth("nine.taboldstyle") +-- setwidth("dollar.oldstyle") +-- end +-- } return { name = "treatments", diff --git a/tex/context/interface/keys-cs.xml b/tex/context/interface/keys-cs.xml index e32918566..b261a74e4 100644 --- a/tex/context/interface/keys-cs.xml +++ b/tex/context/interface/keys-cs.xml @@ -659,7 +659,7 @@ - + diff --git a/tex/context/interface/keys-de.xml b/tex/context/interface/keys-de.xml index 48329fabf..b9f6c400b 100644 --- a/tex/context/interface/keys-de.xml +++ b/tex/context/interface/keys-de.xml @@ -659,7 +659,7 @@ - + diff --git a/tex/context/interface/keys-en.xml b/tex/context/interface/keys-en.xml index dd8de7312..50e15c05b 100644 --- a/tex/context/interface/keys-en.xml +++ b/tex/context/interface/keys-en.xml @@ -659,7 +659,7 @@ - + diff --git a/tex/context/interface/keys-fr.xml b/tex/context/interface/keys-fr.xml index 4a9f2b78b..15ebc93c6 100644 --- a/tex/context/interface/keys-fr.xml +++ b/tex/context/interface/keys-fr.xml @@ -659,7 +659,7 @@ - + diff --git a/tex/context/interface/keys-it.xml b/tex/context/interface/keys-it.xml index ce1be9a61..e256c965b 100644 --- a/tex/context/interface/keys-it.xml +++ b/tex/context/interface/keys-it.xml @@ -659,7 +659,7 @@ - + diff --git a/tex/context/interface/keys-nl.xml b/tex/context/interface/keys-nl.xml index bdcf2a96a..eebc048c0 100644 --- a/tex/context/interface/keys-nl.xml +++ b/tex/context/interface/keys-nl.xml @@ -659,7 +659,7 @@ - + diff --git a/tex/context/interface/keys-pe.xml b/tex/context/interface/keys-pe.xml index 77b137293..926cb4f1e 100644 --- a/tex/context/interface/keys-pe.xml +++ b/tex/context/interface/keys-pe.xml @@ -659,7 +659,7 @@ - + diff --git a/tex/context/interface/keys-ro.xml b/tex/context/interface/keys-ro.xml index ad07ea880..f07634521 100644 --- a/tex/context/interface/keys-ro.xml +++ b/tex/context/interface/keys-ro.xml @@ -659,7 +659,7 @@ - + diff --git a/tex/generic/context/luatex/luatex-basics-gen.lua b/tex/generic/context/luatex/luatex-basics-gen.lua index c19a49af3..e7cdc7b39 100644 --- a/tex/generic/context/luatex/luatex-basics-gen.lua +++ b/tex/generic/context/luatex/luatex-basics-gen.lua @@ -351,7 +351,12 @@ end -- function table.setmetatableindex(t,f) + if type(t) ~= "table" then + f = f or t + t = { } + end setmetatable(t,{ __index = f }) + return t end -- helper for plain: diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index 98e98d806..42f85340e 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 : luatex-fonts-merged.lua -- parent file : luatex-fonts.lua --- merge date : 09/27/14 14:46:07 +-- merge date : 10/02/14 23:07:34 do -- begin closure to overcome local limits and interference @@ -895,7 +895,7 @@ local function compare(a,b) if ta==tb then return a=private or (unic>=0xE000 and unic<=0xF8FF) or unic==0xFFFE or unic==0xFFFF then local unicode=lumunic and lumunic[name] or unicodevector[name] if unicode then - originals[index]=unicode - tounicode[index]=tounicode16(unicode,name) + glyph.unicode=unicode ns=ns+1 end if (not unicode) and usedmap then @@ -5283,8 +5303,7 @@ function mappings.addtounicode(data,filename) if foundindex then unicode=cidcodes[foundindex] if unicode then - originals[index]=unicode - tounicode[index]=tounicode16(unicode,name) + glyph.unicode=unicode ns=ns+1 else local reference=cidnames[foundindex] @@ -5293,21 +5312,18 @@ function mappings.addtounicode(data,filename) if foundindex then unicode=cidcodes[foundindex] if unicode then - originals[index]=unicode - tounicode[index]=tounicode16(unicode,name) + glyph.unicode=unicode ns=ns+1 end end if not unicode or unicode=="" then local foundcodes,multiple=lpegmatch(uparser,reference) if foundcodes then - originals[index]=foundcodes + glyph.unicode=foundcodes if multiple then - tounicode[index]=tounicode16sequence(foundcodes) nl=nl+1 unicode=true else - tounicode[index]=tounicode16(foundcodes,name) ns=ns+1 unicode=foundcodes end @@ -5345,25 +5361,20 @@ function mappings.addtounicode(data,filename) end if n==0 then elseif n==1 then - originals[index]=t[1] - tounicode[index]=tounicode16(t[1],name) + glyph.unicode=t[1] else - originals[index]=t - tounicode[index]=tounicode16sequence(t) + glyph.unicode=t end nl=nl+1 end if not unicode or unicode=="" then local foundcodes,multiple=lpegmatch(uparser,name) if foundcodes then + glyph.unicode=foundcodes if multiple then - originals[index]=foundcodes - tounicode[index]=tounicode16sequence(foundcodes,name) nl=nl+1 unicode=true else - originals[index]=foundcodes - tounicode[index]=tounicode16(foundcodes,name) ns=ns+1 unicode=foundcodes end @@ -5387,8 +5398,7 @@ function mappings.addtounicode(data,filename) else return end - local index=descriptions[code].index - if tounicode[index] then + if descriptions[code].unicode then return end local g=guess[variant] @@ -5453,37 +5463,31 @@ function mappings.addtounicode(data,filename) end end end + local orphans=0 + local guessed=0 for k,v in next,guess do if type(v)=="number" then - guess[k]=tounicode16(v) + descriptions[unicodes[k]].unicode=descriptions[v].unicode or v + guessed=guessed+1 else local t=nil local l=lower(k) local u=unicodes[l] if not u then + orphans=orphans+1 elseif u==-1 or u>=private or (u>=0xE000 and u<=0xF8FF) or u==0xFFFE or u==0xFFFF then - t=tounicode[descriptions[u].index] - else - end - if t then - guess[k]=t + local unicode=descriptions[u].unicode + if unicode then + descriptions[unicodes[k]].unicode=unicode + guessed=guessed+1 + else + orphans=orphans+1 + end else - guess[k]="FFFD" + orphans=orphans+1 end end end - local orphans=0 - local guessed=0 - for k,v in next,guess do - tounicode[descriptions[unicodes[k]].index]=v - if v=="FFFD" then - orphans=orphans+1 - guess[k]=false - else - guessed=guessed+1 - guess[k]=true - end - end if trace_loading and orphans>0 or guessed>0 then report_fonts("%s glyphs with no related unicode, %s guessed, %s orphans",guessed+orphans,guessed,orphans) end @@ -5492,9 +5496,17 @@ function mappings.addtounicode(data,filename) for unic,glyph in table.sortedhash(descriptions) do local name=glyph.name local index=glyph.index - local toun=tounicode[index] - if toun then - report_fonts("internal slot %U, name %a, unicode %U, tounicode %a",index,name,unic,toun) + local unicode=glyph.unicode + if unicode then + if type(unicode)=="table" then + local unicodes={} + for i=1,#unicode do + unicodes[i]=formatters("%U",unicode[i]) + end + report_fonts("internal slot %U, name %a, unicode %U, tounicode % t",index,name,unic,unicodes) + else + report_fonts("internal slot %U, name %a, unicode %U, tounicode %U",index,name,unic,unicode) + end else report_fonts("internal slot %U, name %a, unicode %U",index,name,unic) end @@ -5675,6 +5687,10 @@ local function read_from_tfm(specification) features.encoding=encoding end end + properties.haskerns=true + properties.haslogatures=true + resources.unicodes={} + resources.lookuptags={} return tfmdata end end @@ -5730,6 +5746,7 @@ local trace_indexing=false trackers.register("afm.indexing",function(v) trace_in local trace_loading=false trackers.register("afm.loading",function(v) trace_loading=v end) local trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end) local report_afm=logs.reporter("fonts","afm loading") +local setmetatableindex=table.setmetatableindex local findbinfile=resolvers.findbinfile local definers=fonts.definers local readers=fonts.readers @@ -5738,7 +5755,7 @@ local afm=constructors.newhandler("afm") local pfb=constructors.newhandler("pfb") local afmfeatures=constructors.newfeatures("afm") local registerafmfeature=afmfeatures.register -afm.version=1.410 +afm.version=1.500 afm.cache=containers.define("fonts","afm",afm.version,true) afm.autoprefixed=true afm.helpdata={} @@ -5760,6 +5777,15 @@ registerafmfeature { node=setmode, } } +local remappednames={ + ff={ name="f_f",unicode={ 0x66,0x66 } }, + fi={ name="f_i",unicode={ 0x66,0x69 } }, + fj={ name="f_j",unicode={ 0x66,0x6A } }, + fk={ name="f_k",unicode={ 0x66,0x6B } }, + fl={ name="f_l",unicode={ 0x66,0x6C } }, + ffi={ name="f_f_i",unicode={ 0x66,0x66,0x69 } }, + ffl={ name="f_f_l",unicode={ 0x66,0x66,0x6C } }, +} local comment=P("Comment") local spacing=patterns.spacer local lineend=patterns.newline @@ -5933,7 +5959,7 @@ local function readafm(filename) return nil end end -local addkerns,addligatures,addtexligatures,unify,normalize +local addkerns,addligatures,addtexligatures,unify,normalize,fixnames function afm.load(filename) filename=resolvers.findfile(filename,'afm') or "" if filename~="" and not fonts.names.ignoredfile(filename) then @@ -5976,6 +6002,7 @@ function afm.load(filename) addkerns(data) end normalize(data) + fixnames(data) report_afm("add tounicode data") fonts.mappings.addtounicode(data,filename) data.size=size @@ -5983,6 +6010,7 @@ function afm.load(filename) data.pfbsize=pfbsize data.pfbtime=pfbtime report_afm("saving %a in cache",name) + data.resources.unicodes=nil data=containers.write(afm.cache,name,data) data=containers.read(afm.cache,name) end @@ -6042,18 +6070,29 @@ unify=function(data,filename) local filename=resources.filename or file.removesuffix(file.basename(filename)) resources.filename=resolvers.unresolve(filename) resources.unicodes=unicodes - resources.marks={} - resources.names=names + resources.marks={} resources.private=private end normalize=function(data) end +fixnames=function(data) + for k,v in next,data.descriptions do + local n=v.name + local r=remappednames[n] + if r then + if trace_indexing then + report_afm("renaming characters %a to %a",n,r.name) + end + v.name=r.name + v.unicode=r.unicode + end + end +end local addthem=function(rawdata,ligatures) if ligatures then local descriptions=rawdata.descriptions local resources=rawdata.resources local unicodes=resources.unicodes - local names=resources.names for ligname,ligdata in next,ligatures do local one=descriptions[unicodes[ligname]] if one then @@ -6186,8 +6225,8 @@ local function copytotfm(data) local filename=constructors.checkedfilename(resources) local fontname=metadata.fontname or metadata.fullname local fullname=metadata.fullname or metadata.fontname - local endash=unicodes['space'] - local emdash=unicodes['emdash'] + local endash=0x0020 + local emdash=0x2014 local spacer="space" local spaceunits=500 local monospaced=metadata.isfixedpitch @@ -6241,7 +6280,7 @@ local function copytotfm(data) if charxheight then parameters.x_height=charxheight else - local x=unicodes['x'] + local x=0x0078 if x then local x=descriptions[x] if x then @@ -6288,7 +6327,34 @@ function afm.setfeatures(tfmdata,features) return {} end end -local function checkfeatures(specification) +local function addtables(data) + local resources=data.resources + local lookuptags=resources.lookuptags + local unicodes=resources.unicodes + if not lookuptags then + lookuptags={} + resources.lookuptags=lookuptags + end + setmetatableindex(lookuptags,function(t,k) + local v=type(k)=="number" and ("lookup "..k) or k + t[k]=v + return v + end) + if not unicodes then + unicodes={} + resources.unicodes=unicodes + setmetatableindex(unicodes,function(t,k) + setmetatableindex(unicodes,nil) + for u,d in next,data.descriptions do + local n=d.name + if n then + t[n]=u + end + end + return rawget(t,k) + end) + end + constructors.addcoreunicodes(unicodes) end local function afmtotfm(specification) local afmname=specification.filename or specification.name @@ -6315,6 +6381,7 @@ local function afmtotfm(specification) if not tfmdata then local rawdata=afm.load(afmname) if rawdata and next(rawdata) then + addtables(rawdata) adddimensions(rawdata) tfmdata=copytotfm(rawdata) if tfmdata and next(tfmdata) then @@ -6349,6 +6416,7 @@ end local function prepareligatures(tfmdata,ligatures,value) if value then local descriptions=tfmdata.descriptions + local hasligatures=false for unicode,character in next,tfmdata.characters do local description=descriptions[unicode] local dligatures=description.ligatures @@ -6364,8 +6432,10 @@ local function prepareligatures(tfmdata,ligatures,value) type=0 } end + hasligatures=true end end + tfmdata.properties.hasligatures=hasligatures end end local function preparekerns(tfmdata,kerns,value) @@ -6374,6 +6444,7 @@ local function preparekerns(tfmdata,kerns,value) local resources=rawdata.resources local unicodes=resources.unicodes local descriptions=tfmdata.descriptions + local haskerns=false for u,chr in next,tfmdata.characters do local d=descriptions[u] local newkerns=d[kerns] @@ -6389,8 +6460,10 @@ local function preparekerns(tfmdata,kerns,value) kerns[uk]=v end end + haskerns=true end end + tfmdata.properties.haskerns=haskerns end end local list={ @@ -6820,6 +6893,8 @@ local reversed,concat,remove,sortedkeys=table.reversed,table.concat,table.remove local ioflush=io.flush local fastcopy,tohash,derivetable=table.fastcopy,table.tohash,table.derive local formatters=string.formatters +local P,R,S,C,Ct,lpegmatch=lpeg.P,lpeg.R,lpeg.S,lpeg.C,lpeg.Ct,lpeg.match +local setmetatableindex=table.setmetatableindex local allocate=utilities.storage.allocate local registertracker=trackers.register local registerdirective=directives.register @@ -6834,26 +6909,27 @@ local trace_dynamics=false registertracker("otf.dynamics",function(v) trace_dyna local trace_sequences=false registertracker("otf.sequences",function(v) trace_sequences=v end) local trace_markwidth=false registertracker("otf.markwidth",function(v) trace_markwidth=v end) local trace_defining=false registertracker("fonts.defining",function(v) trace_defining=v end) +local compact_lookups=true registertracker("otf.compactlookups",function(v) compact_lookups=v end) +local purge_names=true registertracker("otf.purgenames",function(v) purge_names=v end) local report_otf=logs.reporter("fonts","otf loading") local fonts=fonts local otf=fonts.handlers.otf otf.glists={ "gsub","gpos" } -otf.version=2.762 +otf.version=2.801 otf.cache=containers.define("fonts","otf",otf.version,true) local fontdata=fonts.hashes.identifiers local chardata=characters and characters.data -local otffeatures=fonts.constructors.newfeatures("otf") +local definers=fonts.definers +local readers=fonts.readers +local constructors=fonts.constructors +local otffeatures=constructors.newfeatures("otf") local registerotffeature=otffeatures.register local enhancers=allocate() otf.enhancers=enhancers local patches={} enhancers.patches=patches -local definers=fonts.definers -local readers=fonts.readers -local constructors=fonts.constructors local forceload=false local cleanup=0 -local usemetatables=false local packdata=true local syncspace=true local forcenotdef=false @@ -6872,7 +6948,6 @@ formats.ttc="truetype" formats.dfont="truetype" registerdirective("fonts.otf.loader.cleanup",function(v) cleanup=tonumber(v) or (v and 1) or 0 end) registerdirective("fonts.otf.loader.force",function(v) forceload=v end) -registerdirective("fonts.otf.loader.usemetatables",function(v) usemetatables=v end) registerdirective("fonts.otf.loader.pack",function(v) packdata=v end) registerdirective("fonts.otf.loader.syncspace",function(v) syncspace=v end) registerdirective("fonts.otf.loader.forcenotdef",function(v) forcenotdef=v end) @@ -7017,6 +7092,8 @@ local ordered_enhancers={ "check encoding", "add duplicates", "cleanup tables", + "compact lookups", + "purge names", } local actions=allocate() local before=allocate() @@ -7207,7 +7284,7 @@ function otf.load(filename,sub,featurefile) goodies={}, helpers={ tounicodelist=splitter, - tounicodetable=lpeg.Ct(splitter), + tounicodetable=Ct(splitter), }, } starttiming(data) @@ -7250,6 +7327,34 @@ function otf.load(filename,sub,featurefile) report_otf("loading from cache using hash %a",hash) end enhance("unpack",data,filename,nil,false) + local resources=data.resources + local lookuptags=resources.lookuptags + local unicodes=resources.unicodes + if not lookuptags then + lookuptags={} + resources.lookuptags=lookuptags + end + setmetatableindex(lookuptags,function(t,k) + local v=type(k)=="number" and ("lookup "..k) or k + t[k]=v + return v + end) + if not unicodes then + unicodes={} + resources.unicodes=unicodes + setmetatableindex(unicodes,function(t,k) + setmetatableindex(unicodes,nil) + for u,d in next,data.descriptions do + local n=d.name + if n then + t[n]=u + else + end + end + return rawget(t,k) + end) + end + constructors.addcoreunicodes(unicodes) if applyruntimefixes then applyruntimefixes(filename,data) end @@ -7286,34 +7391,22 @@ actions["add dimensions"]=function(data,filename) local defaultheight=resources.defaultheight or 0 local defaultdepth=resources.defaultdepth or 0 local basename=trace_markwidth and file.basename(filename) - if usemetatables then - for _,d in next,descriptions do - local wd=d.width - if not wd then - d.width=defaultwidth - elseif trace_markwidth and wd~=0 and d.class=="mark" then - report_otf("mark %a with width %b found in %a",d.name or "",wd,basename) - end - setmetatable(d,mt) + for _,d in next,descriptions do + local bb,wd=d.boundingbox,d.width + if not wd then + d.width=defaultwidth + elseif trace_markwidth and wd~=0 and d.class=="mark" then + report_otf("mark %a with width %b found in %a",d.name or "",wd,basename) end - else - for _,d in next,descriptions do - local bb,wd=d.boundingbox,d.width - if not wd then - d.width=defaultwidth - elseif trace_markwidth and wd~=0 and d.class=="mark" then - report_otf("mark %a with width %b found in %a",d.name or "",wd,basename) - end - if bb then - local ht,dp=bb[4],-bb[2] - if ht==0 or ht<0 then - else - d.height=ht - end - if dp==0 or dp<0 then - else - d.depth=dp - end + if bb then + local ht,dp=bb[4],-bb[2] + if ht==0 or ht<0 then + else + d.height=ht + end + if dp==0 or dp<0 then + else + d.depth=dp end end end @@ -7878,9 +7971,14 @@ local function t_hashed(t,cache) local ti=t[i] local tih=cache[ti] if not tih then - tih={} - for i=1,#ti do - tih[ti[i]]=true + local tn=#ti + if tn==1 then + tih={ [ti[1]]=true } + else + tih={} + for i=1,tn do + tih[ti[i]]=true + end end cache[ti]=tih end @@ -7893,12 +7991,17 @@ local function t_hashed(t,cache) end local function s_hashed(t,cache) if t then - local ht={} local tf=t[1] - for i=1,#tf do - ht[i]={ [tf[i]]=true } + local nf=#tf + if nf==1 then + return { [tf[1]]=true } + else + local ht={} + for i=1,nf do + ht[i]={ [tf[i]]=true } + end + return ht end - return ht else return nil end @@ -8326,7 +8429,7 @@ actions["check glyphs"]=function(data,filename,raw) description.glyph=nil end end -local valid=(lpeg.R("\x00\x7E")-lpeg.S("(){}[]<>%/ \n\r\f\v"))^0*lpeg.P(-1) +local valid=(R("\x00\x7E")-S("(){}[]<>%/ \n\r\f\v"))^0*P(-1) local function valid_ps_name(str) return str and str~="" and #str<64 and lpegmatch(valid,str) and true or false end @@ -8380,8 +8483,17 @@ actions["check metadata"]=function(data,filename,raw) end end actions["cleanup tables"]=function(data,filename,raw) + local duplicates=data.resources.duplicates + if duplicates then + for k,v in next,duplicates do + if #v==1 then + duplicates[k]=v[1] + end + end + end data.resources.indices=nil - data.helpers=nil + data.resources.unicodes=nil + data.helpers=nil end actions["reorganize glyph lookups"]=function(data,filename,raw) local resources=data.resources @@ -8486,6 +8598,142 @@ actions["reorganize glyph anchors"]=function(data,filename,raw) end end end +local bogusname=(P("uni")+P("u"))*R("AF","09")^4+(P("index")+P("glyph")+S("Ii")*P("dentity")*P(".")^0)*R("09")^1 +local uselessname=(1-bogusname)^0*bogusname +actions["purge names"]=function(data,filename,raw) + if purge_names then + local n=0 + for u,d in next,data.descriptions do + if lpegmatch(uselessname,d.name) then + n=n+1 + d.name=nil + end + end + if n>0 then + report_otf("%s bogus names removed",n) + end + end +end +actions["compact lookups"]=function(data,filename,raw) + if not compact_lookups then + report_otf("not compacting") + return + end + local last=0 + local tags=table.setmetatableindex({}, + function(t,k) + last=last+1 + t[k]=last + return last + end + ) + local descriptions=data.descriptions + local resources=data.resources + for u,d in next,descriptions do + local slookups=d.slookups + if type(slookups)=="table" then + local s={} + for k,v in next,slookups do + s[tags[k]]=v + end + d.slookups=s + end + local mlookups=d.mlookups + if type(mlookups)=="table" then + local m={} + for k,v in next,mlookups do + m[tags[k]]=v + end + d.mlookups=m + end + local kerns=d.kerns + if type(kerns)=="table" then + local t={} + for k,v in next,kerns do + t[tags[k]]=v + end + d.kerns=t + end + end + local lookups=data.lookups + if lookups then + local l={} + for k,v in next,lookups do + local rules=v.rules + if rules then + for i=1,#rules do + local l=rules[i].lookups + if type(l)=="table" then + for i=1,#l do + l[i]=tags[l[i]] + end + end + end + end + l[tags[k]]=v + end + data.lookups=l + end + local lookups=resources.lookups + if lookups then + local l={} + for k,v in next,lookups do + local s=v.subtables + if type(s)=="table" then + for i=1,#s do + s[i]=tags[s[i]] + end + end + l[tags[k]]=v + end + resources.lookups=l + end + local sequences=resources.sequences + if sequences then + for i=1,#sequences do + local s=sequences[i] + local n=s.name + if n then + s.name=tags[n] + end + local t=s.subtables + if type(t)=="table" then + for i=1,#t do + t[i]=tags[t[i]] + end + end + end + end + local lookuptypes=resources.lookuptypes + if lookuptypes then + local l={} + for k,v in next,lookuptypes do + l[tags[k]]=v + end + resources.lookuptypes=l + end + local anchor_to_lookup=resources.anchor_to_lookup + if anchor_to_lookup then + for anchor,lookups in next,anchor_to_lookup do + local l={} + for lookup,value in next,lookups do + l[tags[lookup]]=value + end + anchor_to_lookup[anchor]=l + end + end + local lookup_to_anchor=resources.lookup_to_anchor + if lookup_to_anchor then + local l={} + for lookup,value in next,lookup_to_anchor do + l[tags[lookup]]=value + end + resources.lookup_to_anchor=l + end + tags=table.swapped(tags) + report_otf("%s lookup tags compacted",#tags) + resources.lookuptags=tags +end function otf.setfeatures(tfmdata,features) local okay=constructors.initializefeatures("otf",tfmdata,features,trace_features,report_otf) if okay then @@ -8587,8 +8835,8 @@ local function copytotfm(data,cache_id) parameters.italicangle=italicangle parameters.charwidth=charwidth parameters.charxheight=charxheight - local space=0x0020 - local emdash=0x2014 + local space=0x0020 + local emdash=0x2014 if monospaced then if descriptions[space] then spaceunits,spacer=descriptions[space].width,"space" @@ -8635,7 +8883,7 @@ local function copytotfm(data,cache_id) if charxheight then parameters.x_height=charxheight else - local x=0x78 + local x=0x0078 if x then local x=descriptions[x] if x then @@ -8691,14 +8939,23 @@ local function otftotfm(specification) if duplicates then local nofduplicates,nofduplicated=0,0 for parent,list in next,duplicates do - for i=1,#list do - local unicode=list[i] - if not descriptions[unicode] then - descriptions[unicode]=descriptions[parent] + if type(list)=="table" then + local n=#list + for i=1,n do + local unicode=list[i] + if not descriptions[unicode] then + descriptions[unicode]=descriptions[parent] + nofduplicated=nofduplicated+1 + end + end + nofduplicates=nofduplicates+n + else + if not descriptions[list] then + descriptions[list]=descriptions[parent] nofduplicated=nofduplicated+1 end + nofduplicates=nofduplicates+1 end - nofduplicates=nofduplicates+#list end if trace_otf and nofduplicated~=nofduplicates then report_otf("%i extra duplicates copied out of %i",nofduplicated,nofduplicates) @@ -8829,7 +9086,7 @@ if not modules then modules={} end modules ['font-otb']={ } local concat=table.concat local format,gmatch,gsub,find,match,lower,strip=string.format,string.gmatch,string.gsub,string.find,string.match,string.lower,string.strip -local type,next,tonumber,tostring=type,next,tonumber,tostring +local type,next,tonumber,tostring,rawget=type,next,tonumber,tostring,rawget local lpegmatch=lpeg.match local utfchar=utf.char local trace_baseinit=false trackers.register("otf.baseinit",function(v) trace_baseinit=v end) @@ -8876,36 +9133,36 @@ local function gref(descriptions,n) return "" end end -local function cref(feature,lookupname) +local function cref(feature,lookuptags,lookupname) if lookupname then - return formatters["feature %a, lookup %a"](feature,lookupname) + return formatters["feature %a, lookup %a"](feature,lookuptags[lookupname]) else return formatters["feature %a"](feature) end end -local function report_alternate(feature,lookupname,descriptions,unicode,replacement,value,comment) +local function report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,comment) report_prepare("%s: base alternate %s => %s (%S => %S)", - cref(feature,lookupname), + cref(feature,lookuptags,lookupname), gref(descriptions,unicode), replacement and gref(descriptions,replacement), value, comment) end -local function report_substitution(feature,lookupname,descriptions,unicode,substitution) +local function report_substitution(feature,lookuptags,lookupname,descriptions,unicode,substitution) report_prepare("%s: base substitution %s => %S", - cref(feature,lookupname), + cref(feature,lookuptags,lookupname), gref(descriptions,unicode), gref(descriptions,substitution)) end -local function report_ligature(feature,lookupname,descriptions,unicode,ligature) +local function report_ligature(feature,lookuptags,lookupname,descriptions,unicode,ligature) report_prepare("%s: base ligature %s => %S", - cref(feature,lookupname), + cref(feature,lookuptags,lookupname), gref(descriptions,ligature), gref(descriptions,unicode)) end -local function report_kern(feature,lookupname,descriptions,unicode,otherunicode,value) +local function report_kern(feature,lookuptags,lookupname,descriptions,unicode,otherunicode,value) report_prepare("%s: base kern %s + %s => %S", - cref(feature,lookupname), + cref(feature,lookuptags,lookupname), gref(descriptions,unicode), gref(descriptions,otherunicode), value) @@ -8942,7 +9199,7 @@ local function finalize_ligatures(tfmdata,ligatures) local characters=tfmdata.characters local descriptions=tfmdata.descriptions local resources=tfmdata.resources - local unicodes=resources.unicodes + local unicodes=resources.unicodes local private=resources.private local alldone=false while not alldone do @@ -8978,12 +9235,12 @@ local function finalize_ligatures(tfmdata,ligatures) local secondname=firstname.."_"..secondcode if i==size-1 then target=unicode - if not unicodes[secondname] then + if not rawget(unicodes,secondname) then unicodes[secondname]=unicode end okay=true else - target=unicodes[secondname] + target=rawget(unicodes,secondname) if not target then break end @@ -9019,16 +9276,18 @@ local function finalize_ligatures(tfmdata,ligatures) end end resources.private=private + return true end end local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplist) local characters=tfmdata.characters local descriptions=tfmdata.descriptions local resources=tfmdata.resources + local properties=tfmdata.properties local changed=tfmdata.changed - local unicodes=resources.unicodes local lookuphash=resources.lookuphash local lookuptypes=resources.lookuptypes + local lookuptags=resources.lookuptags local ligatures={} local alternate=tonumber(value) or true and 1 local defaultalt=otf.defaultbasealternate @@ -9036,39 +9295,39 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis local trace_alternatives=trace_baseinit and trace_alternatives local trace_ligatures=trace_baseinit and trace_ligatures local actions={ - substitution=function(lookupdata,lookupname,description,unicode) + substitution=function(lookupdata,lookuptags,lookupname,description,unicode) if trace_singles then - report_substitution(feature,lookupname,descriptions,unicode,lookupdata) + report_substitution(feature,lookuptags,lookupname,descriptions,unicode,lookupdata) end changed[unicode]=lookupdata end, - alternate=function(lookupdata,lookupname,description,unicode) + alternate=function(lookupdata,lookuptags,lookupname,description,unicode) local replacement=lookupdata[alternate] if replacement then changed[unicode]=replacement if trace_alternatives then - report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"normal") + report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,"normal") end elseif defaultalt=="first" then replacement=lookupdata[1] changed[unicode]=replacement if trace_alternatives then - report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt) + report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,defaultalt) end elseif defaultalt=="last" then replacement=lookupdata[#data] if trace_alternatives then - report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt) + report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,defaultalt) end else if trace_alternatives then - report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"unknown") + report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,"unknown") end end end, - ligature=function(lookupdata,lookupname,description,unicode) + ligature=function(lookupdata,lookuptags,lookupname,description,unicode) if trace_ligatures then - report_ligature(feature,lookupname,descriptions,unicode,lookupdata) + report_ligature(feature,lookuptags,lookupname,descriptions,unicode,lookupdata) end ligatures[#ligatures+1]={ unicode,lookupdata } end, @@ -9084,7 +9343,7 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis local lookuptype=lookuptypes[lookupname] local action=actions[lookuptype] if action then - action(lookupdata,lookupname,description,unicode) + action(lookupdata,lookuptags,lookupname,description,unicode) end end end @@ -9099,22 +9358,24 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis local action=actions[lookuptype] if action then for i=1,#lookuplist do - action(lookuplist[i],lookupname,description,unicode) + action(lookuplist[i],lookuptags,lookupname,description,unicode) end end end end end end - finalize_ligatures(tfmdata,ligatures) + properties.hasligatures=finalize_ligatures(tfmdata,ligatures) end local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist) local characters=tfmdata.characters local descriptions=tfmdata.descriptions local resources=tfmdata.resources - local unicodes=resources.unicodes + local properties=tfmdata.properties + local lookuptags=resources.lookuptags local sharedkerns={} local traceindeed=trace_baseinit and trace_kerns + local haskerns=false for unicode,character in next,characters do local description=descriptions[unicode] local rawkerns=description.kerns @@ -9136,13 +9397,13 @@ local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist newkerns={ [otherunicode]=value } done=true if traceindeed then - report_kern(feature,lookup,descriptions,unicode,otherunicode,value) + report_kern(feature,lookuptags,lookup,descriptions,unicode,otherunicode,value) end elseif not newkerns[otherunicode] then newkerns[otherunicode]=value done=true if traceindeed then - report_kern(feature,lookup,descriptions,unicode,otherunicode,value) + report_kern(feature,lookuptags,lookup,descriptions,unicode,otherunicode,value) end end end @@ -9151,12 +9412,14 @@ local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist if done then sharedkerns[rawkerns]=newkerns character.kerns=newkerns + haskerns=true else sharedkerns[rawkerns]=false end end end end + properties.haskerns=haskerns end basemethods.independent={ preparesubstitutions=preparesubstitutions, @@ -9182,13 +9445,13 @@ local function make_1(present,tree,name) end end end -local function make_2(present,tfmdata,characters,tree,name,preceding,unicode,done,lookupname) +local function make_2(present,tfmdata,characters,tree,name,preceding,unicode,done,lookuptags,lookupname) for k,v in next,tree do if k=="ligature" then local character=characters[preceding] if not character then if trace_baseinit then - report_prepare("weird ligature in lookup %a, current %C, preceding %C",lookupname,v,preceding) + report_prepare("weird ligature in lookup %a, current %C, preceding %C",lookuptags[lookupname],v,preceding) end character=makefake(tfmdata,name,present) end @@ -9209,7 +9472,7 @@ local function make_2(present,tfmdata,characters,tree,name,preceding,unicode,don else local code=present[name] or unicode local name=name.."_"..k - make_2(present,tfmdata,characters,v,name,code,k,done,lookupname) + make_2(present,tfmdata,characters,v,name,code,k,done,lookuptags,lookupname) end end end @@ -9220,6 +9483,7 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis local changed=tfmdata.changed local lookuphash=resources.lookuphash local lookuptypes=resources.lookuptypes + local lookuptags=resources.lookuptags local ligatures={} local alternate=tonumber(value) or true and 1 local defaultalt=otf.defaultbasealternate @@ -9233,7 +9497,7 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis for unicode,data in next,lookupdata do if lookuptype=="substitution" then if trace_singles then - report_substitution(feature,lookupname,descriptions,unicode,data) + report_substitution(feature,lookuptags,lookupname,descriptions,unicode,data) end changed[unicode]=data elseif lookuptype=="alternate" then @@ -9241,28 +9505,28 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis if replacement then changed[unicode]=replacement if trace_alternatives then - report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"normal") + report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,"normal") end elseif defaultalt=="first" then replacement=data[1] changed[unicode]=replacement if trace_alternatives then - report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt) + report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,defaultalt) end elseif defaultalt=="last" then replacement=data[#data] if trace_alternatives then - report_alternate(feature,lookupname,descriptions,unicode,replacement,value,defaultalt) + report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,defaultalt) end else if trace_alternatives then - report_alternate(feature,lookupname,descriptions,unicode,replacement,value,"unknown") + report_alternate(feature,lookuptags,lookupname,descriptions,unicode,replacement,value,"unknown") end end elseif lookuptype=="ligature" then ligatures[#ligatures+1]={ unicode,data,lookupname } if trace_ligatures then - report_ligature(feature,lookupname,descriptions,unicode,data) + report_ligature(feature,lookuptags,lookupname,descriptions,unicode,data) end end end @@ -9280,7 +9544,7 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis for i=1,nofligatures do local ligature=ligatures[i] local unicode,tree,lookupname=ligature[1],ligature[2],ligature[3] - make_2(present,tfmdata,characters,tree,"ctx_"..unicode,unicode,unicode,done,lookupname) + make_2(present,tfmdata,characters,tree,"ctx_"..unicode,unicode,unicode,done,lookuptags,lookupname) end end end @@ -9288,7 +9552,9 @@ local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist local characters=tfmdata.characters local descriptions=tfmdata.descriptions local resources=tfmdata.resources + local properties=tfmdata.properties local lookuphash=resources.lookuphash + local lookuptags=resources.lookuptags local traceindeed=trace_baseinit and trace_kerns for l=1,#lookuplist do local lookupname=lookuplist[l] @@ -9304,7 +9570,7 @@ local function preparepositionings(tfmdata,feature,value,validlookups,lookuplist for otherunicode,kern in next,data do if not kerns[otherunicode] and kern~=0 then kerns[otherunicode]=kern - report_kern(feature,lookup,descriptions,unicode,otherunicode,kern) + report_kern(feature,lookuptags,lookup,descriptions,unicode,otherunicode,kern) end end else @@ -10318,6 +10584,7 @@ local currentfont=false local lookuptable=false local anchorlookups=false local lookuptypes=false +local lookuptags=false local handlers={} local rlmode=0 local featurevalue=false @@ -10362,19 +10629,19 @@ local function gref(n) end local function cref(kind,chainname,chainlookupname,lookupname,index) if index then - return formatters["feature %a, chain %a, sub %a, lookup %a, index %a"](kind,chainname,chainlookupname,lookupname,index) + return formatters["feature %a, chain %a, sub %a, lookup %a, index %a"](kind,chainname,chainlookupname,lookuptags[lookupname],index) elseif lookupname then - return formatters["feature %a, chain %a, sub %a, lookup %a"](kind,chainname,chainlookupname,lookupname) + return formatters["feature %a, chain %a, sub %a, lookup %a"](kind,chainname,chainlookupname,lookuptags[lookupname]) elseif chainlookupname then - return formatters["feature %a, chain %a, sub %a"](kind,chainname,chainlookupname) + return formatters["feature %a, chain %a, sub %a"](kind,lookuptags[chainname],lookuptags[chainlookupname]) elseif chainname then - return formatters["feature %a, chain %a"](kind,chainname) + return formatters["feature %a, chain %a"](kind,lookuptags[chainname]) else return formatters["feature %a"](kind) end end local function pref(kind,lookupname) - return formatters["feature %a, lookup %a"](kind,lookupname) + return formatters["feature %a, lookup %a"](kind,lookuptags[lookupname]) end local function copy_glyph(g) local components=g.components @@ -11728,7 +11995,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end else local i=1 - repeat + while true do if skipped then while true do local char=start.char @@ -11765,11 +12032,13 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end end end - if start then + if i>nofchainlookups then + break + elseif start then start=start.next else end - until i>nofchainlookups + end end else local replacements=ck[7] @@ -11910,6 +12179,7 @@ local function featuresprocessor(head,font,attr) anchorlookups=resources.lookup_to_anchor lookuptable=resources.lookups lookuptypes=resources.lookuptypes + lookuptags=resources.lookuptags currentfont=font rlmode=0 local sequences=resources.sequences @@ -12441,6 +12711,7 @@ local function prepare_contextchains(tfmdata) local rawdata=tfmdata.shared.rawdata local resources=rawdata.resources local lookuphash=resources.lookuphash + local lookuptags=resources.lookuptags local lookups=rawdata.lookups if lookups then for lookupname,lookupdata in next,rawdata.lookups do @@ -12453,7 +12724,7 @@ local function prepare_contextchains(tfmdata) if not validformat then report_prepare("unsupported format %a",format) elseif not validformat[lookuptype] then - report_prepare("unsupported format %a, lookuptype %a, lookupname %a",format,lookuptype,lookupname) + report_prepare("unsupported format %a, lookuptype %a, lookupname %a",format,lookuptype,lookuptags[lookupname]) else local contexts=lookuphash[lookupname] if not contexts then @@ -12502,7 +12773,7 @@ local function prepare_contextchains(tfmdata) else end else - report_prepare("missing lookuptype for lookupname %a",lookupname) + report_prepare("missing lookuptype for lookupname %a",lookuptags[lookupname]) end end end @@ -13374,6 +13645,7 @@ if otf.enhancers.register then otf.enhancers.register("unpack",unpackdata) end otf.enhancers.unpack=unpackdata +otf.enhancers.pack=packdata end -- closure diff --git a/tex/generic/context/luatex/luatex-fonts-otn.lua b/tex/generic/context/luatex/luatex-fonts-otn.lua index 068f0a9b9..831b23350 100644 --- a/tex/generic/context/luatex/luatex-fonts-otn.lua +++ b/tex/generic/context/luatex/luatex-fonts-otn.lua @@ -252,6 +252,7 @@ local currentfont = false local lookuptable = false local anchorlookups = false local lookuptypes = false +local lookuptags = false local handlers = { } local rlmode = 0 local featurevalue = false @@ -306,20 +307,20 @@ end local function cref(kind,chainname,chainlookupname,lookupname,index) -- not in the mood to alias f_ if index then - return formatters["feature %a, chain %a, sub %a, lookup %a, index %a"](kind,chainname,chainlookupname,lookupname,index) + return formatters["feature %a, chain %a, sub %a, lookup %a, index %a"](kind,chainname,chainlookupname,lookuptags[lookupname],index) elseif lookupname then - return formatters["feature %a, chain %a, sub %a, lookup %a"](kind,chainname,chainlookupname,lookupname) + return formatters["feature %a, chain %a, sub %a, lookup %a"](kind,chainname,chainlookupname,lookuptags[lookupname]) elseif chainlookupname then - return formatters["feature %a, chain %a, sub %a"](kind,chainname,chainlookupname) + return formatters["feature %a, chain %a, sub %a"](kind,lookuptags[chainname],lookuptags[chainlookupname]) elseif chainname then - return formatters["feature %a, chain %a"](kind,chainname) + return formatters["feature %a, chain %a"](kind,lookuptags[chainname]) else return formatters["feature %a"](kind) end end local function pref(kind,lookupname) - return formatters["feature %a, lookup %a"](kind,lookupname) + return formatters["feature %a, lookup %a"](kind,lookuptags[lookupname]) end -- We can assume that languages that use marks are not hyphenated. We can also assume @@ -1896,7 +1897,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end else local i = 1 - repeat + while true do if skipped then while true do local char = start.char @@ -1937,12 +1938,14 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end end end - if start then + if i > nofchainlookups then + break + elseif start then start = start.next else -- weird end - until i > nofchainlookups + end end else local replacements = ck[7] @@ -2139,6 +2142,7 @@ local function featuresprocessor(head,font,attr) anchorlookups = resources.lookup_to_anchor lookuptable = resources.lookups lookuptypes = resources.lookuptypes + lookuptags = resources.lookuptags currentfont = font rlmode = 0 @@ -2734,6 +2738,7 @@ local function prepare_contextchains(tfmdata) local rawdata = tfmdata.shared.rawdata local resources = rawdata.resources local lookuphash = resources.lookuphash + local lookuptags = resources.lookuptags local lookups = rawdata.lookups if lookups then for lookupname, lookupdata in next, rawdata.lookups do @@ -2747,7 +2752,7 @@ local function prepare_contextchains(tfmdata) report_prepare("unsupported format %a",format) elseif not validformat[lookuptype] then -- todo: dejavu-serif has one (but i need to see what use it has) - report_prepare("unsupported format %a, lookuptype %a, lookupname %a",format,lookuptype,lookupname) + report_prepare("unsupported format %a, lookuptype %a, lookupname %a",format,lookuptype,lookuptags[lookupname]) else local contexts = lookuphash[lookupname] if not contexts then @@ -2803,7 +2808,7 @@ local function prepare_contextchains(tfmdata) -- no rules end else - report_prepare("missing lookuptype for lookupname %a",lookupname) + report_prepare("missing lookuptype for lookupname %a",lookuptags[lookupname]) end end end -- cgit v1.2.3