diff options
| -rw-r--r-- | README | 1 | ||||
| -rw-r--r-- | luaotfload.dtx | 20 | ||||
| -rw-r--r-- | otfl-font-cid.lua | 1 | ||||
| -rw-r--r-- | otfl-font-def.lua | 27 | ||||
| -rw-r--r-- | otfl-font-dum.lua | 4 | ||||
| -rw-r--r-- | otfl-font-ini.lua | 5 | ||||
| -rw-r--r-- | otfl-font-map.lua | 218 | ||||
| -rw-r--r-- | otfl-font-otf.lua | 183 | ||||
| -rw-r--r-- | otfl-font-otn.lua | 4 | ||||
| -rw-r--r-- | otfl-font-ott.lua | 10 | ||||
| -rw-r--r-- | otfl-font-tfm.lua | 19 | ||||
| -rw-r--r-- | otfl-font-xtx.lua | 2 | ||||
| -rw-r--r-- | otfl-node-dum.lua | 13 | ||||
| -rw-r--r-- | otfl-node-ini.lua | 5 | ||||
| -rw-r--r-- | otfl-node-inj.lua | 298 | ||||
| -rw-r--r-- | otfl-node-res.lua | 14 | 
16 files changed, 467 insertions, 357 deletions
@@ -48,6 +48,7 @@ Source files:          otfl-font-ott.lua                       .          otfl-font-tfm.lua                       .          otfl-font-xtx.lua                       . +        otfl-font-map.lua                       .          otfl-luat-dum.lua                       .          otfl-node-dum.lua                       .          otfl-node-fnt.lua                       . diff --git a/luaotfload.dtx b/luaotfload.dtx index 6dceeb8..5f25675 100644 --- a/luaotfload.dtx +++ b/luaotfload.dtx @@ -162,9 +162,9 @@ and the derived files  % algorithm, for instance we can improve the font loading system; this is what  % we do in this package.  % -%This package is quite low-level, and should be loaded directly in the macro -%package, like it is in Con\TeX t. Sadly, Plain and \LaTeX\ are frozen and -%it's even impossible to adapt them to the new engines.  +% This package is quite low-level, and should be loaded directly in the macro +% package, like it is in Con\TeX t. Sadly, Plain and \LaTeX\ are frozen and +% it's even impossible to adapt them to the new engines.   %  % \subsection{Con\TeX t files needed}  % @@ -199,9 +199,18 @@ and the derived files  % \item \texttt{font-otc.lua}  % \item \texttt{font-def.lua}  % \item \texttt{font-xtx.lua} +% \item \texttt{font-map.lua}  % \item \texttt{font-dum.lua}  % \end{itemize}  %  +% \subsection{Troubleshooting} +% +% If you encounter problems with some fonts, please first update to the latest version of this package before reporting a bug, as this package is under active development. +% +% A very common problem is the lack of features for some otf fonts even when specified. It can be related to the fact that some fonts do not provide features for the |dflt| script, which is the default one in this package, so you may have to specify the script in the command line, for example: +% +% |\font\myfont = MyFont.otf:script=latn;+liga;| +%  % \section{\texttt{luaotfload.lua}}  %  % \iffalse @@ -398,6 +407,7 @@ do  end  luaotfload.loadmodule('font-xtx.lua') +luaotfload.loadmodule('font-map.lua')  luaotfload.loadmodule('font-dum.lua')  %    \end{macrocode} @@ -415,8 +425,6 @@ fonts.enc.known = {}  %    \begin{macrocode}  function luaotfload.register_callbacks() -    callback.add('ligaturing',           nodes.simple_font_dummy, 'luaotfload.ligaturing') -    callback.add('kerning',              nodes.simple_font_dummy, 'luaotfload.kerning')      callback.add('pre_linebreak_filter', nodes.simple_font_handler, 'luaotfload.pre_linebreak_filter')      callback.add('hpack_filter',         nodes.simple_font_handler, 'luaotfload.hpack_filter')      callback.reset('define_font') @@ -424,8 +432,6 @@ function luaotfload.register_callbacks()  end  function luaotfload.unregister_callbacks() -    callback.remove('ligaturing', 'luaotfload.ligaturing') -    callback.remove('kerning', 'luaotfload.kerning')      callback.remove('pre_linebreak_filter', 'luaotfload.pre_linebreak_filter')      callback.remove('hpack_filter', 'luaotfload.hpack_filter')      callback.remove('define_font', 'luaotfload.define_font') diff --git a/otfl-font-cid.lua b/otfl-font-cid.lua index b8dfc42..13e9cce 100644 --- a/otfl-font-cid.lua +++ b/otfl-font-cid.lua @@ -93,6 +93,7 @@ local function locate(registry,ordering,supplement)                      logs.report("load otf","using cidmap file %s",filename)                  end                  fonts.cid.map[filename] = cidmap +                cidmap.usedname = file.basename(filename)                  return cidmap              end          end diff --git a/otfl-font-def.lua b/otfl-font-def.lua index eca6311..3301c39 100644 --- a/otfl-font-def.lua +++ b/otfl-font-def.lua @@ -328,22 +328,18 @@ evolved. Each one has its own way of dealing with its format.</p>  --ldx]]--  local function check_tfm(specification,fullname) -    -- ofm directive blocks local path search unless set -    fullname = resolvers.findbinfile(fullname, 'tfm') or "" -- just to be sure -    if fullname ~= "" then -        specification.filename, specification.format = fullname, "ofm" +    -- ofm directive blocks local path search unless set; btw, in context we +    -- don't support ofm files anyway as this format is obsolete +    local foundname = resolvers.findbinfile(fullname, 'tfm') or "" -- just to be sure +    if foundname == "" then +        foundname = resolvers.findbinfile(fullname, 'ofm') or "" -- bonus for usage outside context +    end +    if foundname ~= "" then +        specification.filename, specification.format = foundname, "ofm"          return tfm.read_from_tfm(specification)      end  end ---~ local function check_afm(specification,fullname) ---~     fullname = resolvers.findbinfile(fullname, 'afm') or "" -- just to be sure ---~     if fullname ~= "" then ---~         specification.filename, specification.format = fullname, "afm" ---~         return tfm.read_from_afm(specification) ---~     end ---~ end -  local function check_afm(specification,fullname)      local foundname = resolvers.findbinfile(fullname, 'afm') or "" -- just to be sure      if foundname == "" and tfm.auto_afm then @@ -440,9 +436,10 @@ function readers.opentype(specification,suffix,what)      end  end -function readers.otf(specification) return readers.opentype(specification,"otf","opentype") end -function readers.ttf(specification) return readers.opentype(specification,"ttf","truetype") end -function readers.ttc(specification) return readers.opentype(specification,"ttf","truetype") end -- !! +function readers.otf  (specification) return readers.opentype(specification,"otf","opentype") end +function readers.ttf  (specification) return readers.opentype(specification,"ttf","truetype") end +function readers.ttc  (specification) return readers.opentype(specification,"ttf","truetype") end -- !! +function readers.dfont(specification) return readers.opentype(specification,"ttf","truetype") end -- !!  --[[ldx--  <p>We need to check for default features. For this we provide diff --git a/otfl-font-dum.lua b/otfl-font-dum.lua index 5ae53d0..ef267a4 100644 --- a/otfl-font-dum.lua +++ b/otfl-font-dum.lua @@ -60,7 +60,7 @@ function fonts.names.resolve(name,sub)                          local d = {  }                          for k, v in pairs(data.mapping) do                              local t = v[1] -                            if t == "ttf" or t == "otf" or t == "ttc" then +                            if t == "ttf" or t == "otf" or t == "ttc" or t == "dfont" then                                  d[k] = v                              end                          end @@ -73,7 +73,7 @@ function fonts.names.resolve(name,sub)          loaded = true      end      if type(data) == "table" and data.version == 1.08 then -        local condensed = string.gsub(name,"[^%a%d]","") +        local condensed = string.gsub(string.lower(name),"[^%a%d]","")          local found = data.mapping and data.mapping[condensed]          if found then              local filename, is_sub = found[3], found[4] diff --git a/otfl-font-ini.lua b/otfl-font-ini.lua index 248a2ba..4005726 100644 --- a/otfl-font-ini.lua +++ b/otfl-font-ini.lua @@ -27,6 +27,11 @@ fonts.mode    = 'base'  fonts.private = 0xF0000 -- 0x10FFFF  fonts.verbose = false -- more verbose cache tables +fonts.ids[0] = { -- nullfont +    characters   = { }, +    descriptions = { }, +} +  fonts.methods = fonts.methods or {      base = { tfm = { }, afm = { }, otf = { }, vtf = { }, fix = { } },      node = { tfm = { }, afm = { }, otf = { }, vtf = { }, fix = { }  }, diff --git a/otfl-font-map.lua b/otfl-font-map.lua new file mode 100644 index 0000000..c597d48 --- /dev/null +++ b/otfl-font-map.lua @@ -0,0 +1,218 @@ +if not modules then modules = { } end modules ['font-map'] = { +    version   = 1.001, +    comment   = "companion to font-ini.tex", +    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", +    copyright = "PRAGMA ADE / ConTeXt Development Team", +    license   = "see context related readme files" +} + +local match, format, find, concat = string.match, string.format, string.find, table.concat + +local trace_loading = false  trackers.register("otf.loading", function(v) trace_loading = v end) + +local ctxcatcodes = tex.ctxcatcodes + +--[[ldx-- +<p>Eventually this code will disappear because map files are kind +of obsolete. Some code may move to runtime or auxiliary modules.</p> +<p>The name to unciode related code will stay of course.</p> +--ldx]]-- + +fonts               = fonts               or { } +fonts.map           = fonts.map           or { } +fonts.map.data      = fonts.map.data      or { } +fonts.map.encodings = fonts.map.encodings or { } +fonts.map.done      = fonts.map.done      or { } +fonts.map.loaded    = fonts.map.loaded    or { } +fonts.map.direct    = fonts.map.direct    or { } +fonts.map.line      = fonts.map.line      or { } + +function fonts.map.line.pdfmapline(tag,str) +    return "\\loadmapline[" .. tag .. "][" .. str .. "]" +end + +function fonts.map.line.pdftex(e) -- so far no combination of slant and stretch +    if e.name and e.fontfile then +        local fullname = e.fullname or "" +        if e.slant and e.slant ~= 0 then +            if e.encoding then +                return fonts.map.line.pdfmapline("=",format('%s %s "%g SlantFont" <%s <%s',e.name,fullname,e.slant,e.encoding,e.fontfile)) +            else +                return fonts.map.line.pdfmapline("=",format('%s %s "%g SlantFont" <%s',e.name,fullname,e.slant,e.fontfile)) +            end +        elseif e.stretch and e.stretch ~= 1 and e.stretch ~= 0 then +            if e.encoding then +                return fonts.map.line.pdfmapline("=",format('%s %s "%g ExtendFont" <%s <%s',e.name,fullname,e.stretch,e.encoding,e.fontfile)) +            else +                return fonts.map.line.pdfmapline("=",format('%s %s "%g ExtendFont" <%s',e.name,fullname,e.stretch,e.fontfile)) +            end +        else +            if e.encoding then +                return fonts.map.line.pdfmapline("=",format('%s %s <%s <%s',e.name,fullname,e.encoding,e.fontfile)) +            else +                return fonts.map.line.pdfmapline("=",format('%s %s <%s',e.name,fullname,e.fontfile)) +            end +        end +    else +        return nil +    end +end + +function fonts.map.flush(backend) -- will also erase the accumulated data +    local flushline = fonts.map.line[backend or "pdftex"] or fonts.map.line.pdftex +    for _, e in pairs(fonts.map.data) do +        tex.sprint(ctxcatcodes,flushline(e)) +    end +    fonts.map.data = { } +end + +fonts.map.line.dvips     = fonts.map.line.pdftex +fonts.map.line.dvipdfmx  = function() end + +function fonts.map.convert_entries(filename) +    if not fonts.map.loaded[filename] then +        fonts.map.data, fonts.map.encodings = fonts.map.load_file(filename,fonts.map.data, fonts.map.encodings) +        fonts.map.loaded[filename] = true +    end +end + +function fonts.map.load_file(filename, entries, encodings) +    entries   = entries   or { } +    encodings = encodings or { } +    local f = io.open(filename) +    if f then +        local data = f:read("*a") +        if data then +            for line in gmatch(data,"(.-)[\n\t]") do +                if find(line,"^[%#%%%s]") then +                    -- print(line) +                else +                    local stretch, slant, name, fullname, fontfile, encoding +                    line = line:gsub('"(.+)"', function(s) +                        stretch = find(s,'"([^"]+) ExtendFont"') +                        slant = find(s,'"([^"]+) SlantFont"') +                        return "" +                    end) +                    if not name then +                        -- name fullname encoding fontfile +                        name, fullname, encoding, fontfile = match(line,"^(%S+)%s+(%S*)[%s<]+(%S*)[%s<]+(%S*)%s*$") +                    end +                    if not name then +                        -- name fullname (flag) fontfile encoding +                        name, fullname, fontfile, encoding = match(line,"^(%S+)%s+(%S*)[%d%s<]+(%S*)[%s<]+(%S*)%s*$") +                    end +                    if not name then +                        -- name fontfile +                        name, fontfile = match(line,"^(%S+)%s+[%d%s<]+(%S*)%s*$") +                    end +                    if name then +                        if encoding == "" then encoding = nil end +                        entries[name] = { +                            name     = name, -- handy +                            fullname = fullname, +                            encoding = encoding, +                            fontfile = fontfile, +                            slant    = tonumber(slant), +                            stretch  = tonumber(stretch) +                        } +                        encodings[name] = encoding +                    elseif line ~= "" then +                    --  print(line) +                    end +                end +            end +        end +        f:close() +    end +    return entries, encodings +end + +function fonts.map.load_lum_table(filename) +    local lumname = file.replacesuffix(file.basename(filename),"lum") +    local lumfile = resolvers.find_file(lumname,"map") or "" +    if lumfile ~= "" and lfs.isfile(lumfile) then +        if trace_loading or trace_unimapping then +            logs.report("load otf","enhance: loading %s ",lumfile) +        end +        lumunic = dofile(lumfile) +        return lumunic, lumfile +    end +end + +local hex     = lpeg.R("AF","09") +local hexfour = (hex*hex*hex*hex) / function(s) return tonumber(s,16) end +local dec     = (lpeg.R("09")^1) / tonumber +local period  = lpeg.P(".") + +local unicode = lpeg.P("uni")   * (hexfour * (period + lpeg.P(-1)) * lpeg.Cc(false) + lpeg.Ct(hexfour^1) * lpeg.Cc(true)) +local index   = lpeg.P("index") * dec * lpeg.Cc(false) + +local parser  = unicode + index + +local parsers = { } + +function fonts.map.make_name_parser(str) +    if not str or str == "" then +        return parser +    else +        local p = parsers[str] +        if not p then +            p = lpeg.P(str) * period * dec * lpeg.Cc(false) +            parsers[str] = p +        end +        return p +    end +end + +--~ local parser = fonts.map.make_name_parser("Japan1") +--~ local function test(str) +--~     local b, a = parser:match(str) +--~     print((a and table.serialize(b)) or b) +--~ end +--~ test("uni1234") +--~ test("uni1234.xx") +--~ test("uni12349876") +--~ test("index1234") +--~ test("Japan1.123") + +function fonts.map.tounicode16(unicode) +    if unicode < 0x10000 then +        return format("%04X",unicode) +    else +        return format("%04X%04X",unicode/1024+0xD800,unicode%1024+0xDC00) +    end +end + +function fonts.map.tounicode16sequence(unicodes) +    local t = { } +    for l=1,#unicodes do +        local unicode = unicodes[l] +        if unicode < 0x10000 then +            t[l] = format("%04X",unicode) +        else +            t[l] = format("%04X%04X",unicode/1024+0xD800,unicode%1024+0xDC00) +        end +    end +    return concat(t) +end + +--~ This is quite a bit faster but at the cost of some memory but if we +--~ do this we will also use it elsewhere so let's not follow this route +--~ now. I might use this method in the plain variant (no caching there) +--~ but then I need a flag that distinguishes between code branches. +--~ +--~ local cache = { } +--~ +--~ function fonts.map.tounicode16(unicode) +--~     local s = cache[unicode] +--~     if not s then +--~         if unicode < 0x10000 then +--~             s = format("%04X",unicode) +--~         else +--~             s = format("%04X%04X",unicode/1024+0xD800,unicode%1024+0xDC00) +--~         end +--~         cache[unicode] = s +--~     end +--~     return s +--~ end + diff --git a/otfl-font-otf.lua b/otfl-font-otf.lua index 00ac596..f3b3f54 100644 --- a/otfl-font-otf.lua +++ b/otfl-font-otf.lua @@ -12,12 +12,13 @@ local concat, getn, utfbyte = table.concat, table.getn, 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 trace_private   = false  trackers.register("otf.private",      function(v) trace_private      = v end) -local trace_loading   = false  trackers.register("otf.loading",      function(v) trace_loading      = v end) -local trace_features  = false  trackers.register("otf.features",     function(v) trace_features     = v end) -local trace_dynamics  = false  trackers.register("otf.dynamics",     function(v) trace_dynamics     = v end) -local trace_sequences = false  trackers.register("otf.sequences",    function(v) trace_sequences    = v end) -local trace_math      = false  trackers.register("otf.math",         function(v) trace_math         = v end) +local trace_private    = false  trackers.register("otf.private",      function(v) trace_private      = v end) +local trace_loading    = false  trackers.register("otf.loading",      function(v) trace_loading      = v end) +local trace_features   = false  trackers.register("otf.features",     function(v) trace_features     = v end) +local trace_dynamics   = false  trackers.register("otf.dynamics",     function(v) trace_dynamics     = v end) +local trace_sequences  = false  trackers.register("otf.sequences",    function(v) trace_sequences    = v end) +local trace_math       = false  trackers.register("otf.math",         function(v) trace_math         = v end) +local trace_unimapping = false  trackers.register("otf.unimapping",   function(v) trace_unimapping   = v end)  --~ trackers.enable("otf.loading") @@ -81,7 +82,7 @@ otf.features.default = otf.features.default or { }  otf.enhancers        = otf.enhancers        or { }  otf.glists           = { "gsub", "gpos" } -otf.version          = 2.626 -- beware: also sync font-mis.lua +otf.version          = 2.628 -- beware: also sync font-mis.lua  otf.pack             = true  -- beware: also sync font-mis.lua  otf.syncspace        = true  otf.notdef           = false @@ -464,15 +465,18 @@ otf.enhancers["analyse marks"] = function(data,filename)      end  end -local other = lpeg.C((1 - lpeg.S("_."))^0) -local ligsplitter = lpeg.Ct(other * (lpeg.P("_") * other)^0) +local separator   = lpeg.S("_.") +local other       = lpeg.C((1 - separator)^1) +local ligsplitter = lpeg.Ct(other * (separator * other)^0) ---~ print(splitter:match("this")) ---~ print(splitter:match("this.that")) ---~ print(splitter:match("such_so_more")) ---~ print(splitter:match("such_so_more.that")) +--~ print(table.serialize(ligsplitter:match("this"))) +--~ print(table.serialize(ligsplitter:match("this.that"))) +--~ print(table.serialize(ligsplitter:match("japan1.123"))) +--~ print(table.serialize(ligsplitter:match("such_so_more"))) +--~ print(table.serialize(ligsplitter:match("such_so_more.that")))  otf.enhancers["analyse unicodes"] = function(data,filename) +    local tounicode16, tounicode16sequence = fonts.map.tounicode16, fonts.map.tounicode16sequence      local unicodes = data.luatex.unicodes      -- we need to move this code      unicodes['space']  = unicodes['space']  or 32   -- handly later on @@ -482,53 +486,113 @@ otf.enhancers["analyse unicodes"] = function(data,filename)      -- the tounicode mapping is sparse and only needed for alternatives      local tounicode, originals, ns, nl, private, unknown = { }, { }, 0, 0, fonts.private, format("%04X",utfbyte("?"))      data.luatex.tounicode, data.luatex.originals = tounicode, originals +    local lumunic, uparser, oparser +    if false then -- will become an option +        lumunic = fonts.map.load_lum_table(filename) +        lumunic = lumunic and lumunic.tounicode +    end +    local cidinfo, cidnames, cidcodes = data.cidinfo +    local usedmap = cidinfo and cidinfo.usedname +    usedmap = usedmap and fonts.cid.map[usedmap] +    if usedmap then +        oparser = usedmap and fonts.map.make_name_parser(cidinfo.ordering) +        cidnames = usedmap.names +        cidcodes = usedmap.unicodes +    end +    uparser = fonts.map.make_name_parser()      for index, glyph in next, data.glyphs do          local name, unic = glyph.name, glyph.unicode or -1 -- play safe          if unic == -1 or unic >= private or (unic >= 0xE000 and unic <= 0xF8FF) or unic == 0xFFFE or unic == 0xFFFF then -            -- a.whatever or a_b_c.whatever or a_b_c -            local split = ligsplitter:match(name) -            if #split == 0 then -                -- skip -            elseif #split == 1 then -                local u = unicodes[split[1]] -                if u then -                    if type(u) == "table" then -                        u = u[1] -                    end -                    if u < 0x10000 then -                        originals[index], tounicode[index] = u, format("%04X",u) -                    else -                        originals[index], tounicode[index] = u, format("%04X%04X",u/1024+0xD800,u%1024+0xDC00) +            local unicode = lumunic and lumunic[name] +            if unicode then +                originals[index], tounicode[index], ns = unicode, tounicode16(unicode), ns + 1 +            end +            -- cidmap heuristics, beware, there is no guarantee for a match unless +            -- the chain resolves +            if not unicode and usedmap then +                local foundindex = oparser:match(name) +                if foundindex then +                    unicode = cidcodes[foundindex] -- name to number +                    if not unicode then +                        local reference = cidnames[foundindex] -- number to name +                        if reference then +                            local foundindex = oparser:match(reference) +                            if foundindex then +                                unicode = cidcodes[foundindex] +                                if unicode then +                                    originals[index], tounicode[index], ns = unicode, tounicode16(unicode), ns + 1 +                                end +                            end +                            if not unicode then +                                local foundcodes, multiple = uparser:match(reference) +                                if foundcodes then +                                    if multiple then +                                        originals[index], tounicode[index], nl, unicode = foundcodes, tounicode16sequence(foundcodes), nl + 1, true +                                    else +                                        originals[index], tounicode[index], ns, unicode = foundcodes, tounicode16(foundcodes), ns + 1, foundcodes +                                    end +                                end +                            end +                        end                      end -                    ns = ns + 1 -                else -                    originals[index], tounicode[index] = 0xFFFD, "FFFD"                  end -            else -                local as = { } -                for l=1,#split do -                    local u = unicodes[split[l]] -                    if not u then -                        as[l], split[l] = 0xFFFD, "FFFD" -                    else -                        if type(u) == "table" then -                            u = u[1] +            end +            -- a.whatever or a_b_c.whatever or a_b_c (no numbers) +            if not unicode then +                local split = ligsplitter:match(name) +                local nplit = (split and #split) or 0 +                if nplit == 0 then +                    -- skip +                elseif nplit == 1 then +                    unicode = unicodes[split[1]] +                    if unicode then +                        if type(unicode) == "table" then +                            unicode = unicode[1]                          end -                        if u < 0x10000 then -                            as[l], split[l] = u, format("%04X",u) +                        originals[index], tounicode[index], ns = unicode, tounicode16(unicode), ns + 1 +                    end +                else +                    local done = true +                    for l=1,nplit do +                        local u = unicodes[split[l]] +                        if not u then +                            done = false +                            break +                        elseif type(u) == "table" then +                            split[l] = u[1]                          else -                            as[l], split[l] = u, format("%04X%04X",u/1024+0xD800,u%1024+0xDC00) +                            split[l] = u                          end                      end +                    if done then +                        originals[index], tounicode[index], nl, unicode = split, tounicode16sequence(split), nl + 1, true +                    end                  end -                split = concat(split) -                if split ~= "" then -                    originals[index], tounicode[index] = as, split -                    nl = nl + 1 -                else -                    originals[index], tounicode[index] = 0xFFFD, "FFFD" +            end +            -- last resort +            if not unicode then +                local foundcodes, multiple = uparser:match(name) +                if foundcodes then +                    if multiple then +                        originals[index], tounicode[index], nl, unicode = foundcodes, tounicode16sequence(foundcodes), nl + 1, true +                    else +                        originals[index], tounicode[index], ns, unicode = foundcodes, tounicode16(foundcodes), ns + 1, foundcodes +                    end                  end              end +            if not unicode then +                originals[index], tounicode[index] = 0xFFFD, "FFFD" +            end +        end +    end +    if trace_unimapping then +        for index, glyph in table.sortedpairs(data.glyphs) do +            local toun, name, unic = tounicode[index], glyph.name, glyph.unicode or -1 -- play safe +            if toun then +                logs.report("load otf","internal: 0x%05X, name: %s, unicode: 0x%05X, tounicode: %s",index,name,unic,toun) +            else +                logs.report("load otf","internal: 0x%05X, name: %s, unicode: 0x%05X",index,name,unic) +            end          end      end      if trace_loading and (ns > 0 or nl > 0) then @@ -546,16 +610,14 @@ otf.enhancers["analyse subtables"] = function(data,filename)      for _, g in next, { data.gsub, data.gpos } do          for k=1,#g do              local gk = g[k] - -local typ = gk.type -if typ == "gsub_contextchain" or typ == "gpos_contextchain" then -    gk.chain = 1 -elseif typ == "gsub_reversecontextchain" or typ == "gpos_reversecontextchain" then -    gk.chain = -1 -else -    gk.chain = 0 -end - +            local typ = gk.type +            if typ == "gsub_contextchain" or typ == "gpos_contextchain" then +                gk.chain = 1 +            elseif typ == "gsub_reversecontextchain" or typ == "gpos_reversecontextchain" then +                gk.chain = -1 +            else +                gk.chain = 0 +            end              local features = gk.features              if features then                  sequences[#sequences+1] = gk @@ -610,8 +672,9 @@ otf.enhancers["merge cid fonts"] = function(data,filename)          local cidinfo = data.cidinfo          local verbose = fonts.verbose          if cidinfo.registry then -            local cidmap = fonts.cid.getmap and fonts.cid.getmap(cidinfo.registry,cidinfo.ordering,cidinfo.supplement) +            local cidmap, cidname = fonts.cid.getmap(cidinfo.registry,cidinfo.ordering,cidinfo.supplement)              if cidmap then +                cidinfo.usedname = cidmap.usedname                  local glyphs, uni_to_int, int_to_uni, nofnames, nofunicodes = { }, { }, { }, 0, 0                  local unicodes, names = cidmap.unicodes, cidmap.names                  for n, subfont in next, data.subfonts do @@ -1343,7 +1406,7 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th          }          -- 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 +            characters[u] = { } -- we need this because for instance we add protruding info and loop over characters              descriptions[u] = glyphs[i]          end          -- math diff --git a/otfl-font-otn.lua b/otfl-font-otn.lua index 719c0ca..3c11b84 100644 --- a/otfl-font-otn.lua +++ b/otfl-font-otn.lua @@ -150,7 +150,7 @@ trackers.register("*otf.sample","otf.steps,otf.actions,otf.analyzing")  local insert_node_after = node.insert_after  local delete_node       = nodes.delete  local copy_node         = node.copy -local slide_node_list   = node.slide +local find_node_tail    = node.tail or node.slide  local set_attribute     = node.set_attribute  local has_attribute     = node.has_attribute @@ -1905,7 +1905,7 @@ function fonts.methods.node.otf.features(head,font,attr)                  local handler = handlers[typ]                  local thecache = featuredata[typ] or { }                  -- we need to get rid of this slide ! -                start = slide_node_list(head) -- slow (we can store tail because there's always a skip at the end): todo +                start = find_node_tail(head) -- slow (we can store tail because there's always a skip at the end): todo                  while start do                      local id = start.id                      if id == glyph then diff --git a/otfl-font-ott.lua b/otfl-font-ott.lua index 6676ff6..47c2e0e 100644 --- a/otfl-font-ott.lua +++ b/otfl-font-ott.lua @@ -671,6 +671,16 @@ local to_scripts   = otf.tables.to_scripts  local to_languages = otf.tables.to_languages  local to_features  = otf.tables.to_features +for k, v in pairs(to_features) do +    local stripped = gsub(k,"%-"," ") +    to_features[stripped] = v +    local stripped = gsub(k,"[^a-zA-Z0-9]","") +    to_features[stripped] = v +end +for k, v in pairs(to_features) do +    to_features[lower(k)] = v +end +  function otf.meanings.normalize(features)      local h = { }      for k,v in next, features do diff --git a/otfl-font-tfm.lua b/otfl-font-tfm.lua index 472f69c..8b799df 100644 --- a/otfl-font-tfm.lua +++ b/otfl-font-tfm.lua @@ -245,7 +245,7 @@ function tfm.do_scale(tfmtable, scaledpoints)      end      -- status      local isvirtual = tfmtable.type == "virtual" or tfmtable.virtualized -    local hasmath = tfmtable.math_parameters ~= nil or tfmtable.MathConstants ~= nil +    local hasmath = (tfmtable.math_parameters ~= nil and next(tfmtable.math_parameters) ~= nil) or (tfmtable.MathConstants ~= nil and next(tfmtable.MathConstants) ~= nil)      local nodemode = tfmtable.mode == "node"      local hasquality = tfmtable.auto_expand or tfmtable.auto_protrude      local hasitalic = tfmtable.has_italic @@ -293,6 +293,7 @@ function tfm.do_scale(tfmtable, scaledpoints)      local scaledheight = defaultheight * delta      local scaleddepth  = defaultdepth  * delta      local stackmath = tfmtable.ignore_stack_math ~= true +local private = fonts.private      for k,v in next, characters do          local chr, description, index          if ischanged then @@ -355,7 +356,7 @@ function tfm.do_scale(tfmtable, scaledpoints)      --      logs.report("define font","t=%s, u=%s, i=%s, n=%s c=%s",k,chr.tounicode or k,description.index,description.name or '-',description.class or '-')      --  end          if tounicode then -            local tu = tounicode[index] +            local tu = tounicode[index] -- nb: index!              if tu then                  chr.tounicode = tu              end @@ -528,6 +529,7 @@ function tfm.do_scale(tfmtable, scaledpoints)      end      -- needed for \high cum suis      local tpx = tp.x_height +if hasmath then      if not tp[13] then tp[13] = .86*tpx end  -- mathsupdisplay      if not tp[14] then tp[14] = .86*tpx end  -- mathsupnormal      if not tp[15] then tp[15] = .86*tpx end  -- mathsupcramped @@ -535,11 +537,22 @@ function tfm.do_scale(tfmtable, scaledpoints)      if not tp[17] then tp[17] = .48*tpx end  -- mathsubcombined      if not tp[22] then tp[22] =   0     end  -- mathaxisheight      if t.MathConstants then t.MathConstants.AccentBaseHeight = nil end -- safeguard +end      t.tounicode = 1      t.cidinfo = tfmtable.cidinfo      -- we have t.name=metricfile and t.fullname=RealName and t.filename=diskfilename      -- when collapsing fonts, luatex looks as both t.name and t.fullname as ttc files      -- can have multiple subfonts +    if hasmath then +        if trace_defining then +            logs.report("define font","math enabled for: %s %s %s",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename") +        end +    else +        if trace_defining then +            logs.report("define font","math disabled for: %s %s %s",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename") +        end +        t.nomath, t.MathConstants = true, nil +    end      return t, delta  end @@ -714,7 +727,7 @@ function tfm.set_features(tfmdata)                          local value = features[f]                          if value and fi.tfm[f] then -- brr                              if tfm.trace_features then -                                logs.report("define tfm","initializing feature %s to %s for mode %s for font %s",f,tostring(value),mode or 'unknown',tfmdata.name or 'unknown') +                                logs.report("define font","initializing feature %s to %s for mode %s for font %s",f,tostring(value),mode or 'unknown',tfmdata.name or 'unknown')                              end                              fi.tfm[f](tfmdata,value)                              mode = tfmdata.mode or fonts.mode diff --git a/otfl-font-xtx.lua b/otfl-font-xtx.lua index 63e421f..7b3f1ec 100644 --- a/otfl-font-xtx.lua +++ b/otfl-font-xtx.lua @@ -72,7 +72,7 @@ local function isfalse(s)   list[s]     = 'no' end  local function iskey  (k,v) list[k]     = v end  local spaces     = lpeg.P(" ")^0 -local namespec   = (1-lpeg.S("/: ("))^0 +local namespec   = (1-lpeg.S("/:("))^0 -- was: (1-lpeg.S("/: ("))^0  local crapspec   = spaces * lpeg.P("/") * (((1-lpeg.P(":"))^0)/iscrap) * spaces  local filename   = (lpeg.P("file:")/isfile * (namespec/thename)) + (lpeg.P("[") * lpeg.P(true)/isname * (((1-lpeg.P("]"))^0)/thename) * lpeg.P("]"))  local fontname   = (lpeg.P("name:")/isname * (namespec/thename)) + lpeg.P(true)/issome * (namespec/thename) diff --git a/otfl-node-dum.lua b/otfl-node-dum.lua index 274e0cd..f39a087 100644 --- a/otfl-node-dum.lua +++ b/otfl-node-dum.lua @@ -8,17 +8,12 @@ if not modules then modules = { } end modules ['node-dum'] = {  nodes = nodes or { } -function nodes.simple_font_dummy(head,tail) -    return tail -end -  function nodes.simple_font_handler(head) -    local tail = node.slide(head) ---  lang.hyphenate(head,tail) -    head = nodes.process_characters(head,tail) +--  lang.hyphenate(head) +    head = nodes.process_characters(head)      nodes.inject_kerns(head)      nodes.protect_glyphs(head) -    tail = node.ligaturing(head,tail) -    tail = node.kerning(head,tail) +    head = node.ligaturing(head) +    head = node.kerning(head)      return head  end diff --git a/otfl-node-ini.lua b/otfl-node-ini.lua index 8185e30..3ff73c6 100644 --- a/otfl-node-ini.lua +++ b/otfl-node-ini.lua @@ -110,7 +110,6 @@ local whatsit = node.id('whatsit')  local traverse_id = node.traverse_id  local traverse    = node.traverse -local slide_nodes = node.slide  local free_node   = node.free  local remove_node = node.remove @@ -132,10 +131,10 @@ function nodes.delete(head,current)      return nodes.remove(head,current,true)  end -nodes.before = node.insert_before -- broken +nodes.before = node.insert_before  nodes.after  = node.insert_after --- we need to test this, as it might be fixed +-- we need to test this, as it might be fixed now  function nodes.before(h,c,n)      if c then diff --git a/otfl-node-inj.lua b/otfl-node-inj.lua index 2e8b5ae..dc676a4 100644 --- a/otfl-node-inj.lua +++ b/otfl-node-inj.lua @@ -114,7 +114,7 @@ end  function nodes.trace_injection(head)      local function dir(n) -        return (n<0 and "r-to-l") or (n>0 and "l-to-r") or ("unset") +        return (n and n<0 and "r-to-l") or (n and n>0 and "l-to-r") or ("unset")      end      local function report(...)          logs.report("nodes finisher",...) @@ -132,9 +132,9 @@ function nodes.trace_injection(head)              if kp then                  local k = kerns[kp]                  if k[3] then -                    report("  pairkern: dir=%s, x=%s, y=%s, w=%s, h=%s",dir(k[1]),k[2],k[3],k[4],k[5]) +                    report("  pairkern: dir=%s, x=%s, y=%s, w=%s, h=%s",dir(k[1]),k[2] or "?",k[3] or "?",k[4] or "?",k[5] or "?")                  else -                    report("  kern: dir=%s, dx=%s",dir(k[1]),k[2]) +                    report("  kern: dir=%s, dx=%s",dir(k[1]),k[2] or "?")                  end              end              if mb then @@ -145,13 +145,13 @@ function nodes.trace_injection(head)                  if mb then                      local m = m[mb]                      if m then -                        report("  markmark: bound=%s, index=%s, dx=%s, dy=%s",mm,j,m[1],m[2]) +                        report("  markmark: bound=%s, index=%s, dx=%s, dy=%s",mm,md or "?",m[1] or "?",m[2] or "?")                      else                          report("  markmark: bound=%s, missing index",mm)                      end                  else                      m = m[1] -                    report("  markmark: bound=%s, dx=%s, dy=%s",mm,m[1],m[2]) +                    report("  markmark: bound=%s, dx=%s, dy=%s",mm,m[1] or "?",m[2] or "?")                  end              end              if cb then @@ -159,7 +159,7 @@ function nodes.trace_injection(head)              end              if cc then                  local c = cursives[cc] -                report("  curscurs: bound=%s, dir=%s, dx=%s, dy=%s",cc,dir(c[1]),c[2],c[3]) +                report("  curscurs: bound=%s, dir=%s, dx=%s, dy=%s",cc,dir(c[1]),c[2] or "?",c[3] or "?")              end          end      end @@ -168,18 +168,24 @@ end  -- todo: reuse tables (i.e. no collection), but will be extra fields anyway -function nodes.inject_kerns(head,tail,where,keep) -    if trace_injections then -        nodes.trace_injection(head) -    end +function nodes.inject_kerns(head,where,keep)      local has_marks, has_cursives, has_kerns = next(marks), next(cursives), next(kerns)      if has_marks or has_cursives then +        if trace_injections then +            nodes.trace_injection(head) +        end          -- in the future variant we will not copy items but refs to tables -        local done, ky, rl, valid, cx, wx = false, { }, { }, { }, { }, { } +        local done, ky, rl, valid, cx, wx, mk = false, { }, { }, { }, { }, { }, { }          if has_kerns then -- move outside loop +            local nf, tm = nil, nil              for n in traverse_id(glyph,head) do                  if n.subtype < 256 then                      valid[#valid+1] = n +                    if n.font ~= nf then +                        nf = n.font +                        tm = fontdata[nf].marks +                    end +                    mk[n] = tm[n.char]                      local k = has_attribute(n,kernpair)                      if k then                          local kk = kerns[k] @@ -198,9 +204,15 @@ function nodes.inject_kerns(head,tail,where,keep)                  end              end          else +            local nf, tm = nil, nil              for n in traverse_id(glyph,head) do                  if n.subtype < 256 then                      valid[#valid+1] = n +                    if n.font ~= nf then +                        nf = n.font +                        tm = fontdata[nf].marks +                    end +                    mk[n] = tm[n.char]                  end              end          end @@ -214,22 +226,15 @@ function nodes.inject_kerns(head,tail,where,keep)              end              -- todo: reuse t and use maxt              if has_cursives then -                local n_cursbase, n_curscurs, p_cursbase, n, p, nf, tm = nil, nil, nil, nil, nil, nil, nil +                local p_cursbase, p = nil, nil                  -- since we need valid[n+1] we can also use a "while true do"                  local t, d, maxt = { }, { }, 0                  for i=1,#valid do -- valid == glyphs -                    n = valid[i] -                    if n.font ~= nf then -                        nf = n.font ---~ print(n.font,nf,fontdata[nf]) -                        tm = fontdata[nf].marks -                        -- maybe flush -                        maxt = 0 -                    end -                    if not tm[n.char] then -                        n_cursbase = has_attribute(n,cursbase) -                        n_curscurs = has_attribute(n,curscurs) +                    local n = valid[i] +                    if not mk[n] then +                        local n_cursbase = has_attribute(n,cursbase)                          if p_cursbase then +                            local n_curscurs = has_attribute(n,curscurs)                              if p_cursbase == n_curscurs then                                  local c = cursives[n_curscurs]                                  if c then @@ -257,7 +262,8 @@ function nodes.inject_kerns(head,tail,where,keep)                              local ny = n.yoffset                              for i=maxt,1,-1 do                                  ny = ny + d[i] -                                t[i].yoffset = t[i].yoffset + ny +                                local ti = t[i] +                                ti.yoffset = ti.yoffset + ny                              end                              maxt = 0                          end @@ -265,7 +271,8 @@ function nodes.inject_kerns(head,tail,where,keep)                              local ny = n.yoffset                              for i=maxt,1,-1 do                                  ny = ny + d[i] -                                t[i].yoffset = ny +                                local ti = t[i] +                                ti.yoffset = ny                              end                              maxt = 0                          end @@ -276,7 +283,8 @@ function nodes.inject_kerns(head,tail,where,keep)                      local ny = n.yoffset                      for i=maxt,1,-1 do                          ny = ny + d[i] -                        t[i].yoffset = ny +                        local ti = t[i] +                        ti.yoffset = ny                      end                      maxt = 0                  end @@ -285,14 +293,13 @@ function nodes.inject_kerns(head,tail,where,keep)                  end              end              if has_marks then -                local p_markbase, n_markmark = nil, nil                  for i=1,#valid do                      local p = valid[i] -                    p_markbase = has_attribute(p,markbase) +                    local p_markbase = has_attribute(p,markbase)                      if p_markbase then                          local mrks = marks[p_markbase]                          for n in traverse_id(glyph,p.next) do -                            n_markmark = has_attribute(n,markmark) +                            local n_markmark = has_attribute(n,markmark)                              if p_markbase == n_markmark then                                  local index = has_attribute(n,markdone) or 1                                  local d = mrks[index] @@ -301,9 +308,17 @@ function nodes.inject_kerns(head,tail,where,keep)                                  --  if rlmode and rlmode < 0 then                                  --      n.xoffset = p.xoffset + d[1]                                  --  else -                                        n.xoffset = p.xoffset - d[1] +                                         n.xoffset = p.xoffset - d[1] +--~ local k = wx[p] +--~ if k then +--~     wx[n] = k +--~ end                                  --  end -                                    n.yoffset = p.yoffset + d[2] +                                    if mk[p] then +                                        n.yoffset = p.yoffset + d[2] +                                    else +                                        n.yoffset = n.yoffset + p.yoffset + d[2] +                                    end                                  end                              else                                  break @@ -358,224 +373,9 @@ function nodes.inject_kerns(head,tail,where,keep)              kerns, cursives, marks = { }, { }, { }          end      elseif has_kerns then -        -- we assume done is true because there are kerns -        for n in traverse_id(glyph,head) do -            local k = has_attribute(n,kernpair) -            if k then -                local kk = kerns[k] -                if kk then -                 -- only w can be nil, can be sped up when w == nil -                    local rl, x, y, w = kk[1], kk[2] or 0, kk[3] or 0, kk[4] or 0 -                    if y ~= 0 then -                        n.yoffset = y -- todo: h ? -                    end -                    local wx = w - x -                    if rl < 0 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 wx ~= 0 then -                    --      insert_node_after(head,n,newkern(wx)) -                    --  end -                        if x ~= 0 then -                            insert_node_before(head,n,newkern(x)) -                        end -                    end -                end -            end +        if trace_injections then +            nodes.trace_injection(head)          end -        if not keep then -            kerns = { } -        end -        return head, true -    end -    return head, false -end - --- -- -- KEEP OLD ONE, THE NEXT IS JUST OPTIMIZED -- -- -- - -function nodes.XXXXXXXxinject_kerns(head,tail,keep) -    if trace_injections then -        nodes.trace_injection(head) -    end -    local has_marks, has_cursives, has_kerns = next(marks), next(cursives), next(kerns) -    if has_marks or has_cursives then -        -- in the future variant we will not copy items but refs to tables -        local done, ky, valid, cx, wx = false, { }, { }, { }, { } -        for n in traverse_id(glyph,head) do -            if n.subtype < 256 then -                valid[#valid+1] = n -                if has_kerns then -- move outside loop -                    local k = has_attribute(n,kernpair) -                    if k then -                        local kk = kerns[k] -                        if kk then -                            local x, y, w, h = kk[2], kk[3], kk[4], kk[5] -                            local dy = y - h -                            if dy ~= 0 then -                                ky[n] = dy -                            end -                            if w ~= 0 or x ~= 0 then -                                wx[n] = kk -                            end -                        end -                    end -                end -            end -        end -        if #valid > 0 then -            -- we can assume done == true because we have cursives and marks -            local cx = { } -            if has_kerns and next(ky) then -                for n, k in next, ky do -                    n.yoffset = k -                end -            end -            -- todo: reuse t and use maxt -            if has_cursives then -                local n_cursbase, n_curscurs, p_cursbase, n, p, nf, tm = nil, nil, nil, nil, nil, nil, nil -                -- since we need valid[n+1] we can also use a "while true do" -                local t, d, maxt = { }, { }, 0 -                for i=1,#valid do -- valid == glyphs -                    n = valid[i] -                    if n.font ~= nf then -                        nf = n.font -                        tm = fontdata[nf].marks -                        -- maybe flush -                        maxt = 0 -                    end -                    if not tm[n.char] then -                        n_cursbase = has_attribute(n,cursbase) -                        n_curscurs = has_attribute(n,curscurs) -                        if p_cursbase then -                            if p_cursbase == n_curscurs then -                                local c = cursives[n_curscurs] -                                if c then -                                    local rlmode, dx, dy, ws, wn = c[1], c[2], c[3], c[4], c[5] -                                    if rlmode >= 0 then -                                        dx = dx - ws -                                    else -                                        dx = dx + wn -                                    end -                                    if dx ~= 0 then -if rlmode < 0 then -                                        cx[n] = -dx -else -                                        cx[n] = dx -end -                                    end -                                --  if rlmode and rlmode < 0 then -                                        dy = -dy -                                --  end -                                    maxt = maxt + 1 -                                    t[maxt] = p -                                    d[maxt] = dy -                                else -                                    maxt = 0 -                                end -                            end -                        elseif maxt > 0 then -                            local ny = n.yoffset -                            for i=maxt,1,-1 do -                                ny = ny + d[i] -                                t[i].yoffset = t[i].yoffset + ny -                            end -                            maxt = 0 -                        end -                        if not n_cursbase and maxt > 0 then -                            local ny = n.yoffset -                            for i=maxt,1,-1 do -                                ny = ny + d[i] -                                t[i].yoffset = ny -                            end -                            maxt = 0 -                        end -                        p_cursbase, p = n_cursbase, n -                    end -                end -                if maxt > 0 then -                    local ny = n.yoffset -                    for i=maxt,1,-1 do -                        ny = ny + d[i] -                        t[i].yoffset = ny -                    end -                    maxt = 0 -                end -                if not keep then -                    cursives = { } -                end -            end -            if has_marks then -                local p_markbase, n_markmark = nil, nil -                for i=1,#valid do -                    local p = valid[i] -                    p_markbase = has_attribute(p,markbase) -                    if p_markbase then -                        local mrks = marks[p_markbase] -                        for n in traverse_id(glyph,p.next) do -                            n_markmark = has_attribute(n,markmark) -                            if p_markbase == n_markmark then -                                local index = has_attribute(n,markdone) or 1 -                                local d = mrks[index] -                                if d then -                                    local d1, d2 = d[1], d[2] -                                    if d1 ~= 0 then -                                        n.xoffset = p.xoffset - d[1] -                                    end -                                    if d2 ~= 0 then -                                        n.yoffset = p.yoffset + d[2] -                                    end -                                end -                            else -                                break -                            end -                        end -                    end -                end -                if not keep then -                    marks = { } -                end -            end -            -- todo : combine -            if next(wx) then -                for n, k in next, wx do -                 -- only w can be nil, can be sped up when w == nil -                    local rl, x, w = k[1], k[2] or 0, k[4] or 0 -                    local wx = w - x -                    if rl < 0 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 wx ~= 0 then -                    --      insert_node_after(head,n,newkern(wx)) -                    --  end -                        if x ~= 0 then -                            insert_node_before(head,n,newkern(x)) -                        end -                    end -                end -            end -            if next(cx) then -                for n, k in next, cx do -                    insert_node_before(head,n,newkern(k)) -                end -            end -            if not keep then -                kerns = { } -            end -            return head, true -        elseif not keep then -            kerns, cursives, marks = { }, { }, { } -        end -    elseif has_kerns then          -- we assume done is true because there are kerns          for n in traverse_id(glyph,head) do              local k = has_attribute(n,kernpair) @@ -610,6 +410,8 @@ end              kerns = { }          end          return head, true +    else +        -- no tracing needed      end      return head, false  end diff --git a/otfl-node-res.lua b/otfl-node-res.lua index b84e5b1..4f2cf5a 100644 --- a/otfl-node-res.lua +++ b/otfl-node-res.lua @@ -7,7 +7,7 @@ if not modules then modules = { } end modules ['node-res'] = {  }  local gmatch, format = string.gmatch, string.format -local copy_node, free_node, new_node = node.copy, node.free, node.new +local copy_node, free_node, free_list, new_node = node.copy, node.free, node.flush_list, node.new  --[[ldx--  <p>The next function is not that much needed but in <l n='context'/> we use @@ -51,7 +51,6 @@ function nodes.usage()      return t  end -local pdfliteral = nodes.register(new_node("whatsit",8))   pdfliteral.mode = 1  local disc       = nodes.register(new_node("disc"))  local kern       = nodes.register(new_node("kern",1))  local penalty    = nodes.register(new_node("penalty")) @@ -60,6 +59,7 @@ local glue_spec  = nodes.register(new_node("glue_spec"))  local glyph      = nodes.register(new_node("glyph",0))  local textdir    = nodes.register(new_node("whatsit",7))  local rule       = nodes.register(new_node("rule")) +local latelua    = nodes.register(new_node("whatsit",35))  function nodes.glyph(fnt,chr)      local n = copy_node(glyph) @@ -91,11 +91,6 @@ end  function nodes.disc()      return copy_node(disc)  end -function nodes.pdfliteral(str) -    local t = copy_node(pdfliteral) -    t.data = str -    return t -end  function nodes.textdir(dir)      local t = copy_node(textdir)      t.dir = dir @@ -108,6 +103,11 @@ function nodes.rule(w,h,d)      if d then n.depth  = d end      return n  end +function nodes.latelua(code) +    local n = copy_node(latelua) +    n.data = code +    return n +end  statistics.register("cleaned up reserved nodes", function()      return format("%s nodes, %s lists of %s", nodes.cleanup_reserved(tex.count["lastallocatedbox"]))  | 
