diff options
| -rw-r--r-- | luaotfload.dtx | 26 | ||||
| -rw-r--r-- | otfl-data-con.lua | 80 | ||||
| -rw-r--r-- | otfl-font-def.lua | 29 | ||||
| -rw-r--r-- | otfl-font-dum.lua | 19 | ||||
| -rw-r--r-- | otfl-font-ini.lua | 5 | ||||
| -rw-r--r-- | otfl-font-ota.lua | 38 | ||||
| -rw-r--r-- | otfl-font-otd.lua | 7 | ||||
| -rw-r--r-- | otfl-font-otf.lua | 391 | ||||
| -rw-r--r-- | otfl-font-otn.lua | 116 | ||||
| -rw-r--r-- | otfl-font-tfm.lua | 5 | ||||
| -rw-r--r-- | otfl-luat-dum.lua | 97 | ||||
| -rw-r--r-- | otfl-node-dum.lua | 108 | ||||
| -rw-r--r-- | otfl-node-fnt.lua | 205 | ||||
| -rw-r--r-- | otfl-node-ini.lua | 244 | ||||
| -rw-r--r-- | otfl-node-inj.lua | 92 | ||||
| -rw-r--r-- | otfl-node-res.lua | 302 | 
16 files changed, 608 insertions, 1156 deletions
| diff --git a/luaotfload.dtx b/luaotfload.dtx index 0918a4b..f2239b7 100644 --- a/luaotfload.dtx +++ b/luaotfload.dtx @@ -350,9 +350,7 @@ and the derived files  % \begin{itemize*}  % \item \texttt{luat-dum.lua}  % \item \texttt{data-con.lua} -% \item \texttt{node-ini.lua}  % \item \texttt{node-inj.lua} -% \item \texttt{node-fnt.lua}  % \item \texttt{node-dum.lua}  % \item \texttt{font-ini.lua}  % \item \texttt{font-tfm.lua} @@ -490,11 +488,12 @@ luaotfload.loadmodule('data-con.lua') -- maybe some day we don't need this one  %    \end{macrocode}  % -%    This one is for node support. +%    Node support modules.  %  %    \begin{macrocode} -luaotfload.loadmodule('node-ini.lua') +luaotfload.loadmodule('node-dum.lua') +luaotfload.loadmodule('node-inj.lua')  %    \end{macrocode}  % @@ -517,7 +516,7 @@ end  %    \end{macrocode}  % -%    A hack to remove a warning from \texttt{node-fnt.lua} as it is \ConTeXt\ +%    A hack to remove a warning from \texttt{node-dum.lua} as it is \ConTeXt\  %    specific.  %  %    \begin{macrocode} @@ -526,21 +525,15 @@ tex.attribute[0] = 0  %    \end{macrocode}  % -%    Some more modules. We don't load neither \texttt{font-enc.lua} nor -%    \texttt{font-afm.lua} as it will never be used here. +%    Font handling modules.  %  %    \begin{macrocode} -luaotfload.loadmodule('node-res.lua') -luaotfload.loadmodule('node-inj.lua') -luaotfload.loadmodule('node-fnt.lua') -luaotfload.loadmodule('node-dum.lua') -  luaotfload.loadmodule('font-ini.lua')  luaotfload.loadmodule('font-tfm.lua')  luaotfload.loadmodule('font-cid.lua') -luaotfload.loadmodule('font-map.lua')  luaotfload.loadmodule('font-ott.lua') +luaotfload.loadmodule('font-map.lua')  luaotfload.loadmodule('font-otf.lua')  luaotfload.loadmodule('font-otd.lua')  luaotfload.loadmodule('font-oti.lua') @@ -551,6 +544,13 @@ luaotfload.loadmodule('font-otc.lua')  luaotfload.loadmodule('font-def.lua')  luaotfload.loadmodule('font-xtx.lua')  luaotfload.loadmodule('font-dum.lua') + +%    \end{macrocode} +% +%    \textsf{luaotfload} specific modules. +% +%    \begin{macrocode} +  luaotfload.loadmodule('font-nms.lua')  luaotfload.loadmodule('font-clr.lua') diff --git a/otfl-data-con.lua b/otfl-data-con.lua index fabe0ba..e7bb8af 100644 --- a/otfl-data-con.lua +++ b/otfl-data-con.lua @@ -1,5 +1,5 @@  if not modules then modules = { } end modules ['data-con'] = { -    version   = 1.001, +    version   = 1.100,      comment   = "companion to luat-lib.mkiv",      author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",      copyright = "PRAGMA ADE / ConTeXt Development Team", @@ -37,38 +37,48 @@ end  local allocated = { } --- tracing +local mt = { +    __index = function(t,k) +        if k == "writable" then +            local writable = caches.getwritablepath(t.category,t.subcategory) or { "." } +            t.writable = writable +            return writable +        elseif k == "readables" then +            local readables = caches.getreadablepaths(t.category,t.subcategory) or { "." } +            t.readables = readables +            return readables +        end +    end +}  function containers.define(category, subcategory, version, enabled) -    return function() -        if category and subcategory then -            local c = allocated[category] -            if not c then -                c  = { } -                allocated[category] = c -            end -            local s = c[subcategory] -            if not s then -                s = { -                    category = category, -                    subcategory = subcategory, -                    storage = { }, -                    enabled = enabled, -                    version = version or 1.000, -                    trace = false, -                    path = caches and caches.setpath and caches.setpath(category,subcategory), -                } -                c[subcategory] = s -            end -            return s -        else -            return nil +    if category and subcategory then +        local c = allocated[category] +        if not c then +            c  = { } +            allocated[category] = c          end +        local s = c[subcategory] +        if not s then +            s = { +                category    = category, +                subcategory = subcategory, +                storage     = { }, +                enabled     = enabled, +                version     = version or math.pi, -- after all, this is TeX +                trace       = false, +             -- writable    = caches.getwritablepath  and caches.getwritablepath (category,subcategory) or { "." }, +             -- readables   = caches.getreadablepaths and caches.getreadablepaths(category,subcategory) or { "." }, +            } +            setmetatable(s,mt) +            c[subcategory] = s +        end +        return s      end  end  function containers.is_usable(container, name) -    return container.enabled and caches and caches.iswritable(container.path, name) +    return container.enabled and caches and caches.iswritable(container.writable, name)  end  function containers.is_valid(container, name) @@ -81,18 +91,20 @@ function containers.is_valid(container, name)  end  function containers.read(container,name) -    if container.enabled and caches and not container.storage[name] and containers.usecache then -        container.storage[name] = caches.loaddata(container.path,name) -        if containers.is_valid(container,name) then +    local storage = container.storage +    local stored = storage[name] +    if not stored and container.enabled and caches and containers.usecache then +        stored = caches.loaddata(container.readables,name) +        if stored and stored.cache_version == container.version then              report(container,"loaded",name)          else -            container.storage[name] = nil +            stored = nil          end -    end -    if container.storage[name] then +        storage[name] = stored +    elseif stored then          report(container,"reusing",name)      end -    return container.storage[name] +    return stored  end  function containers.write(container, name, data) @@ -101,7 +113,7 @@ function containers.write(container, name, data)          if container.enabled and caches then              local unique, shared = data.unique, data.shared              data.unique, data.shared = nil, nil -            caches.savedata(container.path, name, data) +            caches.savedata(container.writable, name, data)              report(container,"saved",name)              data.unique, data.shared = unique, shared          end diff --git a/otfl-font-def.lua b/otfl-font-def.lua index 0add703..8e64872 100644 --- a/otfl-font-def.lua +++ b/otfl-font-def.lua @@ -233,18 +233,29 @@ end  define.resolvers = resolvers +-- todo: reporter +  function define.resolvers.file(specification) -    specification.forced = file.extname(specification.name) -    specification.name = file.removesuffix(specification.name) +    local suffix = file.suffix(specification.name) +    if fonts.formats[suffix] then +        specification.forced = suffix +        specification.name = file.removesuffix(specification.name) +    end  end  function define.resolvers.name(specification)      local resolve = fonts.names.resolve      if resolve then -        specification.resolved, specification.sub = fonts.names.resolve(specification) -        if specification.resolved then -            specification.forced = file.extname(specification.resolved) -            specification.name = file.removesuffix(specification.resolved) +        local resolved, sub = fonts.names.resolve(specification) +        specification.resolved, specification.sub = resolved, sub +        if resolved then +            local suffix = file.suffix(resolved) +            if fonts.formats[suffix] then +                specification.forced = suffix +                specification.name = file.removesuffix(resolved) +            else +                specification.name = resolved +            end          end      else          define.resolvers.file(specification) @@ -456,7 +467,7 @@ end  local function check_otf(forced,specification,suffix,what)      local name = specification.name      if forced then -        name = file.addsuffix(name,suffix) +        name = file.addsuffix(name,suffix,true)      end      local fullname, tfmtable = resolvers.findbinfile(name,suffix) or "", nil -- one shot      if fullname == "" then @@ -578,7 +589,7 @@ function define.read(specification,size,id) -- id can be optional, name can alre      specification = define.resolve(specification)      local hash = tfm.hash_instance(specification)      if cache_them then -        local fontdata = containers.read(fonts.cache(),hash) -- for tracing purposes +        local fontdata = containers.read(fonts.cache,hash) -- for tracing purposes      end      local fontdata = define.registered(hash) -- id      if not fontdata then @@ -591,7 +602,7 @@ function define.read(specification,size,id) -- id can be optional, name can alre              end          end          if cache_them then -            fontdata = containers.write(fonts.cache(),hash,fontdata) -- for tracing purposes +            fontdata = containers.write(fonts.cache,hash,fontdata) -- for tracing purposes          end          if fontdata then              fontdata.hash = hash diff --git a/otfl-font-dum.lua b/otfl-font-dum.lua index 2de1ae1..c9ffb63 100644 --- a/otfl-font-dum.lua +++ b/otfl-font-dum.lua @@ -379,3 +379,22 @@ function fonts.otf.char(n)          tex.sprint("\\char" .. n)      end  end + +-- another one: + +fonts.strippables = table.tohash { +    0x000AD, 0x017B4, 0x017B5, 0x0200B, 0x0200C, 0x0200D, 0x0200E, 0x0200F, 0x0202A, 0x0202B, +    0x0202C, 0x0202D, 0x0202E, 0x02060, 0x02061, 0x02062, 0x02063, 0x0206A, 0x0206B, 0x0206C, +    0x0206D, 0x0206E, 0x0206F, 0x0FEFF, 0x1D173, 0x1D174, 0x1D175, 0x1D176, 0x1D177, 0x1D178, +    0x1D179, 0x1D17A, 0xE0001, 0xE0020, 0xE0021, 0xE0022, 0xE0023, 0xE0024, 0xE0025, 0xE0026, +    0xE0027, 0xE0028, 0xE0029, 0xE002A, 0xE002B, 0xE002C, 0xE002D, 0xE002E, 0xE002F, 0xE0030, +    0xE0031, 0xE0032, 0xE0033, 0xE0034, 0xE0035, 0xE0036, 0xE0037, 0xE0038, 0xE0039, 0xE003A, +    0xE003B, 0xE003C, 0xE003D, 0xE003E, 0xE003F, 0xE0040, 0xE0041, 0xE0042, 0xE0043, 0xE0044, +    0xE0045, 0xE0046, 0xE0047, 0xE0048, 0xE0049, 0xE004A, 0xE004B, 0xE004C, 0xE004D, 0xE004E, +    0xE004F, 0xE0050, 0xE0051, 0xE0052, 0xE0053, 0xE0054, 0xE0055, 0xE0056, 0xE0057, 0xE0058, +    0xE0059, 0xE005A, 0xE005B, 0xE005C, 0xE005D, 0xE005E, 0xE005F, 0xE0060, 0xE0061, 0xE0062, +    0xE0063, 0xE0064, 0xE0065, 0xE0066, 0xE0067, 0xE0068, 0xE0069, 0xE006A, 0xE006B, 0xE006C, +    0xE006D, 0xE006E, 0xE006F, 0xE0070, 0xE0071, 0xE0072, 0xE0073, 0xE0074, 0xE0075, 0xE0076, +    0xE0077, 0xE0078, 0xE0079, 0xE007A, 0xE007B, 0xE007C, 0xE007D, 0xE007E, 0xE007F, +} + diff --git a/otfl-font-ini.lua b/otfl-font-ini.lua index e451497..c695ec4 100644 --- a/otfl-font-ini.lua +++ b/otfl-font-ini.lua @@ -13,6 +13,7 @@ if not modules then modules = { } end modules ['font-ini'] = {  local utf = unicode.utf8  local format, serialize = string.format, table.serialize  local write_nl = texio.write_nl +local lower = string.lower  if not fontloader then fontloader = fontforge end @@ -84,12 +85,12 @@ end  fonts.formats = { }  function fonts.fontformat(filename,default) -    local extname = file.extname(filename) +    local extname = lower(file.extname(filename))      local format = fonts.formats[extname]      if format then          return format      else -        logs.report("fonts define","unable to detemine font format for '%s'",filename) +        logs.report("fonts define","unable to determine font format for '%s'",filename)          return default      end  end diff --git a/otfl-font-ota.lua b/otfl-font-ota.lua index 558e2fc..0b61e17 100644 --- a/otfl-font-ota.lua +++ b/otfl-font-ota.lua @@ -35,14 +35,8 @@ local penalty = node.id('penalty')  local set_attribute      = node.set_attribute  local has_attribute      = node.has_attribute  local traverse_id        = node.traverse_id -local delete_node        = nodes.delete -local replace_node       = nodes.replace -local insert_node_after  = node.insert_after -local insert_node_before = node.insert_before  local traverse_node_list = node.traverse -local new_glue_node      = nodes.glue -  local fontdata = fonts.ids  local state    = attributes.private('state') @@ -56,7 +50,6 @@ local a_to_language = otf.a_to_language  -- font related value, but then we also need dynamic features which is  -- somewhat slower; and .. we need a chain of them -  function fonts.initializers.node.otf.analyze(tfmdata,value,attr)      if attr and attr > 0 then          script, language = a_to_script[attr], a_to_language[attr] @@ -195,8 +188,6 @@ function fonts.analyzers.methods.nocolor(head,font,attr)      return head, true  end -otf.remove_joiners = false -- true -- for idris who want it as option -  local function finish(first,last)      if last then          if first == last then @@ -242,22 +233,10 @@ function fonts.analyzers.methods.arab(head,font,attr) -- maybe make a special ve      local tfmdata = fontdata[font]      local marks = tfmdata.marks      local first, last, current, done = nil, nil, head, false -    local joiners, nonjoiners -    local removejoiners = tfmdata.remove_joiners -- or otf.remove_joiners -    if removejoiners then -        joiners, nonjoiners = { }, { } -    end      while current do          if current.id == glyph and current.subtype<256 and current.font == font and not has_attribute(current,state) then              done = true              local char = current.char -            if removejoiners then -                if char == zwj then -                    joiners[#joiners+1] = current -                elseif char == zwnj then -                    nonjoiners[#nonjoiners+1] = current -                end -            end              if marks[char] then                  set_attribute(current,state,5) -- mark                  if trace_analyzing then fcs(current,"font:mark") end @@ -303,22 +282,5 @@ function fonts.analyzers.methods.arab(head,font,attr) -- maybe make a special ve          current = current.next      end      first, last = finish(first,last) -    if removejoiners then -        -- is never head -        for i=1,#joiners do -            delete_node(head,joiners[i]) -        end -        for i=1,#nonjoiners do -            replace_node(head,nonjoiners[i],new_glue_node(0)) -- or maybe a kern -        end -    end      return head, done  end - -table.insert(fonts.manipulators,"joiners") - -function fonts.initializers.node.otf.joiners(tfmdata,value) -    if value == "strip" then -        tfmdata.remove_joiners = true -    end -end diff --git a/otfl-font-otd.lua b/otfl-font-otd.lua index 41e8853..14a9727 100644 --- a/otfl-font-otd.lua +++ b/otfl-font-otd.lua @@ -6,7 +6,7 @@ if not modules then modules = { } end modules ['font-otd'] = {      license   = "see context related readme files"  } -local trace_dynamics  = false  trackers.register("otf.dynamics",     function(v) trace_dynamics     = v end) +local trace_dynamics = false  trackers.register("otf.dynamics", function(v) trace_dynamics     = v end)  fonts     = fonts     or { }  fonts.otf = fonts.otf or { } @@ -60,9 +60,10 @@ function otf.set_dynamics(font,dynamics,attribute)              tfmdata.script   = script              tfmdata.shared.features = { }              -- end of save -            dsla = otf.set_features(tfmdata,fonts.define.check(features,otf.features.default)) +            local set = fonts.define.check(features,otf.features.default) +            dsla = otf.set_features(tfmdata,set)              if trace_dynamics then -                logs.report("otf define","setting dynamics %s: attribute %s, script %s, language %s",context_numbers[attribute],attribute,script,language) +                logs.report("otf define","setting dynamics %s: attribute %s, script %s, language %s, set: %s",context_numbers[attribute],attribute,script,language,table.sequenced(set))              end              -- we need to restore some values              tfmdata.script          = saved.script diff --git a/otfl-font-otf.lua b/otfl-font-otf.lua index d68137c..b113cf6 100644 --- a/otfl-font-otf.lua +++ b/otfl-font-otf.lua @@ -8,9 +8,11 @@ if not modules then modules = { } end modules ['font-otf'] = {  local utf = unicode.utf8 -local concat, getn, utfbyte = table.concat, table.getn, utf.byte +local concat, utfbyte = table.concat, utf.byte  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 abs = math.abs +local getn = table.getn  local lpegmatch = lpeg.match  local trace_private    = false  trackers.register("otf.private",      function(v) trace_private      = v end) @@ -80,7 +82,7 @@ otf.features.default = otf.features.default or { }  otf.enhancers        = otf.enhancers        or { }  otf.glists           = { "gsub", "gpos" } -otf.version          = 2.650 -- beware: also sync font-mis.lua +otf.version          = 2.653 -- beware: also sync font-mis.lua  otf.pack             = true  -- beware: also sync font-mis.lua  otf.syncspace        = true  otf.notdef           = false @@ -220,6 +222,7 @@ local enhancers = {  function otf.load(filename,format,sub,featurefile)      local name = file.basename(file.removesuffix(filename)) +    local size = lfs.attributes(filename,"size") or 0      if featurefile then          name = name .. "@" .. file.removesuffix(file.basename(featurefile))      end @@ -229,8 +232,7 @@ function otf.load(filename,format,sub,featurefile)          hash = hash .. "-" .. sub      end      hash = containers.cleanname(hash) -    local data = containers.read(otf.cache(), hash) -    local size = lfs.attributes(filename,"size") or 0 +    local data = containers.read(otf.cache,hash)      if not data or data.verbose ~= fonts.verbose or data.size ~= size then          logs.report("load otf","loading: %s (hash: %s)",filename,hash)          local ff, messages @@ -267,9 +269,9 @@ function otf.load(filename,format,sub,featurefile)                  data.size = size                  data.verbose = fonts.verbose                  logs.report("load otf","saving in cache: %s",filename) -                data = containers.write(otf.cache(), hash, data) +                data = containers.write(otf.cache, hash, data)                  collectgarbage("collect") -                data = containers.read(otf.cache(), hash) -- this frees the old table and load the sparse one +                data = containers.read(otf.cache, hash) -- this frees the old table and load the sparse one                  collectgarbage("collect")              else                  logs.report("load otf","loading failed (table conversion error)") @@ -788,14 +790,12 @@ otf.enhancers["check math"] = function(data,filename)                  if hv then                      math.horiz_variants = hv.variants                      local p = hv.parts -                    if p then -                        if #p>0 then -                            for i=1,#p do -                                local pi = p[i] -                                pi.glyph = unicodes[pi.component] or 0 -                            end -                            math.horiz_parts = p +                    if p and #p > 0 then +                        for i=1,#p do +                            local pi = p[i] +                            pi.glyph = unicodes[pi.component] or 0                          end +                        math.horiz_parts = p                      end                      local ic = hv.italic_correction                      if ic and ic ~= 0 then @@ -807,14 +807,12 @@ otf.enhancers["check math"] = function(data,filename)                      local uc = unicodes[index]                      math.vert_variants = vv.variants                      local p = vv.parts -                    if p then -                        if #p>0 then -                            for i=1,#p do -                                local pi = p[i] -                                pi.glyph = unicodes[pi.component] or 0 -                            end -                            math.vert_parts = p +                    if p and #p > 0 then +                        for i=1,#p do +                            local pi = p[i] +                            pi.glyph = unicodes[pi.component] or 0                          end +                        math.vert_parts = p                      end                      local ic = vv.italic_correction                      if ic and ic ~= 0 then @@ -863,10 +861,15 @@ end  -- kern: ttf has a table with kerns +-- Weird, as maxfirst and maxseconds can have holes, first seems to be indexed, but +-- seconds can start at 2 .. this need to be fixed as getn as well as # are sort of +-- unpredictable alternatively we could force an [1] if not set (maybe I will do that +-- anyway). +  --~ otf.enhancers["reorganize kerns"] = function(data,filename)  --~     local glyphs, mapmap, unicodes = data.glyphs, data.luatex.indices, data.luatex.unicodes  --~     local mkdone = false ---~     for index, glyph in next, data.glyphs do +--~     for index, glyph in next, glyphs do  --~         if glyph.kerns then  --~             local mykerns = { }  --~             for k,v in next, glyph.kerns do @@ -915,6 +918,9 @@ end  --~     end  --~     local dgpos = data.gpos  --~     if dgpos then +--~         local separator = lpeg.P(" ") +--~         local other = ((1 - separator)^0) / unicodes +--~         local splitter = lpeg.Ct(other * (separator * other)^0)  --~         for gp=1,#dgpos do  --~             local gpos = dgpos[gp]  --~             local subtables = gpos.subtables @@ -923,56 +929,70 @@ end  --~                     local subtable = subtables[s]  --~                     local kernclass = subtable.kernclass -- name is inconsistent with anchor_classes  --~                     if kernclass then -- the next one is quite slow +--~                         local split = { } -- saves time  --~                         for k=1,#kernclass do  --~                             local kcl = kernclass[k]  --~                             local firsts, seconds, offsets, lookups = kcl.firsts, kcl.seconds, kcl.offsets, kcl.lookup -- singular  --~                             if type(lookups) ~= "table" then  --~                                 lookups = { lookups }  --~                             end +--~                             local maxfirsts, maxseconds = getn(firsts), getn(seconds) +--~                             for _, s in next, firsts do +--~                                 split[s] = split[s] or lpegmatch(splitter,s) +--~                             end +--~                             for _, s in next, seconds do +--~                                 split[s] = split[s] or lpegmatch(splitter,s) +--~                             end  --~                             for l=1,#lookups do  --~                                 local lookup = lookups[l] ---~                                 -- weird, as maxfirst and maxseconds can have holes ---~                                 local maxfirsts, maxseconds = getn(firsts), getn(seconds) ---~                                 if trace_loading then ---~                                     logs.report("load otf", "adding kernclass %s with %s times %s pairs",lookup, maxfirsts, maxseconds) ---~                                 end ---~                                 for fk, fv in next, firsts do ---~                                     for first in gmatch(fv,"[^ ]+") do ---~                                         local first_unicode = unicodes[first] ---~                                         if type(first_unicode) == "number" then ---~                                             first_unicode = { first_unicode } +--~                                 local function do_it(fk,first_unicode) +--~                                     local glyph = glyphs[mapmap[first_unicode]] +--~                                     if glyph then +--~                                         local mykerns = glyph.mykerns +--~                                         if not mykerns then +--~                                             mykerns = { } -- unicode indexed ! +--~                                             glyph.mykerns = mykerns  --~                                         end ---~                                         for f=1,#first_unicode do ---~                                             local glyph = glyphs[mapmap[first_unicode[f]]] ---~                                             if glyph then ---~                                                 local mykerns = glyph.mykerns ---~                                                 if not mykerns then ---~                                                     mykerns = { } -- unicode indexed ! ---~                                                     glyph.mykerns = mykerns ---~                                                 end ---~                                                 local lookupkerns = mykerns[lookup] ---~                                                 if not lookupkerns then ---~                                                     lookupkerns = { } ---~                                                     mykerns[lookup] = lookupkerns ---~                                                 end ---~                                                 for sk, sv in next, seconds do ---~                                                     local offset = offsets[(fk-1) * maxseconds + sk] ---~                                                     --~ local offset = offsets[sk] -- (fk-1) * maxseconds + sk] ---~                                                     for second in gmatch(sv,"[^ ]+") do ---~                                                         local second_unicode = unicodes[second] ---~                                                         if type(second_unicode) == "number" then +--~                                         local lookupkerns = mykerns[lookup] +--~                                         if not lookupkerns then +--~                                             lookupkerns = { } +--~                                             mykerns[lookup] = lookupkerns +--~                                         end +--~                                         local baseoffset = (fk-1) * maxseconds +--~                                         for sk=2,maxseconds do -- we can avoid this loop with a table +--~                                             local sv = seconds[sk] +--~                                             local splt = split[sv] +--~                                             if splt then +--~                                                 local offset = offsets[baseoffset + sk] +--~                                                 --~ local offset = offsets[sk] -- (fk-1) * maxseconds + sk] +--~                                                 if offset then +--~                                                     for i=1,#splt do +--~                                                         local second_unicode = splt[i] +--~                                                         if tonumber(second_unicode) then  --~                                                             lookupkerns[second_unicode] = offset ---~                                                         else ---~                                                             for s=1,#second_unicode do ---~                                                                 lookupkerns[second_unicode[s]] = offset ---~                                                             end ---~                                                         end +--~                                                         else for s=1,#second_unicode do +--~                                                             lookupkerns[second_unicode[s]] = offset +--~                                                         end end  --~                                                     end  --~                                                 end ---~                                             elseif trace_loading then ---~                                                 logs.report("load otf", "no glyph data for U+%04X", first_unicode[f])  --~                                             end  --~                                         end +--~                                     elseif trace_loading then +--~                                         logs.report("load otf", "no glyph data for U+%04X", first_unicode) +--~                                     end +--~                                 end +--~                                 for fk=1,#firsts do +--~                                     local fv = firsts[fk] +--~                                     local splt = split[fv] +--~                                     if splt then +--~                                         for i=1,#splt do +--~                                             local first_unicode = splt[i] +--~                                             if tonumber(first_unicode) then +--~                                                 do_it(fk,first_unicode) +--~                                             else for f=1,#first_unicode do +--~                                                 do_it(fk,first_unicode[f]) +--~                                             end end +--~                                         end  --~                                     end  --~                                 end  --~                             end @@ -989,7 +1009,27 @@ end  otf.enhancers["reorganize kerns"] = function(data,filename)      local glyphs, mapmap, unicodes = data.glyphs, data.luatex.indices, data.luatex.unicodes      local mkdone = false -    for index, glyph in next, data.glyphs do +    local function do_it(lookup,first_unicode,kerns) +        local glyph = glyphs[mapmap[first_unicode]] +        if glyph then +            local mykerns = glyph.mykerns +            if not mykerns then +                mykerns = { } -- unicode indexed ! +                glyph.mykerns = mykerns +            end +            local lookupkerns = mykerns[lookup] +            if not lookupkerns then +                lookupkerns = { } +                mykerns[lookup] = lookupkerns +            end +            for second_unicode, kern in next, kerns do +                lookupkerns[second_unicode] = kern +            end +        elseif trace_loading then +            logs.report("load otf", "no glyph data for U+%04X", first_unicode) +        end +    end +    for index, glyph in next, glyphs do          if glyph.kerns then              local mykerns = { }              for k,v in next, glyph.kerns do @@ -1049,75 +1089,53 @@ otf.enhancers["reorganize kerns"] = function(data,filename)                      local subtable = subtables[s]                      local kernclass = subtable.kernclass -- name is inconsistent with anchor_classes                      if kernclass then -- the next one is quite slow +                        local split = { } -- saves time                          for k=1,#kernclass do                              local kcl = kernclass[k]                              local firsts, seconds, offsets, lookups = kcl.firsts, kcl.seconds, kcl.offsets, kcl.lookup -- singular                              if type(lookups) ~= "table" then                                  lookups = { lookups }                              end -                            local split = { } +                            local maxfirsts, maxseconds = getn(firsts), getn(seconds) +                            -- here we could convert split into a list of unicodes which is a bit +                            -- faster but as this is only done when caching it does not save us much +                            for _, s in next, firsts do +                                split[s] = split[s] or lpegmatch(splitter,s) +                            end +                            for _, s in next, seconds do +                                split[s] = split[s] or lpegmatch(splitter,s) +                            end                              for l=1,#lookups do                                  local lookup = lookups[l] -                                -- weird, as maxfirst and maxseconds can have holes, first seems to be indexed, seconds starts at 2 -                                local maxfirsts, maxseconds = getn(firsts), getn(seconds) -                                for _, s in next, firsts do -                                    split[s] = split[s] or lpegmatch(splitter,s) -                                end -                                for _, s in next, seconds do -                                    split[s] = split[s] or lpegmatch(splitter,s) -                                end -                                if trace_loading then -                                    logs.report("load otf", "adding kernclass %s with %s times %s pairs",lookup, maxfirsts, maxseconds) -                                end -                                local function do_it(fk,first_unicode) -                                    local glyph = glyphs[mapmap[first_unicode]] -                                    if glyph then -                                        local mykerns = glyph.mykerns -                                        if not mykerns then -                                            mykerns = { } -- unicode indexed ! -                                            glyph.mykerns = mykerns -                                        end -                                        local lookupkerns = mykerns[lookup] -                                        if not lookupkerns then -                                            lookupkerns = { } -                                            mykerns[lookup] = lookupkerns -                                        end -                                        local baseoffset = (fk-1) * maxseconds +                                for fk=1,#firsts do +                                    local fv = firsts[fk] +                                    local splt = split[fv] +                                    if splt then +                                        local kerns, baseoffset = { }, (fk-1) * maxseconds                                          for sk=2,maxseconds do                                              local sv = seconds[sk] -                                            local offset = offsets[baseoffset + sk] -                                            --~ local offset = offsets[sk] -- (fk-1) * maxseconds + sk]                                              local splt = split[sv]                                              if splt then -                                                for i=1,#splt do -                                                    local second_unicode = splt[i] -                                                    if tonumber(second_unicode) then -                                                        lookupkerns[second_unicode] = offset -                                                    else -                                                        for s=1,#second_unicode do -                                                            lookupkerns[second_unicode[s]] = offset -                                                        end +                                                local offset = offsets[baseoffset + sk] +                                                if offset then +                                                    for i=1,#splt do +                                                        local second_unicode = splt[i] +                                                        if tonumber(second_unicode) then +                                                            kerns[second_unicode] = offset +                                                        else for s=1,#second_unicode do +                                                            kerns[second_unicode[s]] = offset +                                                        end end                                                      end                                                  end                                              end                                          end -                                    elseif trace_loading then -                                        logs.report("load otf", "no glyph data for U+%04X", first_unicode) -                                    end -                                end -                                for fk=1,#firsts do -                                    local fv = firsts[fk] -                                    local splt = split[fv] -                                    if splt then                                          for i=1,#splt do                                              local first_unicode = splt[i]                                              if tonumber(first_unicode) then -                                                do_it(fk,first_unicode) -                                            else -                                                for f=1,#first_unicode do -                                                    do_it(fk,first_unicode[f]) -                                                end -                                            end +                                                do_it(lookup,first_unicode,kerns) +                                            else for f=1,#first_unicode do +                                                do_it(lookup,first_unicode[f],kerns) +                                            end end                                          end                                      end                                  end @@ -1132,6 +1150,14 @@ otf.enhancers["reorganize kerns"] = function(data,filename)      end  end + + + + + + + +  otf.enhancers["strip not needed data"] = function(data,filename)      local verbose = fonts.verbose      local int_to_uni = data.luatex.unicodes @@ -1356,10 +1382,12 @@ function otf.features.register(name,default)      otf.features.default[name] = default  end +-- for context this will become a task handler +  function otf.set_features(tfmdata,features)      local processes = { }      if features and next(features) then -        local lists = { +        local lists = { -- why local              fonts.triggers,              fonts.processors,              fonts.manipulators, @@ -1396,7 +1424,7 @@ function otf.set_features(tfmdata,features)                  end              end          end -        local fm = fonts.methods[mode] +        local fm = fonts.methods[mode] -- todo: zonder node/mode otf/...          if fm then              local fmotf = fm.otf              if fmotf then @@ -1429,7 +1457,7 @@ function otf.otf_to_tfm(specification)      local format   = specification.format      local features = specification.features.normal      local cache_id = specification.hash -    local tfmdata  = containers.read(tfm.cache(),cache_id) +    local tfmdata  = containers.read(tfm.cache,cache_id)  --~ print(cache_id)      if not tfmdata then          local otfdata = otf.load(filename,format,sub,features and features.featurefile) @@ -1463,7 +1491,7 @@ function otf.otf_to_tfm(specification)                  shared.processes, shared.features = otf.set_features(tfmdata,fonts.define.check(features,otf.features.default))              end          end -        containers.write(tfm.cache(),cache_id,tfmdata) +        containers.write(tfm.cache,cache_id,tfmdata)      end      return tfmdata  end @@ -1505,14 +1533,11 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th          local unicodes = luatex.unicodes -- names to unicodes          local indices = luatex.indices          local characters, parameters, math_parameters, descriptions = { }, { }, { }, { } -        local tfm = { -            characters = characters, -            parameters = parameters, -            math_parameters = math_parameters, -            descriptions = descriptions, -            indices = indices, -            unicodes = unicodes, -        } +        local designsize = metadata.designsize or metadata.design_size or 100 +        if designsize == 0 then +            designsize = 100 +        end +        local spaceunits = 500          -- indices maps from unicodes to indices          for u, i in next, indices do              characters[u] = { } -- we need this because for instance we add protruding info and loop over characters @@ -1531,9 +1556,8 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th                  -- we have them shared because that packs nicer                  -- we could prepare the variants and keep 'm in descriptions                  if m then -                    local variants = m.horiz_variants +                    local variants, parts, c = m.horiz_variants, m.horiz_parts, char                      if variants then -                        local c = char                          for n in gmatch(variants,"[^ ]+") do                              local un = unicodes[n]                              if un and u ~= un then @@ -1541,21 +1565,26 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th                                  c = characters[un]                              end                          end -                        c.horiz_variants = m.horiz_parts -                    else -                        local variants = m.vert_variants -                        if variants then -                            local c = char -                            for n in gmatch(variants,"[^ ]+") do -                                local un = unicodes[n] -                                if un and u ~= un then -                                    c.next = un -                                    c = characters[un] -                                end +                        c.horiz_variants = parts +                    elseif parts then +                        c.horiz_variants = parts +                    end +                    local variants, parts, c = m.vert_variants, m.vert_parts, char +                    if variants then +                        for n in gmatch(variants,"[^ ]+") do +                            local un = unicodes[n] +                            if un and u ~= un then +                                c.next = un +                                c = characters[un]                              end -                            c.vert_variants = m.vert_parts -                            c.vert_italic_correction = m.vert_italic_correction -                        end +                        end -- c is now last in chain +                        c.vert_variants = parts +                    elseif parts then +                        c.vert_variants = parts +                    end +                    local italic_correction = m.vert_italic_correction +                    if italic_correction then +                        c.vert_italic_correction = italic_correction                      end                      local kerns = m.kerns                      if kerns then @@ -1565,65 +1594,49 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th              end          end          -- end math -        local designsize = metadata.designsize or metadata.design_size or 100 -        if designsize == 0 then -            designsize = 100 -        end -        local spaceunits = 500 -        -- we need a runtime lookup because of running from cdrom or zip, brrr (shouldn't we use the basename then?) -        tfm.filename           = fonts.tfm.checked_filename(luatex) -        tfm.fontname           = metadata.fontname -        tfm.fullname           = metadata.fullname or tfm.fontname -        tfm.psname             = tfm.fontname or tfm.fullname -        tfm.name               = tfm.filename or tfm.fullname or tfm.fontname -        tfm.units              = metadata.units_per_em or 1000 -        tfm.encodingbytes      = 2 -        tfm.format             = fonts.fontformat(tfm.filename,"opentype") -        tfm.cidinfo            = data.cidinfo -        tfm.cidinfo.registry   = tfm.cidinfo.registry or "" -        tfm.type               = "real" -        tfm.direction          = 0 -        tfm.boundarychar_label = 0 -        tfm.boundarychar       = 65536 -        tfm.designsize         = (designsize/10)*65536 -        tfm.spacer             = "500 units" -        local endash, emdash = 0x20, 0x2014 -- unicodes['space'], unicodes['emdash'] +        local endash, emdash, space = 0x20, 0x2014, "space" -- unicodes['space'], unicodes['emdash']          if metadata.isfixedpitch then              if descriptions[endash] then -                spaceunits, tfm.spacer = descriptions[endash].width, "space" +                spaceunits, spacer = descriptions[endash].width, "space"              end              if not spaceunits and descriptions[emdash] then -                spaceunits, tfm.spacer = descriptions[emdash].width, "emdash" +                spaceunits, spacer = descriptions[emdash].width, "emdash"              end              if not spaceunits and metadata.charwidth then -                spaceunits, tfm.spacer = metadata.charwidth, "charwidth" +                spaceunits, spacer = metadata.charwidth, "charwidth"              end          else              if descriptions[endash] then -                spaceunits, tfm.spacer = descriptions[endash].width, "space" +                spaceunits, spacer = descriptions[endash].width, "space"              end              if not spaceunits and descriptions[emdash] then -                spaceunits, tfm.spacer = descriptions[emdash].width/2, "emdash/2" +                spaceunits, spacer = descriptions[emdash].width/2, "emdash/2"              end              if not spaceunits and metadata.charwidth then -                spaceunits, tfm.spacer = metadata.charwidth, "charwidth" +                spaceunits, spacer = metadata.charwidth, "charwidth"              end          end          spaceunits = tonumber(spaceunits) or tfm.units/2 -- 500 -- brrr +        -- we need a runtime lookup because of running from cdrom or zip, brrr (shouldn't we use the basename then?) +        local filename = fonts.tfm.checked_filename(luatex) +        local fontname = metadata.fontname +        local fullname = metadata.fullname or fontname +        local cidinfo  = data.cidinfo +        local units    = metadata.units_per_em or 1000 +        -- +        cidinfo.registry = cidinfo and cidinfo.registry or "" -- weird here, fix upstream +        --          parameters.slant         = 0 -        parameters.space         = spaceunits              -- 3.333 (cmr10) -        parameters.space_stretch = tfm.units/2   --  500   -- 1.666 (cmr10) -        parameters.space_shrink  = 1*tfm.units/3 --  333   -- 1.111 (cmr10) -        parameters.x_height      = 2*tfm.units/5 --  400 -        parameters.quad          = tfm.units     -- 1000 -        if spaceunits < 2*tfm.units/5 then +        parameters.space         = spaceunits          -- 3.333 (cmr10) +        parameters.space_stretch = units/2   --  500   -- 1.666 (cmr10) +        parameters.space_shrink  = 1*units/3 --  333   -- 1.111 (cmr10) +        parameters.x_height      = 2*units/5 --  400 +        parameters.quad          = units     -- 1000 +        if spaceunits < 2*units/5 then              -- todo: warning          end          local italicangle = metadata.italicangle -        tfm.ascender    = math.abs(metadata.ascent  or 0) -        tfm.descender   = math.abs(metadata.descent or 0)          if italicangle then -- maybe also in afm _ -            tfm.italicangle = italicangle              parameters.slant = parameters.slant - math.round(math.tan(italicangle*math.pi/180))          end          if metadata.isfixedpitch then @@ -1645,8 +1658,34 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th                  end              end          end -        -- [6] -        return tfm +        -- +        return { +            characters         = characters, +            parameters         = parameters, +            math_parameters    = math_parameters, +            descriptions       = descriptions, +            indices            = indices, +            unicodes           = unicodes, +            type               = "real", +            direction          = 0, +            boundarychar_label = 0, +            boundarychar       = 65536, +            designsize         = (designsize/10)*65536, +            spacer             = "500 units", +            encodingbytes      = 2, +            filename           = filename, +            fontname           = fontname, +            fullname           = fullname, +            psname             = fontname or fullname, +            name               = filename or fullname, +            units              = units, +            format             = fonts.fontformat(filename,"opentype"), +            cidinfo            = cidinfo, +            ascender           = abs(metadata.ascent  or 0), +            descender          = abs(metadata.descent or 0), +            spacer             = spacer, +            italicangle        = italicangle, +        }      else          return nil      end diff --git a/otfl-font-otn.lua b/otfl-font-otn.lua index d4f89ad..4402dd6 100644 --- a/otfl-font-otn.lua +++ b/otfl-font-otn.lua @@ -1882,6 +1882,9 @@ end  local resolved = { } -- we only resolve a font,script,language pair once  -- todo: pass all these 'locals' in a table +-- +-- dynamics will be isolated some day ... for the moment we catch attribute zero +-- not being set  function fonts.methods.node.otf.features(head,font,attr)      if trace_steps then @@ -1926,8 +1929,7 @@ function fonts.methods.node.otf.features(head,font,attr)      local ra  = rl      [attr]     if ra == nil then ra  = { } rl      [attr]     = ra  end -- attr can be false      -- sequences always > 1 so no need for optimization      for s=1,#sequences do -        local pardir, txtdir = 0, { } -        local success = false +        local pardir, txtdir, success = 0, { }, false          local sequence = sequences[s]          local r = ra[s] -- cache          if r == nil then @@ -1994,24 +1996,33 @@ function fonts.methods.node.otf.features(head,font,attr)                  while start do                      local id = start.id                      if id == glyph then -                        if start.subtype<256 and start.font == font and (not attr or has_attribute(start,0,attr)) then ---~                         if start.subtype<256 and start.font == font and has_attribute(start,0,attr) then -                            for i=1,#subtables do -                                local lookupname = subtables[i] -                                local lookupcache = thecache[lookupname] -                                if lookupcache then -                                    local lookupmatch = lookupcache[start.char] -                                    if lookupmatch then -                                        start, success = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,i) -                                        if success then -                                            break +                        if start.subtype<256 and start.font == font then +                            local a = has_attribute(start,0) +                            if a then +                                a = a == attr +                            else +                                a = true +                            end +                            if a then +                                for i=1,#subtables do +                                    local lookupname = subtables[i] +                                    local lookupcache = thecache[lookupname] +                                    if lookupcache then +                                        local lookupmatch = lookupcache[start.char] +                                        if lookupmatch then +                                            start, success = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,i) +                                            if success then +                                                break +                                            end                                          end +                                    else +                                        report_missing_cache(typ,lookupname)                                      end -                                else -                                    report_missing_cache(typ,lookupname)                                  end +                                if start then start = start.prev end +                            else +                                start = start.prev                              end -                            if start then start = start.prev end                          else                              start = start.prev                          end @@ -2034,18 +2045,27 @@ function fonts.methods.node.otf.features(head,font,attr)                          while start do                              local id = start.id                              if id == glyph then ---~                                 if start.font == font and start.subtype<256 and has_attribute(start,0,attr) and (not attribute or has_attribute(start,state,attribute)) then -                                if start.font == font and start.subtype<256 and (not attr or has_attribute(start,0,attr)) and (not attribute or has_attribute(start,state,attribute)) then -                                    local lookupmatch = lookupcache[start.char] -                                    if lookupmatch then -                                        -- sequence kan weg -                                        local ok -                                        start, ok = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,1) -                                        if ok then -                                            success = true +                                if start.subtype<256 and start.font == font then +                                    local a = has_attribute(start,0) +                                    if a then +                                        a = (a == attr) and (not attribute or has_attribute(start,state,attribute)) +                                    else +                                        a = not attribute or has_attribute(start,state,attribute) +                                    end +                                    if a then +                                        local lookupmatch = lookupcache[start.char] +                                        if lookupmatch then +                                            -- sequence kan weg +                                            local ok +                                            start, ok = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,1) +                                            if ok then +                                                success = true +                                            end                                          end +                                        if start then start = start.next end +                                    else +                                        start = start.next                                      end -                                    if start then start = start.next end                                  else                                      start = start.next                                  end @@ -2109,27 +2129,36 @@ function fonts.methods.node.otf.features(head,font,attr)                      while start do                          local id = start.id                          if id == glyph then -                            if start.subtype<256 and start.font == font and (not attr or has_attribute(start,0,attr)) and (not attribute or has_attribute(start,state,attribute)) then ---~                             if start.subtype<256 and start.font == font and has_attribute(start,0,attr) and (not attribute or has_attribute(start,state,attribute)) then -                                for i=1,ns do -                                    local lookupname = subtables[i] -                                    local lookupcache = thecache[lookupname] -                                    if lookupcache then -                                        local lookupmatch = lookupcache[start.char] -                                        if lookupmatch then -                                            -- we could move all code inline but that makes things even more unreadable -                                            local ok -                                            start, ok = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,i) -                                            if ok then -                                                success = true -                                                break +                            if start.subtype<256 and start.font == font then +                                local a = has_attribute(start,0) +                                if a then +                                    a = (a == attr) and (not attribute or has_attribute(start,state,attribute)) +                                else +                                    a = not attribute or has_attribute(start,state,attribute) +                                end +                                if a then +                                    for i=1,ns do +                                        local lookupname = subtables[i] +                                        local lookupcache = thecache[lookupname] +                                        if lookupcache then +                                            local lookupmatch = lookupcache[start.char] +                                            if lookupmatch then +                                                -- we could move all code inline but that makes things even more unreadable +                                                local ok +                                                start, ok = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,i) +                                                if ok then +                                                    success = true +                                                    break +                                                end                                              end +                                        else +                                            report_missing_cache(typ,lookupname)                                          end -                                    else -                                        report_missing_cache(typ,lookupname)                                      end +                                    if start then start = start.next end +                                else +                                    start = start.next                                  end -                                if start then start = start.next end                              else                                  start = start.next                              end @@ -2150,7 +2179,6 @@ function fonts.methods.node.otf.features(head,font,attr)                          --     end                          elseif id == whatsit then                              local subtype = start.subtype -                            local subtype = start.subtype                              if subtype == 7 then                                  local dir = start.dir                                  if     dir == "+TRT" or dir == "+TLT" then diff --git a/otfl-font-tfm.lua b/otfl-font-tfm.lua index 31ae2ca..560ba1c 100644 --- a/otfl-font-tfm.lua +++ b/otfl-font-tfm.lua @@ -52,6 +52,8 @@ tfm.fontname_mode    = "fullpath"  tfm.enhance = tfm.enhance or function() end +fonts.formats.tfm = "type1" -- we need to have at least a value here +  function tfm.read_from_tfm(specification)      local fname, tfmdata = specification.filename or "", nil      if fname ~= "" then @@ -391,6 +393,9 @@ t.colorscheme = tfmtable.colorscheme              local vn = v.next              if vn then                  chr.next = vn +            --~ if v.vert_variants or v.horiz_variants then +            --~     logs.report("glyph 0x%05X has combination of next, vert_variants and horiz_variants",index) +            --~ end              else                  local vv = v.vert_variants                  if vv then diff --git a/otfl-luat-dum.lua b/otfl-luat-dum.lua index 3946b6f..0737762 100644 --- a/otfl-luat-dum.lua +++ b/otfl-luat-dum.lua @@ -1,5 +1,5 @@  if not modules then modules = { } end modules ['luat-dum'] = { -    version   = 1.001, +    version   = 1.100,      comment   = "companion to luatex-*.tex",      author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",      copyright = "PRAGMA ADE / ConTeXt Development Team", @@ -80,29 +80,80 @@ end  -- usage as I don't want any dependency at all. Also, ConTeXt might have  -- different needs and tricks added. +--~ containers.usecache = true +  caches = { } ---~ containers.usecache = true +local writable, readables = nil, { } + +if not caches.namespace or caches.namespace == "" or caches.namespace == "context" then +    caches.namespace = 'generic' +end + +do + +    local cachepaths = kpse.expand_path('$TEXMFCACHE') or "" + +    if cachepaths == "" then +        cachepaths = kpse.expand_path('$VARTEXMF') +    end + +    if cachepaths == "" then +        cachepaths = "." +    end + +    cachepaths = string.split(cachepaths,os.type == "windows" and ";" or ":") -function caches.setpath(category,subcategory) ---  local root = kpse.var_value("TEXMFCACHE") or "" ---  if root == "" then ---      root = kpse.var_value("VARTEXMF") or "" ---  end -    local var  = kpse.var_value("TEXMFVAR") -    local root = var and (var .. "/luatex/generic/luaotfload/") or "" -    if root ~= "" then -        root = file.join(root,category) -        lfs.mkdir(root) -        root = file.join(root,subcategory) -        lfs.mkdir(root) -        return lfs.isdir(root) and root +    for i=1,#cachepaths do +        if file.iswritable(cachepaths[i]) then +            writable = file.join(cachepaths[i],"luatex-cache") +            lfs.mkdir(writable) +            writable = file.join(writable,caches.namespace) +            lfs.mkdir(writable) +            break +        end      end + +    for i=1,#cachepaths do +        if file.isreadable(cachepaths[i]) then +            readables[#readables+1] = file.join(cachepaths[i],"luatex-cache",caches.namespace) +        end +    end + +    if not writable then +        texio.write_nl("quiting: fix your writable cache path") +        os.exit() +    elseif #readables == 0 then +        texio.write_nl("quiting: fix your readable cache path") +        os.exit() +    elseif #readables == 1 and readables[1] == writable then +        texio.write(string.format("(using cache: %s)",writable)) +    else +        texio.write(string.format("(using write cache: %s)",writable)) +        texio.write(string.format("(using read cache: %s)",table.concat(readables, " "))) +    end + +end + +function caches.getwritablepath(category,subcategory) +    local path = file.join(writable,category) +    lfs.mkdir(path) +    path = file.join(path,subcategory) +    lfs.mkdir(path) +    return path +end + +function caches.getreadablepaths(category,subcategory) +    local t = { } +    for i=1,#readables do +        t[i] = file.join(readables[i],category,subcategory) +    end +    return t  end  local function makefullname(path,name)      if path and path ~= "" then -        name = "temp-" and name -- clash prevention +        name = "temp-" .. name -- clash prevention          return file.addsuffix(file.join(path,name),"lua")      end  end @@ -112,17 +163,21 @@ function caches.iswritable(path,name)      return fullname and file.iswritable(fullname)  end -function caches.loaddata(path,name) -    local fullname = makefullname(path,name) -    if fullname then -        local data = loadfile(fullname) -        return data and data() +function caches.loaddata(paths,name) +    for i=1,#paths do +        local fullname = makefullname(paths[i],name) +        if fullname then +            texio.write(string.format("(load: %s)",fullname)) +            local data = loadfile(fullname) +            return data and data() +        end      end  end  function caches.savedata(path,name,data)      local fullname = makefullname(path,name)      if fullname then +        texio.write(string.format("(save: %s)",fullname))          table.tofile(fullname,data,'return',false,true,false)      end  end diff --git a/otfl-node-dum.lua b/otfl-node-dum.lua index f39a087..fbc8264 100644 --- a/otfl-node-dum.lua +++ b/otfl-node-dum.lua @@ -6,7 +6,19 @@ if not modules then modules = { } end modules ['node-dum'] = {      license   = "see context related readme files"  } -nodes = nodes or { } +nodes      = nodes      or { } +fonts      = fonts      or { } +attributes = attributes or { } + +local traverse_id = node.traverse_id +local free_node   = node.free +local remove_node = node.remove + +local glyph = node.id('glyph') + +-- fonts + +local fontdata = fonts.ids or { }  function nodes.simple_font_handler(head)  --  lang.hyphenate(head) @@ -17,3 +29,97 @@ function nodes.simple_font_handler(head)      head = node.kerning(head)      return head  end + +if tex.attribute[0] ~= 0 then + +    texio.write_nl("log","!") +    texio.write_nl("log","! Attribute 0 is reserved for ConTeXt's font feature management and has to be") +    texio.write_nl("log","! set to zero. Also, some attributes in the range 1-255 are used for special") +    texio.write_nl("log","! purposed so setting them at the TeX end might break the font handler.") +    texio.write_nl("log","!") + +    tex.attribute[0] = 0 -- else no features + +end + +nodes.protect_glyphs   = node.protect_glyphs +nodes.unprotect_glyphs = node.unprotect_glyphs + +function nodes.process_characters(head) +    local usedfonts, done, prevfont = { }, false, nil +    for n in traverse_id(glyph,head) do +        if font ~= prevfont then +            prevfont = font +            local used = usedfonts[font] +            if not used then +                local tfmdata = fontdata[font] +                if tfmdata then +                    local shared = tfmdata.shared -- we need to check shared, only when same features +                    if shared then +                        local processors = shared.processes +                        if processors and #processors > 0 then +                            usedfonts[font] = processors +                            done = true +                        end +                    end +                end +            end +        end +    end +    if done then +        for font, processors in next, usedfonts do +            for i=1,#processors do +                local h, d = processors[i](head,font,0) +                head, done = h or head, done or d +            end +        end +    end +    return head, true +end + +-- helper + +function nodes.kern(k) +    local n = new_node("kern",1) +    n.kern = k +    return n +end + +function nodes.remove(head, current, free_too) +   local t = current +   head, current = remove_node(head,current) +   if t then +        if free_too then +            free_node(t) +            t = nil +        else +            t.next, t.prev = nil, nil +        end +   end +   return head, current, t +end + +function nodes.delete(head,current) +    return nodes.remove(head,current,true) +end + +nodes.before = node.insert_before +nodes.after  = node.insert_after + +-- attributes + +attributes.unsetvalue = -0x7FFFFFFF + +local numbers, last = { }, 127 + +function attributes.private(name) +    local number = numbers[name] +    if not number then +        if last < 255 then +            last = last + 1 +        end +        number = last +        numbers[name] = number +    end +    return number +end diff --git a/otfl-node-fnt.lua b/otfl-node-fnt.lua deleted file mode 100644 index f2d8e1d..0000000 --- a/otfl-node-fnt.lua +++ /dev/null @@ -1,205 +0,0 @@ -if not modules then modules = { } end modules ['node-fnt'] = { -    version   = 1.001, -    comment   = "companion to font-ini.mkiv", -    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", -    copyright = "PRAGMA ADE / ConTeXt Development Team", -    license   = "see context related readme files" -} - -local next, type = next, type - -local trace_characters = false  trackers.register("nodes.characters", function(v) trace_characters = v end) - -local glyph = node.id('glyph') - -local traverse_id   = node.traverse_id -local has_attribute = node.has_attribute - -local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming - -fonts     = fonts      or { } -fonts.tfm = fonts.tfm  or { } -fonts.ids = fonts.ids  or { } - -local fontdata = fonts.ids - --- some tests with using an array of dynamics[id] and processes[id] demonstrated --- that there was nothing to gain (unless we also optimize other parts) --- --- maybe getting rid of the intermediate shared can save some time - --- potential speedup: check for subtype < 256 so that we can remove that test --- elsewhere, danger: injected nodes will not be dealt with but that does not --- happen often; we could consider processing sublists but that might need mor --- checking later on; the current approach also permits variants - -if tex.attribute[0] < 0 then - -    texio.write_nl("log","!") -    texio.write_nl("log","! Attribute 0 is reserved for ConTeXt's font feature management and has to be") -    texio.write_nl("log","! set to zero. Also, some attributes in the range 1-255 are used for special") -    texio.write_nl("log","! purposed so setting them at the TeX end might break the font handler.") -    texio.write_nl("log","!") - -    tex.attribute[0] = 0 -- else no features - -end - -function nodes.process_characters(head) -    -- either next or not, but definitely no already processed list -    starttiming(nodes) -    local usedfonts, attrfonts, done = { }, { }, false -    local a, u, prevfont, prevattr = 0, 0, nil, 0 -    for n in traverse_id(glyph,head) do -        local font, attr = n.font, has_attribute(n,0) -- zero attribute is reserved for fonts in context -        if attr and attr > 0 then -            if font ~= prevfont or attr ~= prevattr then -                local used = attrfonts[font] -                if not used then -                    used = { } -                    attrfonts[font] = used -                end -                if not used[attr] then -                    -- we do some testing outside the function -                    local tfmdata = fontdata[font] -                    local shared = tfmdata.shared -                    if shared then -                        local dynamics = shared.dynamics -                        if dynamics then -                            local d = shared.set_dynamics(font,dynamics,attr) -- still valid? -                            if d then -                                used[attr] = d -                                a = a + 1 -                            end -                        end -                    end -                end -                prevfont, prevattr = font, attr -            end -        elseif font ~= prevfont then -            prevfont, prevattr = font, 0 -            local used = usedfonts[font] -            if not used then -                local tfmdata = fontdata[font] -                if tfmdata then -                    local shared = tfmdata.shared -- we need to check shared, only when same features -                    if shared then -                        local processors = shared.processes -                        if processors and #processors > 0 then -                            usedfonts[font] = processors -                            u = u + 1 -                        end -                    end -                else -                    -- probably nullfont -                end -            end -        else -            prevattr = attr -        end -    end -    -- we could combine these and just make the attribute nil -    if u == 1 then -        local font, processors = next(usedfonts) -        local n = #processors -        if n > 0 then -            local h, d = processors[1](head,font,false) -            head, done = h or head, done or d -            if n > 1 then -                for i=2,n do -                    local h, d = processors[i](head,font,false) -                    head, done = h or head, done or d -                end -            end -        end -    elseif u > 0 then -        for font, processors in next, usedfonts do -            local n = #processors -            local h, d = processors[1](head,font,false) -            head, done = h or head, done or d -            if n > 1 then -                for i=2,n do -                    local h, d = processors[i](head,font,false) -                    head, done = h or head, done or d -                end -            end -        end -    end -    if a == 1 then -        local font, dynamics = next(attrfonts) -        for attribute, processors in next, dynamics do -- attr can switch in between -            local n = #processors -            local h, d = processors[1](head,font,attribute) -            head, done = h or head, done or d -            if n > 1 then -                for i=2,n do -                    local h, d = processors[i](head,font,attribute) -                    head, done = h or head, done or d -                end -            end -        end -    elseif a > 0 then -        for font, dynamics in next, attrfonts do -            for attribute, processors in next, dynamics do -- attr can switch in between -                local n = #processors -                local h, d = processors[1](head,font,attribute) -                head, done = h or head, done or d -                if n > 1 then -                    for i=2,n do -                        local h, d = processors[i](head,font,attribute) -                        head, done = h or head, done or d -                    end -                end -            end -        end -    end -    stoptiming(nodes) -    if trace_characters then -        nodes.report(head,done) -    end -    return head, true -end - -if node.protect_glyphs then - -    nodes.protect_glyphs   = node.protect_glyphs -    nodes.unprotect_glyphs = node.unprotect_glyphs - -else do - -    -- initial value subtype     : X000 0001 =  1 = 0x01 = char -    -- -    -- expected before linebreak : X000 0000 =  0 = 0x00 = glyph -    --                             X000 0010 =  2 = 0x02 = ligature -    --                             X000 0100 =  4 = 0x04 = ghost -    --                             X000 1010 = 10 = 0x0A = leftboundary lig -    --                             X001 0010 = 18 = 0x12 = rightboundary lig -    --                             X001 1010 = 26 = 0x1A = both boundaries lig -    --                             X000 1100 = 12 = 0x1C = leftghost -    --                             X001 0100 = 20 = 0x14 = rightghost - -    function nodes.protect_glyphs(head) -        local done = false -        for g in traverse_id(glyph,head) do -            local s = g.subtype -            if s == 1 then -                done, g.subtype = true, 256 -            elseif s <= 256 then -                done, g.subtype = true, 256 + s -            end -        end -        return done -    end - -    function nodes.unprotect_glyphs(head) -        local done = false -        for g in traverse_id(glyph,head) do -            local s = g.subtype -            if s > 256 then -                done, g.subtype = true, s - 256 -            end -        end -        return done -    end - -end end diff --git a/otfl-node-ini.lua b/otfl-node-ini.lua deleted file mode 100644 index 36e2402..0000000 --- a/otfl-node-ini.lua +++ /dev/null @@ -1,244 +0,0 @@ -if not modules then modules = { } end modules ['node-ini'] = { -    version   = 1.001, -    comment   = "companion to node-ini.mkiv", -    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", -    copyright = "PRAGMA ADE / ConTeXt Development Team", -    license   = "see context related readme files" -} - ---[[ldx-- -<p>Most of the code that had accumulated here is now separated in -modules.</p> ---ldx]]-- - --- this module is being reconstructed - -local utf = unicode.utf8 -local next, type = next, type -local format, concat, match, utfchar = string.format, table.concat, string.match, utf.char - -local chardata = characters and characters.data - ---[[ldx-- -<p>We start with a registration system for atributes so that we can use the -symbolic names later on.</p> ---ldx]]-- - -attributes = attributes or { } - -attributes.names      = attributes.names   or { } -attributes.numbers    = attributes.numbers or { } -attributes.list       = attributes.list    or { } -attributes.unsetvalue = -0x7FFFFFFF - -storage.register("attributes/names",   attributes.names,   "attributes.names") -storage.register("attributes/numbers", attributes.numbers, "attributes.numbers") -storage.register("attributes/list",    attributes.list,    "attributes.list") - -local names, numbers, list = attributes.names, attributes.numbers, attributes.list - -function attributes.define(name,number) -- at the tex end -    if not numbers[name] then -        numbers[name], names[number], list[number] = number, name, { } -    end -end - ---[[ldx-- -<p>We can use the attributes in the range 127-255 (outside user space). These -are only used when no attribute is set at the \TEX\ end which normally -happens in <l n='context'/>.</p> ---ldx]]-- - -storage.shared.attributes_last_private = storage.shared.attributes_last_private or 127 - -function attributes.private(name) -- at the lua end (hidden from user) -    local number = numbers[name] -    if not number then -        local last = storage.shared.attributes_last_private or 127 -        if last < 255 then -            last = last + 1 -            storage.shared.attributes_last_private = last -        end -        number = last -        numbers[name], names[number], list[number] = number, name, { } -    end -    return number -end - ---[[ldx-- -<p>Access to nodes is what gives <l n='luatex'/> its power. Here we -implement a few helper functions. These functions are rather optimized.</p> ---ldx]]-- - ---[[ldx-- -<p>When manipulating node lists in <l n='context'/>, we will remove -nodes and insert new ones. While node access was implemented, we did -quite some experiments in order to find out if manipulating nodes -in <l n='lua'/> was feasible from the perspective of performance.</p> - -<p>First of all, we noticed that the bottleneck is more with excessive -callbacks (some gets called very often) and the conversion from and to -<l n='tex'/>'s datastructures. However, at the <l n='lua'/> end, we -found that inserting and deleting nodes in a table could become a -bottleneck.</p> - -<p>This resulted in two special situations in passing nodes back to -<l n='tex'/>: a table entry with value <type>false</type> is ignored, -and when instead of a table <type>true</type> is returned, the -original table is used.</p> - -<p>Insertion is handled (at least in <l n='context'/> as follows. When -we need to insert a node at a certain position, we change the node at -that position by a dummy node, tagged <type>inline</type> which itself -has_attribute the original node and one or more new nodes. Before we pass -back the list we collapse the list. Of course collapsing could be built -into the <l n='tex'/> engine, but this is a not so natural extension.</p> - -<p>When we collapse (something that we only do when really needed), we -also ignore the empty nodes. [This is obsolete!]</p> ---ldx]]-- - -nodes = nodes or { } - -local hlist   = node.id('hlist') -local vlist   = node.id('vlist') -local glyph   = node.id('glyph') -local glue    = node.id('glue') -local penalty = node.id('penalty') -local kern    = node.id('kern') -local whatsit = node.id('whatsit') - -local traverse_id        = node.traverse_id -local traverse           = node.traverse -local free_node          = node.free -local remove_node        = node.remove -local insert_node_before = node.insert_before -local insert_node_after  = node.insert_after - -function nodes.remove(head, current, free_too) -   local t = current -   head, current = remove_node(head,current) -   if t then -        if free_too then -            free_node(t) -            t = nil -        else -            t.next, t.prev = nil, nil -        end -   end -   return head, current, t -end - -function nodes.delete(head,current) -    return nodes.remove(head,current,true) -end - -nodes.before = insert_node_before -nodes.after  = insert_node_after - --- we need to test this, as it might be fixed now - -function nodes.before(h,c,n) -    if c then -        if c == h then -            n.next = h -            n.prev = nil -            h.prev = n -        else -            local cp = c.prev -            n.next = c -            n.prev = cp -            if cp then -                cp.next = n -            end -            c.prev = n -            return h, n -        end -    end -    return n, n -end - -function nodes.after(h,c,n) -    if c then -        local cn = c.next -        if cn then -            n.next = cn -            cn.prev = n -        else -            n.next = nil -        end -        c.next = n -        n.prev = c -        return h, n -    end -    return n, n -end - --- local h, c = nodes.replace(head,current,new) --- local c = nodes.replace(false,current,new) --- local c = nodes.replace(current,new) - -function nodes.replace(head,current,new) -- no head returned if false -    if not new then -        head, current, new = false, head, current -    end -    local prev, next = current.prev, current.next -    if next then -        new.next, next.prev = next, new -    end -    if prev then -        new.prev, prev.next = prev, new -    end -    if head then -        if head == current then -            head = new -        end -        free_node(current) -        return head, new -    else -        free_node(current) -        return new -    end -end - --- will move - -local function count(stack,flat) -    local n = 0 -    while stack do -        local id = stack.id -        if not flat and id == hlist or id == vlist then -            local list = stack.list -            if list then -                n = n + 1 + count(list) -- self counts too -            else -                n = n + 1 -            end -        else -            n = n + 1 -        end -        stack  = stack.next -    end -    return n -end - -nodes.count = count - --- new, will move - -function attributes.ofnode(n) -    local a = n.attr -    if a then -        local names = attributes.names -        a = a.next -        while a do -            local number, value = a.number, a.value -            texio.write_nl(format("%s : attribute %3i, value %4i, name %s",tostring(n),number,value,names[number] or '?')) -            a = a.next -        end -   end -end - -local left, space = lpeg.P("<"), lpeg.P(" ") - -nodes.filterkey = left * (1-left)^0 * left * space^0 * lpeg.C((1-space)^0) diff --git a/otfl-node-inj.lua b/otfl-node-inj.lua index 9c4612a..579a266 100644 --- a/otfl-node-inj.lua +++ b/otfl-node-inj.lua @@ -342,39 +342,21 @@ function nodes.inject_kerns(head,where,keep)                   -- only w can be nil, can be sped up when w == nil                      local rl, x, w, r2l = k[1], k[2] or 0, k[4] or 0, k[6]                      local wx = w - x ---~                     if rl < 0 then ---~                         if r2l then ---~                             if wx ~= 0 then ---~                                 insert_node_before(head,n,newkern(wx)) ---~                             end ---~                             if x ~= 0 then ---~                                 insert_node_after (head,n,newkern(x)) ---~                             end ---~                         else ---~                             if x ~= 0 then ---~                                 insert_node_before(head,n,newkern(x)) ---~                             end ---~                             if wx ~= 0 then ---~                                 insert_node_after(head,n,newkern(wx)) ---~                             end ---~                         end ---~                     else -                        if r2l then -                            if wx ~= 0 then -                                insert_node_before(head,n,newkern(wx)) -                            end -                            if x ~= 0 then -                                insert_node_after (head,n,newkern(x)) -                            end -                        else -                            if x ~= 0 then -                                insert_node_before(head,n,newkern(x)) -                            end -                            if wx ~= 0 then -                                insert_node_after(head,n,newkern(wx)) -                            end +                    if r2l then +                        if wx ~= 0 then +                            insert_node_before(head,n,newkern(wx)) +                        end +                        if x ~= 0 then +                            insert_node_after (head,n,newkern(x)) +                        end +                    else +                        if x ~= 0 then +                            insert_node_before(head,n,newkern(x)) +                        end +                        if wx ~= 0 then +                            insert_node_after(head,n,newkern(wx))                          end ---~                     end +                    end                  end              end              if next(cx) then @@ -413,39 +395,21 @@ function nodes.inject_kerns(head,where,keep)                          -- copied from above                          local r2l = kk[6]                          local wx = w - x ---~                         if rl < 0 then ---~                             if r2l then ---~                                 if x ~= 0 then ---~                                     insert_node_before(head,n,newkern(x)) ---~                                 end ---~                                 if wx ~= 0 then ---~                                     insert_node_after(head,n,newkern(wx)) ---~                                 end ---~                             else ---~                                 if wx ~= 0 then ---~                                     insert_node_before(head,n,newkern(wx)) ---~                                 end ---~                                 if x ~= 0 then ---~                                     insert_node_after (head,n,newkern(x)) ---~                                 end ---~                             end ---~                         else -                            if r2l then -                                if wx ~= 0 then -                                    insert_node_before(head,n,newkern(wx)) -                                end -                                if x ~= 0 then -                                    insert_node_after (head,n,newkern(x)) -                                end -                            else -                                if x ~= 0 then -                                    insert_node_before(head,n,newkern(x)) -                                end -                                if wx ~= 0 then -                                    insert_node_after(head,n,newkern(wx)) -                                end +                        if r2l then +                            if wx ~= 0 then +                                insert_node_before(head,n,newkern(wx)) +                            end +                            if x ~= 0 then +                                insert_node_after (head,n,newkern(x)) +                            end +                        else +                            if x ~= 0 then +                                insert_node_before(head,n,newkern(x))                              end ---~                         end +                            if wx ~= 0 then +                                insert_node_after(head,n,newkern(wx)) +                            end +                        end                      else                          -- simple (e.g. kernclass kerns)                          if x ~= 0 then diff --git a/otfl-node-res.lua b/otfl-node-res.lua deleted file mode 100644 index a8ea874..0000000 --- a/otfl-node-res.lua +++ /dev/null @@ -1,302 +0,0 @@ -if not modules then modules = { } end modules ['node-res'] = { -    version   = 1.001, -    comment   = "companion to node-ini.mkiv", -    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", -    copyright = "PRAGMA ADE / ConTeXt Development Team", -    license   = "see context related readme files" -} - -local gmatch, format = string.gmatch, string.format -local copy_node, free_node, free_list, new_node, node_type, node_id = node.copy, node.free, node.flush_list, node.new, node.type, node.id -local tonumber, round = tonumber, math.round - -local glyph_node = node_id("glyph") - ---[[ldx-- -<p>The next function is not that much needed but in <l n='context'/> we use -for debugging <l n='luatex'/> node management.</p> ---ldx]]-- - -nodes = nodes or { } - -nodes.whatsits = { } -- table.swapped(node.whatsits()) - -local reserved = { } -local whatsits = nodes.whatsits - -for k, v in next, node.whatsits() do -    whatsits[k], whatsits[v] = v, k -- two way -end - -local function register_node(n) -    reserved[#reserved+1] = n -    return n -end - -nodes.register = register_node - -function nodes.cleanup_reserved(nofboxes) -- todo -    nodes.tracers.steppers.reset() -- todo: make a registration subsystem -    local nr, nl = #reserved, 0 -    for i=1,nr do -        local ri = reserved[i] -    --  if not (ri.id == glue_spec and not ri.is_writable) then -            free_node(reserved[i]) -    --  end -    end -    if nofboxes then -        local tb = tex.box -        for i=0,nofboxes do -            local l = tb[i] -            if l then -                free_node(tb[i]) -                nl = nl + 1 -            end -        end -    end -    reserved = { } -    return nr, nl, nofboxes -- can be nil -end - -function nodes.usage() -    local t = { } -    for n, tag in gmatch(status.node_mem_usage,"(%d+) ([a-z_]+)") do -        t[tag] = n -    end -    return t -end - -local disc              = register_node(new_node("disc")) -local kern              = register_node(new_node("kern",1)) -local penalty           = register_node(new_node("penalty")) -local glue              = register_node(new_node("glue")) -- glue.spec = nil -local glue_spec         = register_node(new_node("glue_spec")) -local glyph             = register_node(new_node("glyph",0)) -local textdir           = register_node(new_node("whatsit",whatsits.dir)) -- 7 (6 is local par node) -local rule              = register_node(new_node("rule")) -local latelua           = register_node(new_node("whatsit",whatsits.late_lua)) -- 35 -local user_n            = register_node(new_node("whatsit",whatsits.user_defined)) user_n.type = 100 -- 44 -local user_l            = register_node(new_node("whatsit",whatsits.user_defined)) user_l.type = 110 -- 44 -local user_s            = register_node(new_node("whatsit",whatsits.user_defined)) user_s.type = 115 -- 44 -local user_t            = register_node(new_node("whatsit",whatsits.user_defined)) user_t.type = 116 -- 44 -local left_margin_kern  = register_node(new_node("margin_kern",0)) -local right_margin_kern = register_node(new_node("margin_kern",1)) -local lineskip          = register_node(new_node("glue",1)) -local baselineskip      = register_node(new_node("glue",2)) -local leftskip          = register_node(new_node("glue",8)) -local rightskip         = register_node(new_node("glue",9)) -local temp              = register_node(new_node("temp",0)) - -function nodes.zeroglue(n) -    local s = n.spec -    return not writable or ( -                     s.width == 0 -         and       s.stretch == 0 -         and        s.shrink == 0 -         and s.stretch_order == 0 -         and  s.shrink_order == 0 -        ) -end - -function nodes.glyph(fnt,chr) -    local n = copy_node(glyph) -    if fnt then n.font = fnt end -    if chr then n.char = chr end -    return n -end - -function nodes.penalty(p) -    local n = copy_node(penalty) -    n.penalty = p -    return n -end - -function nodes.kern(k) -    local n = copy_node(kern) -    n.kern = k -    return n -end - -function nodes.glue_spec(width,stretch,shrink) -    local s = copy_node(glue_spec) -    s.width, s.stretch, s.shrink = width, stretch, shrink -    return s -end - -local function someskip(skip,width,stretch,shrink) -    local n = copy_node(skip) -    if not width then -        -- no spec -    elseif tonumber(width) then -        local s = copy_node(glue_spec) -        s.width, s.stretch, s.shrink = width, stretch, shrink -        n.spec = s -    else -        -- shared -        n.spec = copy_node(width) -    end -    return n -end - -function nodes.glue(width,stretch,shrink) -    return someskip(glue,width,stretch,shrink) -end -function nodes.leftskip(width,stretch,shrink) -    return someskip(leftskip,width,stretch,shrink) -end -function nodes.rightskip(width,stretch,shrink) -    return someskip(rightskip,width,stretch,shrink) -end -function nodes.lineskip(width,stretch,shrink) -    return someskip(lineskip,width,stretch,shrink) -end -function nodes.baselineskip(width,stretch,shrink) -    return someskip(baselineskip,width,stretch,shrink) -end - -function nodes.disc() -    return copy_node(disc) -end - -function nodes.textdir(dir) -    local t = copy_node(textdir) -    t.dir = dir -    return t -end - -function nodes.rule(width,height,depth,dir) -    local n = copy_node(rule) -    if width  then n.width  = width  end -    if height then n.height = height end -    if depth  then n.depth  = depth  end -    if dir    then n.dir    = dir    end -    return n -end - -function nodes.latelua(code) -    local n = copy_node(latelua) -    n.data = code -    return n -end - -function nodes.leftmarginkern(glyph,width) -    local n = copy_node(left_margin_kern) -    if not glyph then -        logs.fatal("nodes","invalid pointer to left margin glyph node") -    elseif glyph.id ~= glyph_node then -        logs.fatal("nodes","invalid node type %s for left margin glyph node",node_type(glyph)) -    else -        n.glyph = glyph -    end -    if width then -        n.width = width -    end -    return n -end - -function nodes.rightmarginkern(glyph,width) -    local n = copy_node(right_margin_kern) -    if not glyph then -        logs.fatal("nodes","invalid pointer to right margin glyph node") -    elseif glyph.id ~= glyph_node then -        logs.fatal("nodes","invalid node type %s for right margin glyph node",node_type(p)) -    else -        n.glyph = glyph -    end -    if width then -        n.width = width -    end -    return n -end - -function nodes.temp() -    return copy_node(temp) -end ---[[ -<p>At some point we ran into a problem that the glue specification -of the zeropoint dimension was overwritten when adapting a glue spec -node. This is a side effect of glue specs being shared. After a -couple of hours tracing and debugging Taco and I came to the -conclusion that it made no sense to complicate the spec allocator -and settled on a writable flag. This all is a side effect of the -fact that some glues use reserved memory slots (with the zeropoint -glue being a noticeable one). So, next we wrap this into a function -and hide it for the user. And yes, LuaTeX now gives a warning as -well.</p> -]]-- - -if tex.luatexversion > 51 then - -    function nodes.writable_spec(n) -        local spec = n.spec -        if not spec then -            spec = copy_node(glue_spec) -            n.spec = spec -        elseif not spec.writable then -            spec = copy_node(spec) -            n.spec = spec -        end -        return spec -    end - -else - -    function nodes.writable_spec(n) -        local spec = n.spec -        if not spec then -            spec = copy_node(glue_spec) -        else -            spec = copy_node(spec) -        end -        n.spec = spec -        return spec -    end - -end - -local cache = { } - -function nodes.usernumber(num) -    local n = cache[num] -    if n then -        return copy_node(n) -    else -        local n = copy_node(user_n) -        if num then n.value = num end -        return n -    end -end - -function nodes.userlist(list) -    local n = copy_node(user_l) -    if list then n.value = list end -    return n -end - -local cache = { } -- we could use the same cache - -function nodes.userstring(str) -    local n = cache[str] -    if n then -        return copy_node(n) -    else -        local n = copy_node(user_s) -        n.type = 115 -        if str then n.value = str end -        return n -    end -end - -function nodes.usertokens(tokens) -    local n = copy_node(user_t) -    if tokens then n.value = tokens end -    return n -end - -statistics.register("cleaned up reserved nodes", function() -    return format("%s nodes, %s lists of %s", nodes.cleanup_reserved(tex.count["lastallocatedbox"])) -end) -- \topofboxstack - -statistics.register("node memory usage", function() -- comes after cleanup ! -    return status.node_mem_usage -end) | 
