diff options
| -rw-r--r-- | README | 3 | ||||
| -rw-r--r-- | luaotfload.dtx | 30 | ||||
| -rw-r--r-- | otfl-data-con.lua | 6 | ||||
| -rw-r--r-- | otfl-font-cid.lua | 2 | ||||
| -rw-r--r-- | otfl-font-def.lua | 18 | ||||
| -rw-r--r-- | otfl-font-dum.lua | 30 | ||||
| -rw-r--r-- | otfl-font-otb.lua | 33 | ||||
| -rw-r--r-- | otfl-font-otc.lua | 215 | ||||
| -rw-r--r-- | otfl-font-otd.lua | 78 | ||||
| -rw-r--r-- | otfl-font-otf.lua | 201 | ||||
| -rw-r--r-- | otfl-font-oti.lua | 57 | ||||
| -rw-r--r-- | otfl-font-otn.lua | 157 | ||||
| -rw-r--r-- | otfl-font-ott.lua | 935 | ||||
| -rw-r--r-- | otfl-font-tfm.lua | 23 | ||||
| -rw-r--r-- | otfl-font-xtx.lua | 26 | ||||
| -rw-r--r-- | otfl-luat-dum.lua | 7 | ||||
| -rw-r--r-- | otfl-node-fnt.lua | 18 | ||||
| -rw-r--r-- | otfl-node-ini.lua | 4 | 
18 files changed, 1574 insertions, 269 deletions
@@ -40,8 +40,11 @@ Source files:          otfl-font-ota.lua                       .          otfl-font-otb.lua                       .          otfl-font-otc.lua                       . +        otfl-font-otd.lua                       .          otfl-font-otf.lua                       . +        otfl-font-oti.lua                       .          otfl-font-otn.lua                       . +        otfl-font-ott.lua                       .          otfl-font-tfm.lua                       .          otfl-font-xtx.lua                       .          otfl-luat-dum.lua                       . diff --git a/luaotfload.dtx b/luaotfload.dtx index b93b987..2ed3a04 100644 --- a/luaotfload.dtx +++ b/luaotfload.dtx @@ -166,9 +166,12 @@ and the derived files  % \item \texttt{node-dum.lua}  % \item \texttt{font-ini.lua}  % \item \texttt{font-tfm.lua} +% \item \texttt{font-cid.lua} +% \item \texttt{font-ott.lua}  % \item \texttt{font-otf.lua} +% \item \texttt{font-otd.lua} +% \item \texttt{font-oti.lua}  % \item \texttt{font-otb.lua} -% \item \texttt{font-cid.lua}  % \item \texttt{font-otn.lua}  % \item \texttt{font-ota.lua}  % \item \texttt{font-otc.lua} @@ -271,6 +274,24 @@ function table.sortedhashkeys(tab) -- fast one      return srt  end +function table.reverse_hash(h) +    local r = { } +    for k,v in next, h do +        r[v] = string.lower(string.gsub(k," ","")) +    end  +    return r +end  + +function table.reverse(t) +    local tt = { } +    if #t > 0 then +        for i=#t,1,-1 do +            tt[#tt+1] = t[i] +        end +    end +    return tt +end +  %    \end{macrocode}  %  % We start loading some lua files. These two are some code not used by Con\TeX t at all that allow other modules to be used, it provides some low-level Con\TeX t functions. @@ -304,7 +325,7 @@ end  %    \end{macrocode}  % -% Some more modules. We don't load \texttt{font-ott.lua}, as it only contains the meaning of the options, ans it works perfectly without it. We don't load neither \texttt{font-enc.lua} nor \texttt{font-afm.lua} as it will never be used here. +% Some more modules. We don't load neither \texttt{font-enc.lua} nor \texttt{font-afm.lua} as it will never be used here.  %  %    \begin{macrocode} @@ -315,9 +336,12 @@ luaotfload.loadmodule('node-dum.lua')  luaotfload.loadmodule('font-ini.lua')  luaotfload.loadmodule('font-tfm.lua') +luaotfload.loadmodule('font-cid.lua') +luaotfload.loadmodule('font-ott.lua')  luaotfload.loadmodule('font-otf.lua') +luaotfload.loadmodule('font-otd.lua') +luaotfload.loadmodule('font-oti.lua')  luaotfload.loadmodule('font-otb.lua') -luaotfload.loadmodule('font-cid.lua')  luaotfload.loadmodule('font-otn.lua')  luaotfload.loadmodule('font-ota.lua')  luaotfload.loadmodule('font-otc.lua') diff --git a/otfl-data-con.lua b/otfl-data-con.lua index ec146f0..02ee9ee 100644 --- a/otfl-data-con.lua +++ b/otfl-data-con.lua @@ -58,7 +58,7 @@ function containers.define(category, subcategory, version, enabled)                      enabled = enabled,                      version = version or 1.000,                      trace = false, -                    path = caches and caches.setpath(category,subcategory), +                    path = caches and caches.setpath and caches.setpath(category,subcategory),                  }                  c[subcategory] = s              end @@ -116,3 +116,7 @@ end  function containers.content(container,name)      return container.storage[name]  end + +function containers.cleanname(name) +    return (gsub(lower(name),"[^%w%d]+","-")) +end diff --git a/otfl-font-cid.lua b/otfl-font-cid.lua index b1ddaae..b8dfc42 100644 --- a/otfl-font-cid.lua +++ b/otfl-font-cid.lua @@ -79,7 +79,7 @@ end  local template = "%s-%s-%s.cidmap"  local function locate(registry,ordering,supplement) -    local filename = format(template,registry,ordering,supplement) +    local filename = string.lower(format(template,registry,ordering,supplement))      local cidmap = fonts.cid.map[filename]      if not cidmap then          if trace_loading then diff --git a/otfl-font-def.lua b/otfl-font-def.lua index 284f8ef..f91575a 100644 --- a/otfl-font-def.lua +++ b/otfl-font-def.lua @@ -83,7 +83,8 @@ function define.add_specifier(symbol)      local method        = lpeg.S(specifiers)      local lookup        = lpeg.C(lpeg.P("file")+lpeg.P("name")) * colon -- hard test, else problems with : method      local sub           = left * lpeg.C(lpeg.P(1-left-right-method)^1) * right -    local specification = lpeg.C(method) * lpeg.C(lpeg.P(1-method)^1) +--~   local specification = lpeg.C(method) * lpeg.C(lpeg.P(1-method)^1) +    local specification = lpeg.C(method) * lpeg.C(lpeg.P(1)^1)      local name          = lpeg.C((1-sub-specification)^1)      splitter = lpeg.P((lookup + lpeg.Cc("")) * name * (sub + lpeg.Cc("")) * (specification + lpeg.Cc("")))  end @@ -147,7 +148,7 @@ function tfm.hash_features(specification)              local f = sortedhashkeys(normal)              for i=1,#f do                  local v = f[i] -                if v ~= "number" then +                if v ~= "number" and v ~= "features" then -- i need to figure this out, features                      t[#t+1] = v .. '=' .. tostring(normal[v])                  end              end @@ -160,6 +161,9 @@ function tfm.hash_features(specification)                  t[#t+1] = v .. '=' .. tostring(vtf[v])              end          end +--~ if specification.mathsize then +--~     t[#t+1] = "mathsize=" .. specification.mathsize +--~ end          if #t > 0 then              return concat(t,"+")          end @@ -364,13 +368,13 @@ function readers.afm(specification,method)          if not tfmtable then              method = method or define.method or "afm or tfm"              if method == "tfm" then -                tfmtable = check_tfm(specification,fullname) +                tfmtable = check_tfm(specification,specification.name)              elseif method == "afm" then -                tfmtable = check_afm(specification,fullname) +                tfmtable = check_afm(specification,specification.name)              elseif method == "tfm or afm" then -                tfmtable = check_tfm(specification,fullname) or check_afm(specification,fullname) -            else-- method == "afm or tfm" then -                tfmtable = check_afm(specification,fullname) or check_tfm(specification,fullname) +                tfmtable = check_tfm(specification,specification.name) or check_afm(specification,specification.name) +            else -- method == "afm or tfm" or method == "" then +                tfmtable = check_afm(specification,specification.name) or check_tfm(specification,specification.name)              end          end      else diff --git a/otfl-font-dum.lua b/otfl-font-dum.lua index 0dedc85..0d28128 100644 --- a/otfl-font-dum.lua +++ b/otfl-font-dum.lua @@ -72,14 +72,42 @@ function fonts.names.resolve(name,sub)          end          loaded = true      end -    if type(data) == "table" and data.version == 1.07 then +    if type(data) == "table" and data.version == 1.08 then          local condensed = string.gsub(name,"[^%a%d]","")          local found = data.mapping and data.mapping[condensed]          if found then              local filename, is_sub = found[3], found[4] +            if is_sub then is_sub = found[2] end              return filename, is_sub          else              return name, false -- fallback to filename          end      end  end + +-- For the moment we put this (adapted) pseudo feature here. + +table.insert(fonts.triggers,"itlc") + +local function itlc(tfmdata,value) +    if value then +        -- the magic 40 and it formula come from Dohyun Kim +        local metadata = tfmdata.shared.otfdata.metadata +        if metadata then +            local italicangle = metadata.italicangle +            if italicangle and italicangle ~= 0 then +                local uwidth = (metadata.uwidth or 40)/2 +                for unicode, d in next, tfmdata.descriptions do +                    local it = d.boundingbox[3] - d.width + uwidth +                    if it ~= 0 then +                        d.italic = it +                    end +                end +                tfmdata.has_italic = true +            end +        end +    end +end + +fonts.initializers.base.otf.itlc = itlc +fonts.initializers.node.otf.itlc = itlc diff --git a/otfl-font-otb.lua b/otfl-font-otb.lua index 20ddbfc..5ef44a0 100644 --- a/otfl-font-otb.lua +++ b/otfl-font-otb.lua @@ -22,6 +22,7 @@ local trace_kerns        = false  trackers.register("otf.kerns",        function  local trace_preparing    = false  trackers.register("otf.preparing",    function(v) trace_preparing    = v end)  local wildcard = "*" +local default  = "dflt"  local split_at_space = lpeg.Ct(lpeg.splitat(" ")) -- no trailing or multiple spaces anyway @@ -141,8 +142,8 @@ local function collect_lookups(otfdata,kind,script,language)              local sequence = sequences[s]              local features = sequence.features              features = features and features[kind] -            features = features and (features[script]   or features[wildcard]) -            features = features and (features[language] or features[wildcard]) +            features = features and (features[script]   or features[default] or features[wildcard]) +            features = features and (features[language] or features[default] or features[wildcard])              if features then                  local subtables = sequence.subtables                  if subtables then @@ -322,20 +323,46 @@ function otf.features.register_base_kern(tag)      supported_gsub[#supported_gpos+1] = tag  end +local basehash, basehashes = { }, 1 +  function fonts.initializers.base.otf.features(tfmdata,value)      if true then -- value then          -- not shared          local t = trace_preparing and os.clock()          local features = tfmdata.shared.features          if features then +            local h = { }              for f=1,#supported_gsub do                  local feature = supported_gsub[f] -                prepare_base_substitutions(tfmdata,feature,features[feature]) +                local value = features[feature] +                prepare_base_substitutions(tfmdata,feature,value) +                if value then +                    h[#h+1] = feature  .. "=" .. tostring(value) +                end              end              for f=1,#supported_gpos do                  local feature = supported_gpos[f] +                local value = features[feature]                  prepare_base_kerns(tfmdata,feature,features[feature]) +                if value then +                    h[#h+1] = feature  .. "=" .. tostring(value) +                end +            end +            local hash = concat(h," ") +            local base = basehash[hash] +            if not base then +                basehashes = basehashes + 1 +                base = basehashes +                basehash[hash] = base              end +            -- We need to make sure that luatex sees the difference between +            -- base fonts that have different glyphs in the same slots in fonts +            -- that have the same fullname (or filename). LuaTeX will merge fonts +            -- eventually (and subset later on). If needed we can use a more +            -- verbose name as long as we don't use <()<>[]{}/%> and the length +            -- is < 128. +            tfmdata.fullname = tfmdata.fullname .. "-" .. base +--~ logs.report("otf define","fullname base hash: '%s', featureset '%s'",tfmdata.fullname,hash)          end          if trace_preparing then              logs.report("otf define","preparation time is %0.3f seconds for %s",os.clock()-t,tfmdata.fullname or "?") diff --git a/otfl-font-otc.lua b/otfl-font-otc.lua index 40631fb..f75da39 100644 --- a/otfl-font-otc.lua +++ b/otfl-font-otc.lua @@ -18,79 +18,188 @@ local trace_loading = false  trackers.register("otf.loading", function(v) trace_  local otf = fonts.otf  local tfm = fonts.tfm --- for good old times (usage is to be avoided) - -local tlig_list = { -    endash        = "hyphen hyphen", -    emdash        = "hyphen hyphen hyphen", ---~ quotedblleft  = "quoteleft quoteleft", ---~ quotedblright = "quoteright quoteright", ---~ quotedblleft  = "grave grave", ---~ quotedblright = "quotesingle quotesingle", ---~ quotedblbase  = "comma comma", -} -local trep_list = { ---~ [0x0022] = 0x201D, -    [0x0027] = 0x2019, ---~ [0x0060] = 0x2018, -} -  -- instead of "script = "DFLT", langs = { 'dflt' }" we now use wildcards (we used to  -- have always); some day we can write a "force always when true" trick for other  -- features as well -local tlig_feature = { -    features  = { { scripts = { { script = "*", langs = { "*" }, } }, tag = "tlig", comment = "added bij mkiv" }, }, -    name      = "ctx_tlig", -    subtables = { { name = "ctx_tlig_1" } }, -    type      = "gsub_ligature", -    flags     = { }, +local extra_lists = { +    tlig = { +        { +            endash        = "hyphen hyphen", +            emdash        = "hyphen hyphen hyphen", +         -- quotedblleft  = "quoteleft quoteleft", +         -- quotedblright = "quoteright quoteright", +         -- quotedblleft  = "grave grave", +         -- quotedblright = "quotesingle quotesingle", +         -- quotedblbase  = "comma comma", +        }, +    }, +    trep = { +        { +         -- [0x0022] = 0x201D, +            [0x0027] = 0x2019, +         -- [0x0060] = 0x2018, +        }, +    }, +    anum = { +        { -- arabic +            [0x0030] = 0x0660, +            [0x0031] = 0x0661, +            [0x0032] = 0x0662, +            [0x0033] = 0x0663, +            [0x0034] = 0x0664, +            [0x0035] = 0x0665, +            [0x0036] = 0x0666, +            [0x0037] = 0x0667, +            [0x0038] = 0x0668, +            [0x0039] = 0x0669, +        }, +        { -- persian +            [0x0030] = 0x06F0, +            [0x0031] = 0x06F1, +            [0x0032] = 0x06F2, +            [0x0033] = 0x06F3, +            [0x0034] = 0x06F4, +            [0x0035] = 0x06F5, +            [0x0036] = 0x06F6, +            [0x0037] = 0x06F7, +            [0x0038] = 0x06F8, +            [0x0039] = 0x06F9, +        }, +    },  } -local trep_feature = { -    features  = { { scripts = { { script = "*", langs = { "*" }, } }, tag = "trep", comment = "added bij mkiv" }, }, -    name      = "ctx_trep", -    subtables = { { name = "ctx_trep_1" } }, -    type      = "gsub_single", -    flags     = { }, + +local extra_features = { -- maybe just 1..n so that we prescribe order +    tlig = { +        { +            features  = { { scripts = { { script = "*", langs = { "*" }, } }, tag = "tlig", comment = "added bij mkiv" }, }, +            name      = "ctx_tlig_1", +            subtables = { { name = "ctx_tlig_1_s" } }, +            type      = "gsub_ligature", +            flags     = { }, +        }, +    }, +    trep = { +        { +            features  = { { scripts = { { script = "*", langs = { "*" }, } }, tag = "trep", comment = "added bij mkiv" }, }, +            name      = "ctx_trep_1", +            subtables = { { name = "ctx_trep_1_s" } }, +            type      = "gsub_single", +            flags     = { }, +        }, +    }, +    anum = { +        { +            features  = { { scripts = { { script = "arab", langs = { "dflt", "FAR" }, } }, tag = "anum", comment = "added bij mkiv" }, }, +            name      = "ctx_anum_1", +            subtables = { { name = "ctx_anum_1_s" } }, +            type      = "gsub_single", +            flags     = { }, +        }, +        { +            features  = { { scripts = { { script = "arab", langs = { "URD" }, } }, tag = "anum", comment = "added bij mkiv" }, }, +            name      = "ctx_anum_2", +            subtables = { { name = "ctx_anum_2_s" } }, +            type      = "gsub_single", +            flags     = { }, +        }, +    },  } +fonts.otf.enhancers["add some missing characters"] = function(data,filename) +    -- todo +end +  fonts.otf.enhancers["enrich with features"] = function(data,filename) -    local glyphs = data.glyphs -    local indices = data.map.map -    for unicode, index in next, indices do -        local glyph = glyphs[index] -        local l = tlig_list[glyph.name] -        if l then -            local o = glyph.lookups or { } -            o["ctx_tlig_1"] = { { "ligature", l, glyph.name } } -            glyph.lookups = o -        end -        local r = trep_list[unicode] -        if r then -            local replacement = indices[r] -            if replacement then -                local o = glyph.lookups or { } -                o["ctx_trep_1"] = { { "substitution", glyphs[replacement].name } } --- -                glyph.lookups = o +    -- could be done elsewhere (true can be #) +    local used = { } +    for i=1,#otf.glists do +        local g = data[otf.glists[i]] +        if g then +            for i=1,#g do +                local f = g[i].features +                if f then +                    for i=1,#f do +                        local t = f[i].tag +                        if t then used[t] = true end +                    end +                end              end          end      end +    -- +    local glyphs = data.glyphs +    local indices = data.map.map      data.gsub = data.gsub or { } -    if trace_loading then -        logs.report("load otf","enhance: registering tlig feature") -    end -    insert(data.gsub,1,table.fastcopy(tlig_feature)) -    if trace_loading then -        logs.report("load otf","enhance: registering trep feature") +    for kind, specifications in next, extra_features do +        if not used[kind] then +            local done = 0 +            for s=1,#specifications do +                local added = false +                local specification = specifications[s] +                local list = extra_lists[kind][s] +                local name = specification.name .. "_s" +                if specification.type == "gsub_ligature" then +                    for unicode, index in next, indices do +                        local glyph = glyphs[index] +                        local ligature = list[glyph.name] +                        if ligature then +                            local o = glyph.lookups or { } +                        --  o[name] = { "ligature", ligature, glyph.name } +                            o[name] = { +                                { +                                    ["type"] = "ligature", +                                    ["specification"] = { +                                        char = glyph.name, +                                        components = ligature, +                                    } +                                } +                            } +                            glyph.lookups, done, added = o, done+1, true +                        end +                    end +                elseif specification.type == "gsub_single" then +                    for unicode, index in next, indices do +                        local glyph = glyphs[index] +                        local r = list[unicode] +                        if r then +                            local replacement = indices[r] +                            if replacement and glyphs[replacement] then +                                local o = glyph.lookups or { } +                            --  o[name] = { { "substitution", glyphs[replacement].name } } +                                o[name] = { +                                    { +                                        ["type"] = "substitution", +                                        ["specification"] = { +                                            variant = glyphs[replacement].name, +                                        } +                                    } +                                } +                                glyph.lookups, done, added = o, done+1, true +                            end +                        end +                    end +                end +                if added then +                    insert(data.gsub,s,table.fastcopy(specification)) -- right order +                end +            end +            if done > 0 then +                if trace_loading then +                    logs.report("load otf","enhance: registering %s feature (%s glyphs affected)",kind,done) +                end +            end +        end      end -    insert(data.gsub,1,table.fastcopy(trep_feature))  end  otf.tables.features['tlig'] = 'TeX Ligatures'  otf.tables.features['trep'] = 'TeX Replacements' +otf.tables.features['anum'] = 'Arabic Digits'  otf.features.register_base_substitution('tlig')  otf.features.register_base_substitution('trep') +otf.features.register_base_substitution('anum')  -- the functionality is defined elsewhere diff --git a/otfl-font-otd.lua b/otfl-font-otd.lua new file mode 100644 index 0000000..78a8281 --- /dev/null +++ b/otfl-font-otd.lua @@ -0,0 +1,78 @@ +if not modules then modules = { } end modules ['font-otd'] = { +    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 trace_dynamics  = false  trackers.register("otf.dynamics",     function(v) trace_dynamics     = v end) + +fonts     = fonts     or { } +fonts.otf = fonts.otf or { } + +local otf      = fonts.otf +local fontdata = fonts.ids + +otf.features         = otf.features         or { } +otf.features.default = otf.features.default or { } + +local context_setups  = fonts.define.specify.context_setups +local context_numbers = fonts.define.specify.context_numbers + +local a_to_script   = { }  otf.a_to_script   = a_to_script +local a_to_language = { }  otf.a_to_language = a_to_language + +function otf.set_dynamics(font,dynamics,attribute) +    features = context_setups[context_numbers[attribute]] -- can be moved to caller +    if features then +        local script   = features.script   or 'dflt' +        local language = features.language or 'dflt' +        local ds = dynamics[script] +        if not ds then +            ds = { } +            dynamics[script] = ds +        end +        local dsl = ds[language] +        if not dsl then +            dsl = { } +            ds[language] = dsl +        end +        local dsla = dsl[attribute] +        if dsla then +        --  if trace_dynamics then +        --      logs.report("otf define","using dynamics %s: attribute %s, script %s, language %s",context_numbers[attribute],attribute,script,language) +        --  end +            return dsla +        else +            local tfmdata = fontdata[font] +            a_to_script  [attribute] = script +            a_to_language[attribute] = language +            -- we need to save some values +            local saved = { +                script    = tfmdata.script, +                language  = tfmdata.language, +                mode      = tfmdata.mode, +                features  = tfmdata.shared.features +            } +            tfmdata.mode     = "node" +            tfmdata.language = language +            tfmdata.script   = script +            tfmdata.shared.features = { } +            -- end of save +            dsla = otf.set_features(tfmdata,fonts.define.check(features,otf.features.default)) +            if trace_dynamics then +                logs.report("otf define","setting dynamics %s: attribute %s, script %s, language %s",context_numbers[attribute],attribute,script,language) +            end +            -- we need to restore some values +            tfmdata.script          = saved.script +            tfmdata.language        = saved.language +            tfmdata.mode            = saved.mode +            tfmdata.shared.features = saved.features +            -- end of restore +            dynamics[script][language][attribute] = dsla -- cache +            return dsla +        end +    end +    return nil -- { } +end diff --git a/otfl-font-otf.lua b/otfl-font-otf.lua index a63b9e3..20273f8 100644 --- a/otfl-font-otf.lua +++ b/otfl-font-otf.lua @@ -61,6 +61,7 @@ and don't change to frequently.</p>  fonts                = fonts     or { }  fonts.otf            = fonts.otf or { } +fonts.tfm            = fonts.tfm or { }  local otf            = fonts.otf  local tfm            = fonts.tfm @@ -78,12 +79,14 @@ otf.features.list    = otf.features.list    or { }  otf.features.default = otf.features.default or { }  otf.enhancers        = otf.enhancers        or { } +otf.glists           = { "gsub", "gpos" } -otf.version          = 2.619 -otf.pack             = true +otf.version          = 2.626 -- beware: also sync font-mis.lua +otf.pack             = true  -- beware: also sync font-mis.lua  otf.syncspace        = true  otf.notdef           = false  otf.cache            = containers.define("fonts", "otf", otf.version, true) +otf.cleanup_aat      = false -- only context  --[[ldx--  <p>We start with a lot of tables and related functions.</p> @@ -197,13 +200,16 @@ local enhancers = {      -- away from the enhancers namespace      "patch bugs",      "merge cid fonts", "prepare unicode", "cleanup ttf tables", "compact glyphs", "reverse coverage", -    "enrich with features", +    "cleanup aat", "enrich with features", "add some missing characters",      "reorganize kerns", -- moved here      "flatten glyph lookups", "flatten anchor tables", "flatten feature tables", -    "prepare luatex tables", "analyse features", "analyse anchors", "analyse marks", "analyse unicodes", "analyse subtables", +    "prepare luatex tables", +    "analyse features", "rehash features", +    "analyse anchors", "analyse marks", "analyse unicodes", "analyse subtables",      "check italic correction","check math",      "share widths",      "strip not needed data", +    "migrate metadata",  }  function otf.load(filename,format,sub,featurefile) @@ -213,11 +219,10 @@ function otf.load(filename,format,sub,featurefile)      end      if sub == "" then sub = false end      local hash = name -    if sub then -- name cleanup will move to cache code +    if sub then          hash = hash .. "-" .. sub -        hash = lower(hash) -        hash = gsub(hash,"[^%w%d]+","-")      end +    hash = containers.cleanname(hash)      local data = containers.read(otf.cache(), hash)      local size = lfs.attributes(filename,"size") or 0      if not data or data.verbose ~= fonts.verbose or data.size ~= size then @@ -261,7 +266,7 @@ function otf.load(filename,format,sub,featurefile)          end      end      if data then -        otf.enhance("unpack",data,filename,false) -- no mesage here +        otf.enhance("unpack",data,filename,false) -- no message here          otf.add_dimensions(data)          if trace_sequences then              otf.show_feature_order(data,filename) @@ -356,6 +361,11 @@ otf.enhancers["prepare luatex tables"] = function(data,filename)      luatex.creator = "context mkiv"  end +otf.enhancers["cleanup aat"] = function(data,filename) +    if otf.cleanup_aat then +    end +end +  local function analyze_features(g, features)      if g then          local t, done = { }, { } @@ -380,9 +390,40 @@ local function analyze_features(g, features)  end  otf.enhancers["analyse features"] = function(data,filename) -    local luatex = data.luatex -    luatex.gposfeatures = analyze_features(data.gpos) -    luatex.gsubfeatures = analyze_features(data.gsub) + -- local luatex = data.luatex + -- luatex.gposfeatures = analyze_features(data.gpos) + -- luatex.gsubfeatures = analyze_features(data.gsub) +end + +otf.enhancers["rehash features"] = function(data,filename) +    local features = { } +    data.luatex.features = features +    for k, what in next, otf.glists do +        local dw = data[what] +        if dw then +            local f = { } +            features[what] = f +            for i=1,#dw do +                local d= dw[i] +                local dfeatures = d.features +                if dfeatures then +                    for i=1,#dfeatures do +                        local df = dfeatures[i] +                        local tag = strip(lower(df.tag)) +                        local ft = f[tag] if not ft then ft = {} f[tag] = ft end +                        local dscripts = df.scripts +                        for script, languages in next, dscripts do +                            script = strip(lower(script)) +                            local fts = ft[script] if not fts then fts = {} ft[script] = fts end +                            for i=1,#languages do +                                fts[strip(lower(languages[i]))] = true +                            end +                        end +                    end +                end +            end +        end +    end  end  otf.enhancers["analyse anchors"] = function(data,filename) @@ -433,6 +474,7 @@ local ligsplitter = lpeg.Ct(other * (lpeg.P("_") * other)^0)  otf.enhancers["analyse unicodes"] = function(data,filename)      local unicodes = data.luatex.unicodes +    -- we need to move this code      unicodes['space']  = unicodes['space']  or 32   -- handly later on      unicodes['hyphen'] = unicodes['hyphen'] or 45   -- handly later on      unicodes['zwj']    = unicodes['zwj']    or zwj  -- handly later on @@ -616,7 +658,18 @@ otf.enhancers["prepare unicode"] = function(data,filename)      if not luatex then luatex = { } data.luatex = luatex end      local indices, unicodes, multiples, internals = { }, { }, { }, { }      local glyphs = data.glyphs -    local mapmap = data.map.map +    local mapmap = data.map +    if not mapmap then +        logs.report("load otf","no map in %s",filename) +        mapmap = { } +        data.map = { map = mapmap } +    elseif not mapmap.map then +        logs.report("load otf","no unicode map in %s",filename) +        mapmap = { } +        data.map.map = mapmap +    else +        mapmap = mapmap.map +    end      local criterium = fonts.private      local private = fonts.private      for index, glyph in next, glyphs do @@ -720,6 +773,7 @@ end  otf.enhancers["check italic correction"] = function(data,filename)      local glyphs = data.glyphs +    local ok = false      for index, glyph in next, glyphs do          local ic = glyph.italic_correction          if ic then @@ -727,8 +781,12 @@ otf.enhancers["check italic correction"] = function(data,filename)                  glyph.italic = ic              end              glyph.italic_correction = nil +            ok = true          end      end +    -- we can use this to avoid calculations +    otf.tables.valid_fields[#otf.tables.valid_fields+1] = "has_italic" +    data.has_italic = true  end  otf.enhancers["check math"] = function(data,filename) @@ -993,6 +1051,9 @@ otf.enhancers["strip not needed data"] = function(data,filename)          data.gsub = nil          data.anchor_classes = nil      end +end + +otf.enhancers["migrate metadata"] = function(data,filename)      local global_fields = otf.tables.global_fields      local metadata = { }      for k,v in next, data do @@ -1082,7 +1143,7 @@ end  otf.enhancers["flatten feature tables"] = function(data,filename)      -- is this needed? do we still use them at all? -    for _, tag in next, { "gsub", "gpos" } do +    for _, tag in next, otf.glists do          if data[tag] then              if trace_loading then                  logs.report("load otf", "flattening %s table", tag) @@ -1229,6 +1290,7 @@ function otf.otf_to_tfm(specification)                  tfmdata.marks = otfdata.luatex.marks                  tfmdata.originals = otfdata.luatex.originals                  tfmdata.changed = { } +                tfmdata.has_italic = otfdata.metadata.has_italic                  if not tfmdata.language then tfmdata.language = 'dflt' end                  if not tfmdata.script   then tfmdata.script   = 'dflt' end                  shared.processes, shared.features = otf.set_features(tfmdata,fonts.define.check(features,otf.features.default)) @@ -1374,14 +1436,11 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th          end          spaceunits = tonumber(spaceunits) or tfm.units/2 -- 500 -- brrr          parameters.slant         = 0 -        parameters.space         = spaceunits -        parameters.space_stretch = tfm.units/2   --  500 -     -- parameters.space_shrink  = 2*tfm.units/3 --  333 -        parameters.space_shrink  = 1*tfm.units/3 --  333 -     -- parameters.x_height      = 4*tfm.units/5 --  400 +        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 -        parameters.extra_space   = 0          if spaceunits < 2*tfm.units/5 then              -- todo: warning          end @@ -1399,6 +1458,7 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th              parameters.space_stretch = spaceunits/2              parameters.space_shrink  = spaceunits/3          end +        parameters.extra_space = parameters.space_shrink -- 1.111 (cmr10)          if pfminfo.os2_xheight and pfminfo.os2_xheight > 0 then              parameters.x_height = pfminfo.os2_xheight          else @@ -1479,106 +1539,3 @@ function tfm.read_from_open_type(specification)      end      return tfmtable  end - -local a_to_script   = { }  otf.a_to_script   = a_to_script -local a_to_language = { }  otf.a_to_language = a_to_language - -otf.default_language = 'latn' -otf.default_script   = 'dflt' - -local context_setups  = fonts.define.specify.context_setups -local context_numbers = fonts.define.specify.context_numbers - -function otf.set_dynamics(font,dynamics,attribute) -    features = context_setups[context_numbers[attribute]] -- can be moved to caller -    if features then -        local script   = features.script   or 'dflt' -        local language = features.language or 'dflt' -        local ds = dynamics[script] -        if not ds then -            ds = { } -            dynamics[script] = ds -        end -        local dsl = ds[language] -        if not dsl then -            dsl = { } -            ds[language] = dsl -        end -        local dsla = dsl[attribute] -        if dsla then -        --  if trace_dynamics then -        --      logs.report("otf define","using dynamics %s: attribute %s, script %s, language %s",context_numbers[attribute],attribute,script,language) -        --  end -            return dsla -        else -            local tfmdata = fontdata[font] -            a_to_script  [attribute] = script -            a_to_language[attribute] = language -            -- we need to save some values -            local saved = { -                script    = tfmdata.script, -                language  = tfmdata.language, -                mode      = tfmdata.mode, -                features  = tfmdata.shared.features -            } -            tfmdata.mode     = "node" -            tfmdata.language = language -            tfmdata.script   = script -            tfmdata.shared.features = { } -            -- end of save -            dsla = otf.set_features(tfmdata,fonts.define.check(features,otf.features.default)) -            if trace_dynamics then -                logs.report("otf define","setting dynamics %s: attribute %s, script %s, language %s",context_numbers[attribute],attribute,script,language) -            end -            -- we need to restore some values -            tfmdata.script          = saved.script -            tfmdata.language        = saved.language -            tfmdata.mode            = saved.mode -            tfmdata.shared.features = saved.features -            -- end of restore -            dynamics[script][language][attribute] = dsla -- cache -            return dsla -        end -    end -    return nil -- { } -end - --- common stuff - -function otf.features.language(tfmdata,value) -    if value then -        value = lower(value) -        if otf.tables.languages[value] then -            tfmdata.language = value -        end -    end -end - -function otf.features.script(tfmdata,value) -    if value then -        value = lower(value) -        if otf.tables.scripts[value] then -            tfmdata.script = value -        end -    end -end - -function otf.features.mode(tfmdata,value) -    if value then -        tfmdata.mode = lower(value) -    end -end - -fonts.initializers.base.otf.language = otf.features.language -fonts.initializers.base.otf.script   = otf.features.script -fonts.initializers.base.otf.mode     = otf.features.mode -fonts.initializers.base.otf.method   = otf.features.mode - -fonts.initializers.node.otf.language = otf.features.language -fonts.initializers.node.otf.script   = otf.features.script -fonts.initializers.node.otf.mode     = otf.features.mode -fonts.initializers.node.otf.method   = otf.features.mode - -otf.features.register("features",true)     -- we always do features -table.insert(fonts.processors,"features")  -- we need a proper function for doing this - diff --git a/otfl-font-oti.lua b/otfl-font-oti.lua new file mode 100644 index 0000000..cbac6d3 --- /dev/null +++ b/otfl-font-oti.lua @@ -0,0 +1,57 @@ +if not modules then modules = { } end modules ['font-oti'] = { +    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" +} + +-- i need to check features=yes|no also in relation to hashing + +local lower = string.lower + +local otf = fonts.otf + +otf.default_language = 'latn' +otf.default_script   = 'dflt' + +local languages = otf.tables.languages +local scripts   = otf.tables.scripts + +function otf.features.language(tfmdata,value) +    if value then +        value = lower(value) +        if languages[value] then +            tfmdata.language = value +        end +    end +end + +function otf.features.script(tfmdata,value) +    if value then +        value = lower(value) +        if scripts[value] then +            tfmdata.script = value +        end +    end +end + +function otf.features.mode(tfmdata,value) +    if value then +        tfmdata.mode = lower(value) +    end +end + +fonts.initializers.base.otf.language = otf.features.language +fonts.initializers.base.otf.script   = otf.features.script +fonts.initializers.base.otf.mode     = otf.features.mode +fonts.initializers.base.otf.method   = otf.features.mode + +fonts.initializers.node.otf.language = otf.features.language +fonts.initializers.node.otf.script   = otf.features.script +fonts.initializers.node.otf.mode     = otf.features.mode +fonts.initializers.node.otf.method   = otf.features.mode + +otf.features.register("features",true)     -- we always do features +table.insert(fonts.processors,"features")  -- we need a proper function for doing this + diff --git a/otfl-font-otn.lua b/otfl-font-otn.lua index c4c42fa..d23a8a0 100644 --- a/otfl-font-otn.lua +++ b/otfl-font-otn.lua @@ -134,6 +134,8 @@ local trace_cursive      = false  trackers.register("otf.cursive",      function  local trace_preparing    = false  trackers.register("otf.preparing",    function(v) trace_preparing    = v end)  local trace_bugs         = false  trackers.register("otf.bugs",         function(v) trace_bugs         = v end)  local trace_details      = false  trackers.register("otf.details",      function(v) trace_details      = v end) +local trace_applied      = false  trackers.register("otf.applied",      function(v) trace_applied      = v end) +local trace_steps        = false  trackers.register("otf.steps",        function(v) trace_steps        = v end)  trackers.register("otf.verbose_chain", function(v) otf.setcontextchain(v and "verbose") end)  trackers.register("otf.normal_chain",  function(v) otf.setcontextchain(v and "normal")  end) @@ -155,6 +157,7 @@ local has_attribute     = node.has_attribute  local zwnj     = 0x200C  local zwj      = 0x200D  local wildcard = "*" +local default  = "dflt"  local split_at_space = lpeg.Ct(lpeg.splitat(" ")) -- no trailing or multiple spaces anyway @@ -201,11 +204,13 @@ local lookuptable   = false  local anchorlookups = false  local handlers      = { }  local rlmode        = 0 +local featurevalue  = false  -- we cheat a bit and assume that a font,attr combination are kind of ranged  local context_setups  = fonts.define.specify.context_setups  local context_numbers = fonts.define.specify.context_numbers +local context_merged  = fonts.define.specify.context_merged  -- we cannot optimize with "start = first_character(head)" because then we don't  -- know which rlmode we're in which messes up cursive handling later on @@ -226,7 +231,10 @@ local registerstep    = (nodes and nodes.tracers and nodes.tracers.steppers.regi  local registermessage = (nodes and nodes.tracers and nodes.tracers.steppers.message)  or function() end  local function logprocess(...) -    logs.report("otf direct",registermessage(...)) +    if trace_steps then +        registermessage(...) +    end +    logs.report("otf direct",...)  end  local function logwarning(...)      logs.report("otf direct",...) @@ -259,9 +267,9 @@ local function cref(kind,chainname,chainlookupname,lookupname,index)      if index then          return format("feature %s, chain %s, sub %s, lookup %s, index %s",kind,chainname,chainlookupname,lookupname,index)      elseif lookupname then -        return format("feature %s, chain %s, sub %s, lookup %s",kind,chainname,chainlookupname,lookupname) +        return format("feature %s, chain %s, sub %s, lookup %s",kind,chainname or "?",chainlookupname or "?",lookupname)      elseif chainlookupname then -        return format("feature %s, chain %s, sub %s",kind,chainname,chainlookupname) +        return format("feature %s, chain %s, sub %s",kind,chainname or "?",chainlookupname)      elseif chainname then          return format("feature %s, chain %s",kind,chainname)      else @@ -369,7 +377,7 @@ function handlers.gsub_single(start,kind,lookupname,replacement)  end  local function alternative_glyph(start,alternatives,kind,chainname,chainlookupname,lookupname) -- chainname and chainlookupname optional -    local value, choice, n = tfmdata.shared.features[kind], nil, #alternatives +    local value, choice, n = featurevalue or tfmdata.shared.features[kind], nil, #alternatives -- global value, brrr      if value == "random" then          local r = math.random(1,n)          value, choice = format("random, choice %s",r), alternatives[r] @@ -381,6 +389,8 @@ local function alternative_glyph(start,alternatives,kind,chainname,chainlookupna          value, choice = "default, choice 1", alternatives[1]      elseif value > n then          value, choice = format("no %s variants, taking %s",value,n), alternatives[n] +    elseif value == 0 then +        value, choice = format("choice %s (no change)",value), start.char      elseif value < 1 then          value, choice = format("no %s variants, taking %s",value,1), alternatives[1]      else @@ -554,7 +564,7 @@ function handlers.gpos_mark2base(start,kind,lookupname,markanchors,sequence)                  end              else -- if trace_bugs then              --  logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar)) -                fonts.register_missing(currentfont,basechar) +                fonts.register_message(currentfont,basechar,"no base anchors")              end          elseif trace_bugs then              logwarning("%s: prev node is no char",pref(kind,lookupname)) @@ -624,7 +634,7 @@ function handlers.gpos_mark2ligature(start,kind,lookupname,markanchors,sequence)                  end              else -- if trace_bugs then              --  logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar)) -                fonts.register_missing(currentfont,basechar) +                fonts.register_message(currentfont,basechar,"no base anchors")              end          elseif trace_bugs then              logwarning("%s: prev node is no char",pref(kind,lookupname)) @@ -638,8 +648,8 @@ end  function handlers.gpos_mark2mark(start,kind,lookupname,markanchors,sequence)      local markchar = start.char      if marks[markchar] then -        local alreadydone = markonce and has_attribute(start,markmark) -        if not alreadydone then +--~         local alreadydone = markonce and has_attribute(start,markmark) +--~         if not alreadydone then              local base = start.prev -- [glyph] [basemark] [start=mark]              if base and base.id == glyph and base.subtype<256 and base.font == currentfont then -- subtype test can go                  local basechar = base.char @@ -670,14 +680,14 @@ function handlers.gpos_mark2mark(start,kind,lookupname,markanchors,sequence)                      end                  else -- if trace_bugs then                  --  logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar)) -                    fonts.register_missing(currentfont,basechar) +                    fonts.register_message(currentfont,basechar,"no base anchors")                  end              elseif trace_bugs then                  logwarning("%s: prev node is no mark",pref(kind,lookupname))              end -        elseif trace_marks and trace_details then -            logprocess("%s, mark %s is already bound (n=%s), ignoring mark2mark",pref(kind,lookupname),gref(markchar),alreadydone) -        end +--~         elseif trace_marks and trace_details then +--~             logprocess("%s, mark %s is already bound (n=%s), ignoring mark2mark",pref(kind,lookupname),gref(markchar),alreadydone) +--~         end      elseif trace_bugs then          logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar))      end @@ -725,7 +735,7 @@ function handlers.gpos_cursive(start,kind,lookupname,exitanchors,sequence) -- to                          end                      else -- if trace_bugs then                      --  logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(startchar)) -                        fonts.register_missing(currentfont,startchar) +                        fonts.register_message(currentfont,startchar,"no entry anchors")                      end                      break                  end @@ -822,7 +832,10 @@ local chainmores = { }  local chainprocs = { }  local function logprocess(...) -    logs.report("otf subchain",registermessage(...)) +    if trace_steps then +        registermessage(...) +    end +    logs.report("otf subchain",...)  end  local function logwarning(...)      logs.report("otf subchain",...) @@ -862,7 +875,10 @@ end  -- end  local function logprocess(...) -    logs.report("otf chain",registermessage(...)) +    if trace_steps then +        registermessage(...) +    end +    logs.report("otf chain",...)  end  local function logwarning(...)      logs.report("otf chain",...) @@ -1270,8 +1286,8 @@ end  function chainprocs.gpos_mark2mark(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)      local markchar = start.char      if marks[markchar] then -        local alreadydone = markonce and has_attribute(start,markmark) -        if not alreadydone then +--~         local alreadydone = markonce and has_attribute(start,markmark) +--~         if not alreadydone then          --  local markanchors = descriptions[markchar].anchors markanchors = markanchors and markanchors.mark              local subtables = currentlookup.subtables              local lookupname = subtables[1] @@ -1312,9 +1328,9 @@ function chainprocs.gpos_mark2mark(start,stop,kind,chainname,currentcontext,cach              elseif trace_bugs then                  logwarning("%s: mark %s has no anchors",cref(kind,chainname,chainlookupname,lookupname),gref(markchar))              end -        elseif trace_marks and trace_details then -            logprocess("%s, mark %s is already bound (n=%s), ignoring mark2mark",pref(kind,lookupname),gref(markchar),alreadydone) -        end +--~         elseif trace_marks and trace_details then +--~             logprocess("%s, mark %s is already bound (n=%s), ignoring mark2mark",pref(kind,lookupname),gref(markchar),alreadydone) +--~         end      elseif trace_bugs then          logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar))      end @@ -1371,7 +1387,7 @@ function chainprocs.gpos_cursive(start,stop,kind,chainname,currentcontext,cache,                              end                          else -- if trace_bugs then                          --  logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(startchar)) -                            fonts.register_missing(currentfont,startchar) +                            fonts.register_message(currentfont,startchar,"no entry anchors")                          end                          break                      end @@ -1761,7 +1777,10 @@ otf.setcontextchain()  local missing = { } -- we only report once  local function logprocess(...) -    logs.report("otf process",registermessage(...)) +    if trace_steps then +        registermessage(...) +    end +    logs.report("otf process",...)  end  local function logwarning(...)      logs.report("otf process",...) @@ -1798,14 +1817,21 @@ function fonts.methods.node.otf.features(head,font,attr)      local sequences = luatex.sequences      lookuptable = luatex.lookups      local done = false -    local script, language, enabled -    if attr and attr > 0 then +    local script, language, s_enabled, a_enabled, dyn +    local attribute_driven = attr and attr ~= 0 +    if attribute_driven then          local features = context_setups[context_numbers[attr]] -- could be a direct list +        dyn = context_merged[attr] or 0          language, script = features.language or "dflt", features.script or "dflt" -        enabled = features -- shared.features -- can be made local to the resolver +        a_enabled = features -- shared.features -- can be made local to the resolver +        if dyn == 2 or dyn == -2 then +            -- font based +            s_enabled = shared.features +        end      else          language, script = tfmdata.language or "dflt", tfmdata.script or "dflt" -        enabled = shared.features -- can be made local to the resolver +        s_enabled = shared.features -- can be made local to the resolver +        dyn = 0      end      -- we can save some runtime by caching feature tests      local res = resolved[font]     if not res   then res = { } resolved[font]     = res end @@ -1817,44 +1843,62 @@ function fonts.methods.node.otf.features(head,font,attr)          local success = false          local sequence = sequences[s]          local r = ra[s] -- cache -        if not r then -            local typ = sequence.type -            -- we could save this in the tma/c file ---~             local chain ---~             if typ == "gsub_contextchain" or typ == "gpos_contextchain" then ---~                 chain = 1 ---~             elseif typ == "gsub_reversecontextchain" or typ == "gpos_reversecontextchain" then ---~                 chain = -1 ---~             else ---~                 chain = 0 ---~             end -local chain = sequence.chain or 0 +        if r == nil then +            -- +            -- this bit will move to font-ctx and become a function +            --- +            local chain = sequence.chain or 0              local features = sequence.features              if not features then                  -- indirect lookup, part of chain (todo: make this a separate table) -                r = { false, false, chain } +                r = false -- { false, false, chain }              else -                local valid, attribute, kind = false, false +                local valid, attribute, kind, what = false, false                  for k,v in next, features do -                    if enabled[k] then +                    -- we can quit earlier but for the moment we want the tracing +                    local s_e = s_enabled and s_enabled[k] +                    local a_e = a_enabled and a_enabled[k] +                    if s_e or a_e then                          local l = v[script] or v[wildcard] -                        if l and (l[language] or l[wildcard]) then -                            valid = true -                            kind = k -                            attribute = special_attributes[k] or false -- only first, so we assume simple fina's -                            break +                        if l then +                            -- not l[language] or l[default] or l[wildcard] because we want tracing +                            -- only first attribute match check, so we assume simple fina's +                            -- default can become a font feature itself +                            if l[language] then +--~                                 valid, what = true, language +                                valid, what = s_e or a_e, language +                        --  elseif l[default] then +                        --      valid, what = true, default +                            elseif l[wildcard] then +--~                                 valid, what = true, wildcard +                                valid, what = s_e or a_e, wildcard +                            end +                            if valid then +                                kind, attribute = k, special_attributes[k] or false +                                if a_e and dyn < 0 then +                                    valid = false +                                end +                                if trace_applied then +                                    local typ, action = match(sequence.type,"(.*)_(.*)") +                                    logs.report("otf node mode", +                                        "%s font: %03i, dynamic: %03i, kind: %s, lookup: %3i, script: %-4s, language: %-4s (%-4s), type: %s, action: %s, name: %s", +                                        (valid and "+") or "-",font,attr or 0,kind,s,script,language,what,typ,action,sequence.name) +                                end +                                break +                            end                          end                      end                  end -                if kind then +                if valid then                      r = { valid, attribute, chain, kind }                  else -                    r = { valid, attribute, chain, "generic" } -- false anyway +                    r = false -- { valid, attribute, chain, "generic" } -- false anyway, could be flag instead of table                  end              end              ra[s] = r          end -        if r[1] then -- valid +        featurevalue = r and r[1] -- todo: pass to function instead of using a global +        if featurevalue then              local attribute, chain, typ, subtables = r[2], r[3], sequence.type, sequence.subtables              if chain < 0 then                  -- this is a limited case, no special treatments like 'init' etc @@ -1865,7 +1909,8 @@ local chain = sequence.chain or 0                  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 (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] @@ -1904,7 +1949,8 @@ local chain = sequence.chain or 0                          while start do                              local id = start.id                              if id == glyph 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 +--~                                 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 +                                if start.font == font and start.subtype<256 and 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 @@ -1965,7 +2011,8 @@ local chain = sequence.chain or 0                      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 (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] @@ -2034,9 +2081,9 @@ local chain = sequence.chain or 0              if success then                  done = true              end ---~ if trace_steps then -            registerstep(head) ---~ end +            if trace_steps then -- ? +                registerstep(head) +            end          end      end      return head, done diff --git a/otfl-font-ott.lua b/otfl-font-ott.lua new file mode 100644 index 0000000..6676ff6 --- /dev/null +++ b/otfl-font-ott.lua @@ -0,0 +1,935 @@ +if not modules then modules = { } end modules ['font-otf'] = { +    version   = 1.001, +    comment   = "companion to font-otf.lua (tables)", +    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL", +    copyright = "PRAGMA ADE / ConTeXt Development Team", +    license   = "see context related readme files" +} + +local type, next, tonumber, tostring = type, next, tonumber, tostring +local gsub, lower = string.gsub, string.lower + +fonts     = fonts     or { } +fonts.otf = fonts.otf or { } + +local otf = fonts.otf + +otf.tables   = otf.tables   or { } +otf.meanings = otf.meanings or { } + +otf.tables.scripts = { +    ['dflt'] = 'Default', + +    ['arab'] = 'Arabic', +    ['armn'] = 'Armenian', +    ['bali'] = 'Balinese', +    ['beng'] = 'Bengali', +    ['bopo'] = 'Bopomofo', +    ['brai'] = 'Braille', +    ['bugi'] = 'Buginese', +    ['buhd'] = 'Buhid', +    ['byzm'] = 'Byzantine Music', +    ['cans'] = 'Canadian Syllabics', +    ['cher'] = 'Cherokee', +    ['copt'] = 'Coptic', +    ['cprt'] = 'Cypriot Syllabary', +    ['cyrl'] = 'Cyrillic', +    ['deva'] = 'Devanagari', +    ['dsrt'] = 'Deseret', +    ['ethi'] = 'Ethiopic', +    ['geor'] = 'Georgian', +    ['glag'] = 'Glagolitic', +    ['goth'] = 'Gothic', +    ['grek'] = 'Greek', +    ['gujr'] = 'Gujarati', +    ['guru'] = 'Gurmukhi', +    ['hang'] = 'Hangul', +    ['hani'] = 'CJK Ideographic', +    ['hano'] = 'Hanunoo', +    ['hebr'] = 'Hebrew', +    ['ital'] = 'Old Italic', +    ['jamo'] = 'Hangul Jamo', +    ['java'] = 'Javanese', +    ['kana'] = 'Hiragana and Katakana', +    ['khar'] = 'Kharosthi', +    ['khmr'] = 'Khmer', +    ['knda'] = 'Kannada', +    ['lao' ] = 'Lao', +    ['latn'] = 'Latin', +    ['limb'] = 'Limbu', +    ['linb'] = 'Linear B', +    ['math'] = 'Mathematical Alphanumeric Symbols', +    ['mlym'] = 'Malayalam', +    ['mong'] = 'Mongolian', +    ['musc'] = 'Musical Symbols', +    ['mymr'] = 'Myanmar', +    ['nko' ] = "N'ko", +    ['ogam'] = 'Ogham', +    ['orya'] = 'Oriya', +    ['osma'] = 'Osmanya', +    ['phag'] = 'Phags-pa', +    ['phnx'] = 'Phoenician', +    ['runr'] = 'Runic', +    ['shaw'] = 'Shavian', +    ['sinh'] = 'Sinhala', +    ['sylo'] = 'Syloti Nagri', +    ['syrc'] = 'Syriac', +    ['tagb'] = 'Tagbanwa', +    ['tale'] = 'Tai Le', +    ['talu'] = 'Tai Lu', +    ['taml'] = 'Tamil', +    ['telu'] = 'Telugu', +    ['tfng'] = 'Tifinagh', +    ['tglg'] = 'Tagalog', +    ['thaa'] = 'Thaana', +    ['thai'] = 'Thai', +    ['tibt'] = 'Tibetan', +    ['ugar'] = 'Ugaritic Cuneiform', +    ['xpeo'] = 'Old Persian Cuneiform', +    ['xsux'] = 'Sumero-Akkadian Cuneiform', +    ['yi'  ] = 'Yi' +} + +otf.tables.languages = { +    ['dflt'] = 'Default', + +    ['aba'] = 'Abaza', +    ['abk'] = 'Abkhazian', +    ['ady'] = 'Adyghe', +    ['afk'] = 'Afrikaans', +    ['afr'] = 'Afar', +    ['agw'] = 'Agaw', +    ['als'] = 'Alsatian', +    ['alt'] = 'Altai', +    ['amh'] = 'Amharic', +    ['ara'] = 'Arabic', +    ['ari'] = 'Aari', +    ['ark'] = 'Arakanese', +    ['asm'] = 'Assamese', +    ['ath'] = 'Athapaskan', +    ['avr'] = 'Avar', +    ['awa'] = 'Awadhi', +    ['aym'] = 'Aymara', +    ['aze'] = 'Azeri', +    ['bad'] = 'Badaga', +    ['bag'] = 'Baghelkhandi', +    ['bal'] = 'Balkar', +    ['bau'] = 'Baule', +    ['bbr'] = 'Berber', +    ['bch'] = 'Bench', +    ['bcr'] = 'Bible Cree', +    ['bel'] = 'Belarussian', +    ['bem'] = 'Bemba', +    ['ben'] = 'Bengali', +    ['bgr'] = 'Bulgarian', +    ['bhi'] = 'Bhili', +    ['bho'] = 'Bhojpuri', +    ['bik'] = 'Bikol', +    ['bil'] = 'Bilen', +    ['bkf'] = 'Blackfoot', +    ['bli'] = 'Balochi', +    ['bln'] = 'Balante', +    ['blt'] = 'Balti', +    ['bmb'] = 'Bambara', +    ['bml'] = 'Bamileke', +    ['bos'] = 'Bosnian', +    ['bre'] = 'Breton', +    ['brh'] = 'Brahui', +    ['bri'] = 'Braj Bhasha', +    ['brm'] = 'Burmese', +    ['bsh'] = 'Bashkir', +    ['bti'] = 'Beti', +    ['cat'] = 'Catalan', +    ['ceb'] = 'Cebuano', +    ['che'] = 'Chechen', +    ['chg'] = 'Chaha Gurage', +    ['chh'] = 'Chattisgarhi', +    ['chi'] = 'Chichewa', +    ['chk'] = 'Chukchi', +    ['chp'] = 'Chipewyan', +    ['chr'] = 'Cherokee', +    ['chu'] = 'Chuvash', +    ['cmr'] = 'Comorian', +    ['cop'] = 'Coptic', +    ['cos'] = 'Corsican', +    ['cre'] = 'Cree', +    ['crr'] = 'Carrier', +    ['crt'] = 'Crimean Tatar', +    ['csl'] = 'Church Slavonic', +    ['csy'] = 'Czech', +    ['dan'] = 'Danish', +    ['dar'] = 'Dargwa', +    ['dcr'] = 'Woods Cree', +    ['deu'] = 'German', +    ['dgr'] = 'Dogri', +    ['div'] = 'Divehi', +    ['djr'] = 'Djerma', +    ['dng'] = 'Dangme', +    ['dnk'] = 'Dinka', +    ['dri'] = 'Dari', +    ['dun'] = 'Dungan', +    ['dzn'] = 'Dzongkha', +    ['ebi'] = 'Ebira', +    ['ecr'] = 'Eastern Cree', +    ['edo'] = 'Edo', +    ['efi'] = 'Efik', +    ['ell'] = 'Greek', +    ['eng'] = 'English', +    ['erz'] = 'Erzya', +    ['esp'] = 'Spanish', +    ['eti'] = 'Estonian', +    ['euq'] = 'Basque', +    ['evk'] = 'Evenki', +    ['evn'] = 'Even', +    ['ewe'] = 'Ewe', +    ['fan'] = 'French Antillean', +    ['far'] = 'Farsi', +    ['fin'] = 'Finnish', +    ['fji'] = 'Fijian', +    ['fle'] = 'Flemish', +    ['fne'] = 'Forest Nenets', +    ['fon'] = 'Fon', +    ['fos'] = 'Faroese', +    ['fra'] = 'French', +    ['fri'] = 'Frisian', +    ['frl'] = 'Friulian', +    ['fta'] = 'Futa', +    ['ful'] = 'Fulani', +    ['gad'] = 'Ga', +    ['gae'] = 'Gaelic', +    ['gag'] = 'Gagauz', +    ['gal'] = 'Galician', +    ['gar'] = 'Garshuni', +    ['gaw'] = 'Garhwali', +    ['gez'] = "Ge'ez", +    ['gil'] = 'Gilyak', +    ['gmz'] = 'Gumuz', +    ['gon'] = 'Gondi', +    ['grn'] = 'Greenlandic', +    ['gro'] = 'Garo', +    ['gua'] = 'Guarani', +    ['guj'] = 'Gujarati', +    ['hai'] = 'Haitian', +    ['hal'] = 'Halam', +    ['har'] = 'Harauti', +    ['hau'] = 'Hausa', +    ['haw'] = 'Hawaiin', +    ['hbn'] = 'Hammer-Banna', +    ['hil'] = 'Hiligaynon', +    ['hin'] = 'Hindi', +    ['hma'] = 'High Mari', +    ['hnd'] = 'Hindko', +    ['ho']  = 'Ho', +    ['hri'] = 'Harari', +    ['hrv'] = 'Croatian', +    ['hun'] = 'Hungarian', +    ['hye'] = 'Armenian', +    ['ibo'] = 'Igbo', +    ['ijo'] = 'Ijo', +    ['ilo'] = 'Ilokano', +    ['ind'] = 'Indonesian', +    ['ing'] = 'Ingush', +    ['inu'] = 'Inuktitut', +    ['iri'] = 'Irish', +    ['irt'] = 'Irish Traditional', +    ['isl'] = 'Icelandic', +    ['ism'] = 'Inari Sami', +    ['ita'] = 'Italian', +    ['iwr'] = 'Hebrew', +    ['jan'] = 'Japanese', +    ['jav'] = 'Javanese', +    ['jii'] = 'Yiddish', +    ['jud'] = 'Judezmo', +    ['jul'] = 'Jula', +    ['kab'] = 'Kabardian', +    ['kac'] = 'Kachchi', +    ['kal'] = 'Kalenjin', +    ['kan'] = 'Kannada', +    ['kar'] = 'Karachay', +    ['kat'] = 'Georgian', +    ['kaz'] = 'Kazakh', +    ['keb'] = 'Kebena', +    ['kge'] = 'Khutsuri Georgian', +    ['kha'] = 'Khakass', +    ['khk'] = 'Khanty-Kazim', +    ['khm'] = 'Khmer', +    ['khs'] = 'Khanty-Shurishkar', +    ['khv'] = 'Khanty-Vakhi', +    ['khw'] = 'Khowar', +    ['kik'] = 'Kikuyu', +    ['kir'] = 'Kirghiz', +    ['kis'] = 'Kisii', +    ['kkn'] = 'Kokni', +    ['klm'] = 'Kalmyk', +    ['kmb'] = 'Kamba', +    ['kmn'] = 'Kumaoni', +    ['kmo'] = 'Komo', +    ['kms'] = 'Komso', +    ['knr'] = 'Kanuri', +    ['kod'] = 'Kodagu', +    ['koh'] = 'Korean Old Hangul', +    ['kok'] = 'Konkani', +    ['kon'] = 'Kikongo', +    ['kop'] = 'Komi-Permyak', +    ['kor'] = 'Korean', +    ['koz'] = 'Komi-Zyrian', +    ['kpl'] = 'Kpelle', +    ['kri'] = 'Krio', +    ['krk'] = 'Karakalpak', +    ['krl'] = 'Karelian', +    ['krm'] = 'Karaim', +    ['krn'] = 'Karen', +    ['krt'] = 'Koorete', +    ['ksh'] = 'Kashmiri', +    ['ksi'] = 'Khasi', +    ['ksm'] = 'Kildin Sami', +    ['kui'] = 'Kui', +    ['kul'] = 'Kulvi', +    ['kum'] = 'Kumyk', +    ['kur'] = 'Kurdish', +    ['kuu'] = 'Kurukh', +    ['kuy'] = 'Kuy', +    ['kyk'] = 'Koryak', +    ['lad'] = 'Ladin', +    ['lah'] = 'Lahuli', +    ['lak'] = 'Lak', +    ['lam'] = 'Lambani', +    ['lao'] = 'Lao', +    ['lat'] = 'Latin', +    ['laz'] = 'Laz', +    ['lcr'] = 'L-Cree', +    ['ldk'] = 'Ladakhi', +    ['lez'] = 'Lezgi', +    ['lin'] = 'Lingala', +    ['lma'] = 'Low Mari', +    ['lmb'] = 'Limbu', +    ['lmw'] = 'Lomwe', +    ['lsb'] = 'Lower Sorbian', +    ['lsm'] = 'Lule Sami', +    ['lth'] = 'Lithuanian', +    ['ltz'] = 'Luxembourgish', +    ['lub'] = 'Luba', +    ['lug'] = 'Luganda', +    ['luh'] = 'Luhya', +    ['luo'] = 'Luo', +    ['lvi'] = 'Latvian', +    ['maj'] = 'Majang', +    ['mak'] = 'Makua', +    ['mal'] = 'Malayalam Traditional', +    ['man'] = 'Mansi', +    ['map'] = 'Mapudungun', +    ['mar'] = 'Marathi', +    ['maw'] = 'Marwari', +    ['mbn'] = 'Mbundu', +    ['mch'] = 'Manchu', +    ['mcr'] = 'Moose Cree', +    ['mde'] = 'Mende', +    ['men'] = "Me'en", +    ['miz'] = 'Mizo', +    ['mkd'] = 'Macedonian', +    ['mle'] = 'Male', +    ['mlg'] = 'Malagasy', +    ['mln'] = 'Malinke', +    ['mlr'] = 'Malayalam Reformed', +    ['mly'] = 'Malay', +    ['mnd'] = 'Mandinka', +    ['mng'] = 'Mongolian', +    ['mni'] = 'Manipuri', +    ['mnk'] = 'Maninka', +    ['mnx'] = 'Manx Gaelic', +    ['moh'] = 'Mohawk', +    ['mok'] = 'Moksha', +    ['mol'] = 'Moldavian', +    ['mon'] = 'Mon', +    ['mor'] = 'Moroccan', +    ['mri'] = 'Maori', +    ['mth'] = 'Maithili', +    ['mts'] = 'Maltese', +    ['mun'] = 'Mundari', +    ['nag'] = 'Naga-Assamese', +    ['nan'] = 'Nanai', +    ['nas'] = 'Naskapi', +    ['ncr'] = 'N-Cree', +    ['ndb'] = 'Ndebele', +    ['ndg'] = 'Ndonga', +    ['nep'] = 'Nepali', +    ['new'] = 'Newari', +    ['ngr'] = 'Nagari', +    ['nhc'] = 'Norway House Cree', +    ['nis'] = 'Nisi', +    ['niu'] = 'Niuean', +    ['nkl'] = 'Nkole', +    ['nko'] = "N'ko", +    ['nld'] = 'Dutch', +    ['nog'] = 'Nogai', +    ['nor'] = 'Norwegian', +    ['nsm'] = 'Northern Sami', +    ['nta'] = 'Northern Tai', +    ['nto'] = 'Esperanto', +    ['nyn'] = 'Nynorsk', +    ['oci'] = 'Occitan', +    ['ocr'] = 'Oji-Cree', +    ['ojb'] = 'Ojibway', +    ['ori'] = 'Oriya', +    ['oro'] = 'Oromo', +    ['oss'] = 'Ossetian', +    ['paa'] = 'Palestinian Aramaic', +    ['pal'] = 'Pali', +    ['pan'] = 'Punjabi', +    ['pap'] = 'Palpa', +    ['pas'] = 'Pashto', +    ['pgr'] = 'Polytonic Greek', +    ['pil'] = 'Pilipino', +    ['plg'] = 'Palaung', +    ['plk'] = 'Polish', +    ['pro'] = 'Provencal', +    ['ptg'] = 'Portuguese', +    ['qin'] = 'Chin', +    ['raj'] = 'Rajasthani', +    ['rbu'] = 'Russian Buriat', +    ['rcr'] = 'R-Cree', +    ['ria'] = 'Riang', +    ['rms'] = 'Rhaeto-Romanic', +    ['rom'] = 'Romanian', +    ['roy'] = 'Romany', +    ['rsy'] = 'Rusyn', +    ['rua'] = 'Ruanda', +    ['rus'] = 'Russian', +    ['sad'] = 'Sadri', +    ['san'] = 'Sanskrit', +    ['sat'] = 'Santali', +    ['say'] = 'Sayisi', +    ['sek'] = 'Sekota', +    ['sel'] = 'Selkup', +    ['sgo'] = 'Sango', +    ['shn'] = 'Shan', +    ['sib'] = 'Sibe', +    ['sid'] = 'Sidamo', +    ['sig'] = 'Silte Gurage', +    ['sks'] = 'Skolt Sami', +    ['sky'] = 'Slovak', +    ['sla'] = 'Slavey', +    ['slv'] = 'Slovenian', +    ['sml'] = 'Somali', +    ['smo'] = 'Samoan', +    ['sna'] = 'Sena', +    ['snd'] = 'Sindhi', +    ['snh'] = 'Sinhalese', +    ['snk'] = 'Soninke', +    ['sog'] = 'Sodo Gurage', +    ['sot'] = 'Sotho', +    ['sqi'] = 'Albanian', +    ['srb'] = 'Serbian', +    ['srk'] = 'Saraiki', +    ['srr'] = 'Serer', +    ['ssl'] = 'South Slavey', +    ['ssm'] = 'Southern Sami', +    ['sur'] = 'Suri', +    ['sva'] = 'Svan', +    ['sve'] = 'Swedish', +    ['swa'] = 'Swadaya Aramaic', +    ['swk'] = 'Swahili', +    ['swz'] = 'Swazi', +    ['sxt'] = 'Sutu', +    ['syr'] = 'Syriac', +    ['tab'] = 'Tabasaran', +    ['taj'] = 'Tajiki', +    ['tam'] = 'Tamil', +    ['tat'] = 'Tatar', +    ['tcr'] = 'TH-Cree', +    ['tel'] = 'Telugu', +    ['tgn'] = 'Tongan', +    ['tgr'] = 'Tigre', +    ['tgy'] = 'Tigrinya', +    ['tha'] = 'Thai', +    ['tht'] = 'Tahitian', +    ['tib'] = 'Tibetan', +    ['tkm'] = 'Turkmen', +    ['tmn'] = 'Temne', +    ['tna'] = 'Tswana', +    ['tne'] = 'Tundra Nenets', +    ['tng'] = 'Tonga', +    ['tod'] = 'Todo', +    ['trk'] = 'Turkish', +    ['tsg'] = 'Tsonga', +    ['tua'] = 'Turoyo Aramaic', +    ['tul'] = 'Tulu', +    ['tuv'] = 'Tuvin', +    ['twi'] = 'Twi', +    ['udm'] = 'Udmurt', +    ['ukr'] = 'Ukrainian', +    ['urd'] = 'Urdu', +    ['usb'] = 'Upper Sorbian', +    ['uyg'] = 'Uyghur', +    ['uzb'] = 'Uzbek', +    ['ven'] = 'Venda', +    ['vit'] = 'Vietnamese', +    ['wa' ] = 'Wa', +    ['wag'] = 'Wagdi', +    ['wcr'] = 'West-Cree', +    ['wel'] = 'Welsh', +    ['wlf'] = 'Wolof', +    ['xbd'] = 'Tai Lue', +    ['xhs'] = 'Xhosa', +    ['yak'] = 'Yakut', +    ['yba'] = 'Yoruba', +    ['ycr'] = 'Y-Cree', +    ['yic'] = 'Yi Classic', +    ['yim'] = 'Yi Modern', +    ['zhh'] = 'Chinese Hong Kong', +    ['zhp'] = 'Chinese Phonetic', +    ['zhs'] = 'Chinese Simplified', +    ['zht'] = 'Chinese Traditional', +    ['znd'] = 'Zande', +    ['zul'] = 'Zulu' +} + +otf.tables.features = { +    ['aalt'] = 'Access All Alternates', +    ['abvf'] = 'Above-Base Forms', +    ['abvm'] = 'Above-Base Mark Positioning', +    ['abvs'] = 'Above-Base Substitutions', +    ['afrc'] = 'Alternative Fractions', +    ['akhn'] = 'Akhands', +    ['blwf'] = 'Below-Base Forms', +    ['blwm'] = 'Below-Base Mark Positioning', +    ['blws'] = 'Below-Base Substitutions', +    ['c2pc'] = 'Petite Capitals From Capitals', +    ['c2sc'] = 'Small Capitals From Capitals', +    ['calt'] = 'Contextual Alternates', +    ['case'] = 'Case-Sensitive Forms', +    ['ccmp'] = 'Glyph Composition/Decomposition', +    ['cjct'] = 'Conjunct Forms', +    ['clig'] = 'Contextual Ligatures', +    ['cpsp'] = 'Capital Spacing', +    ['cswh'] = 'Contextual Swash', +    ['curs'] = 'Cursive Positioning', +    ['dflt'] = 'Default Processing', +    ['dist'] = 'Distances', +    ['dlig'] = 'Discretionary Ligatures', +    ['dnom'] = 'Denominators', +    ['dtls'] = 'Dotless Forms', -- math +    ['expt'] = 'Expert Forms', +    ['falt'] = 'Final glyph Alternates', +    ['fin2'] = 'Terminal Forms #2', +    ['fin3'] = 'Terminal Forms #3', +    ['fina'] = 'Terminal Forms', +    ['flac'] = 'Flattened Accents Over Capitals', -- math +    ['frac'] = 'Fractions', +    ['fwid'] = 'Full Width', +    ['half'] = 'Half Forms', +    ['haln'] = 'Halant Forms', +    ['halt'] = 'Alternate Half Width', +    ['hist'] = 'Historical Forms', +    ['hkna'] = 'Horizontal Kana Alternates', +    ['hlig'] = 'Historical Ligatures', +    ['hngl'] = 'Hangul', +    ['hojo'] = 'Hojo Kanji Forms', +    ['hwid'] = 'Half Width', +    ['init'] = 'Initial Forms', +    ['isol'] = 'Isolated Forms', +    ['ital'] = 'Italics', +    ['jalt'] = 'Justification Alternatives', +    ['jp04'] = 'JIS2004 Forms', +    ['jp78'] = 'JIS78 Forms', +    ['jp83'] = 'JIS83 Forms', +    ['jp90'] = 'JIS90 Forms', +    ['kern'] = 'Kerning', +    ['lfbd'] = 'Left Bounds', +    ['liga'] = 'Standard Ligatures', +    ['ljmo'] = 'Leading Jamo Forms', +    ['lnum'] = 'Lining Figures', +    ['locl'] = 'Localized Forms', +    ['mark'] = 'Mark Positioning', +    ['med2'] = 'Medial Forms #2', +    ['medi'] = 'Medial Forms', +    ['mgrk'] = 'Mathematical Greek', +    ['mkmk'] = 'Mark to Mark Positioning', +    ['mset'] = 'Mark Positioning via Substitution', +    ['nalt'] = 'Alternate Annotation Forms', +    ['nlck'] = 'NLC Kanji Forms', +    ['nukt'] = 'Nukta Forms', +    ['numr'] = 'Numerators', +    ['onum'] = 'Old Style Figures', +    ['opbd'] = 'Optical Bounds', +    ['ordn'] = 'Ordinals', +    ['ornm'] = 'Ornaments', +    ['palt'] = 'Proportional Alternate Width', +    ['pcap'] = 'Petite Capitals', +    ['pnum'] = 'Proportional Figures', +    ['pref'] = 'Pre-base Forms', +    ['pres'] = 'Pre-base Substitutions', +    ['pstf'] = 'Post-base Forms', +    ['psts'] = 'Post-base Substitutions', +    ['pwid'] = 'Proportional Widths', +    ['qwid'] = 'Quarter Widths', +    ['rand'] = 'Randomize', +    ['rkrf'] = 'Rakar Forms', +    ['rlig'] = 'Required Ligatures', +    ['rphf'] = 'Reph Form', +    ['rtbd'] = 'Right Bounds', +    ['rtla'] = 'Right-To-Left Alternates', +    ['ruby'] = 'Ruby Notation Forms', +    ['salt'] = 'Stylistic Alternates', +    ['sinf'] = 'Scientific Inferiors', +    ['size'] = 'Optical Size', +    ['smcp'] = 'Small Capitals', +    ['smpl'] = 'Simplified Forms', +    ['ss01'] = 'Stylistic Set 1', +    ['ss02'] = 'Stylistic Set 2', +    ['ss03'] = 'Stylistic Set 3', +    ['ss04'] = 'Stylistic Set 4', +    ['ss05'] = 'Stylistic Set 5', +    ['ss06'] = 'Stylistic Set 6', +    ['ss07'] = 'Stylistic Set 7', +    ['ss08'] = 'Stylistic Set 8', +    ['ss09'] = 'Stylistic Set 9', +    ['ss10'] = 'Stylistic Set 10', +    ['ss11'] = 'Stylistic Set 11', +    ['ss12'] = 'Stylistic Set 12', +    ['ss13'] = 'Stylistic Set 13', +    ['ss14'] = 'Stylistic Set 14', +    ['ss15'] = 'Stylistic Set 15', +    ['ss16'] = 'Stylistic Set 16', +    ['ss17'] = 'Stylistic Set 17', +    ['ss18'] = 'Stylistic Set 18', +    ['ss19'] = 'Stylistic Set 19', +    ['ss20'] = 'Stylistic Set 20', +    ['ssty'] = 'Script Style', -- math +    ['subs'] = 'Subscript', +    ['sups'] = 'Superscript', +    ['swsh'] = 'Swash', +    ['titl'] = 'Titling', +    ['tjmo'] = 'Trailing Jamo Forms', +    ['tnam'] = 'Traditional Name Forms', +    ['tnum'] = 'Tabular Figures', +    ['trad'] = 'Traditional Forms', +    ['twid'] = 'Third Widths', +    ['unic'] = 'Unicase', +    ['valt'] = 'Alternate Vertical Metrics', +    ['vatu'] = 'Vattu Variants', +    ['vert'] = 'Vertical Writing', +    ['vhal'] = 'Alternate Vertical Half Metrics', +    ['vjmo'] = 'Vowel Jamo Forms', +    ['vkna'] = 'Vertical Kana Alternates', +    ['vkrn'] = 'Vertical Kerning', +    ['vpal'] = 'Proportional Alternate Vertical Metrics', +    ['vrt2'] = 'Vertical Rotation', +    ['zero'] = 'Slashed Zero', + +    ['trep'] = 'Traditional TeX Replacements', +    ['tlig'] = 'Traditional TeX Ligatures', +} + +otf.tables.baselines = { +    ['hang'] = 'Hanging baseline', +    ['icfb'] = 'Ideographic character face bottom edge baseline', +    ['icft'] = 'Ideographic character face tope edige baseline', +    ['ideo'] = 'Ideographic em-box bottom edge baseline', +    ['idtp'] = 'Ideographic em-box top edge baseline', +    ['math'] = 'Mathmatical centered baseline', +    ['romn'] = 'Roman baseline' +} + +-- can be sped up by local tables + +function otf.tables.to_tag(id) +    return stringformat("%4s",lower(id)) +end + +local function resolve(tab,id) +    if tab and id then +        id = lower(id) +        return tab[id] or tab[gsub(id," ","")] or tab['dflt'] or '' +    else +        return "unknown" +    end +end + +function otf.meanings.script(id) +    return resolve(otf.tables.scripts,id) +end +function otf.meanings.language(id) +    return resolve(otf.tables.languages,id) +end +function otf.meanings.feature(id) +    return resolve(otf.tables.features,id) +end +function otf.meanings.baseline(id) +    return resolve(otf.tables.baselines,id) +end + +otf.tables.to_scripts   = table.reverse_hash(otf.tables.scripts  ) +otf.tables.to_languages = table.reverse_hash(otf.tables.languages) +otf.tables.to_features  = table.reverse_hash(otf.tables.features ) + +local scripts      = otf.tables.scripts +local languages    = otf.tables.languages +local features     = otf.tables.features + +local to_scripts   = otf.tables.to_scripts +local to_languages = otf.tables.to_languages +local to_features  = otf.tables.to_features + +function otf.meanings.normalize(features) +    local h = { } +    for k,v in next, features do +        k = lower(k) +        if k == "language" or k == "lang" then +            v = gsub(lower(v),"[^a-z0-9%-]","") +            k = language +            if not languages[v] then +                h.language = to_languages[v] or "dflt" +            else +                h.language = v +            end +        elseif k == "script" then +            v = gsub(lower(v),"[^a-z0-9%-]","") +            if not scripts[v] then +                h.script = to_scripts[v] or "dflt" +            else +                h.script = v +            end +        else +            if type(v) == "string" then +                local b = v:is_boolean() +                if type(b) == "nil" then +                    v = tonumber(v) or lower(v) +                else +                    v = b +                end +            end +            h[to_features[k] or k] = v +        end +    end +    return h +end + +-- When I feel the need ... + +--~ otf.tables.aat = { +--~     [ 0] = { +--~         name = "allTypographicFeaturesType", +--~         [ 0] = "allTypeFeaturesOnSelector", +--~         [ 1] = "allTypeFeaturesOffSelector", +--~     }, +--~     [ 1] = { +--~         name = "ligaturesType", +--~         [0 ] = "requiredLigaturesOnSelector", +--~         [1 ] = "requiredLigaturesOffSelector", +--~         [2 ] = "commonLigaturesOnSelector", +--~         [3 ] = "commonLigaturesOffSelector", +--~         [4 ] = "rareLigaturesOnSelector", +--~         [5 ] = "rareLigaturesOffSelector", +--~         [6 ] = "logosOnSelector    ", +--~         [7 ] = "logosOffSelector   ", +--~         [8 ] = "rebusPicturesOnSelector", +--~         [9 ] = "rebusPicturesOffSelector", +--~         [10] = "diphthongLigaturesOnSelector", +--~         [11] = "diphthongLigaturesOffSelector", +--~         [12] = "squaredLigaturesOnSelector", +--~         [13] = "squaredLigaturesOffSelector", +--~         [14] = "abbrevSquaredLigaturesOnSelector", +--~         [15] = "abbrevSquaredLigaturesOffSelector", +--~     }, +--~     [ 2] = { +--~         name = "cursiveConnectionType", +--~         [ 0] = "unconnectedSelector", +--~         [ 1] = "partiallyConnectedSelector", +--~         [ 2] = "cursiveSelector    ", +--~     }, +--~     [ 3] = { +--~         name = "letterCaseType", +--~         [ 0] = "upperAndLowerCaseSelector", +--~         [ 1] = "allCapsSelector    ", +--~         [ 2] = "allLowerCaseSelector", +--~         [ 3] = "smallCapsSelector  ", +--~         [ 4] = "initialCapsSelector", +--~         [ 5] = "initialCapsAndSmallCapsSelector", +--~     }, +--~     [ 4] = { +--~         name = "verticalSubstitutionType", +--~         [ 0] = "substituteVerticalFormsOnSelector", +--~         [ 1] = "substituteVerticalFormsOffSelector", +--~     }, +--~     [ 5] = { +--~         name = "linguisticRearrangementType", +--~         [ 0] = "linguisticRearrangementOnSelector", +--~         [ 1] = "linguisticRearrangementOffSelector", +--~     }, +--~     [ 6] = { +--~         name = "numberSpacingType", +--~         [ 0] = "monospacedNumbersSelector", +--~         [ 1] = "proportionalNumbersSelector", +--~     }, +--~     [ 7] = { +--~         name = "appleReserved1Type", +--~     }, +--~     [ 8] = { +--~         name = "smartSwashType", +--~         [ 0] = "wordInitialSwashesOnSelector", +--~         [ 1] = "wordInitialSwashesOffSelector", +--~         [ 2] = "wordFinalSwashesOnSelector", +--~         [ 3] = "wordFinalSwashesOffSelector", +--~         [ 4] = "lineInitialSwashesOnSelector", +--~         [ 5] = "lineInitialSwashesOffSelector", +--~         [ 6] = "lineFinalSwashesOnSelector", +--~         [ 7] = "lineFinalSwashesOffSelector", +--~         [ 8] = "nonFinalSwashesOnSelector", +--~         [ 9] = "nonFinalSwashesOffSelector", +--~     }, +--~     [ 9] = { +--~         name = "diacriticsType", +--~         [ 0] = "showDiacriticsSelector", +--~         [ 1] = "hideDiacriticsSelector", +--~         [ 2] = "decomposeDiacriticsSelector", +--~     }, +--~     [10] = { +--~         name = "verticalPositionType", +--~         [ 0] = "normalPositionSelector", +--~         [ 1] = "superiorsSelector  ", +--~         [ 2] = "inferiorsSelector  ", +--~         [ 3] = "ordinalsSelector   ", +--~     }, +--~     [11] = { +--~         name = "fractionsType", +--~         [ 0] = "noFractionsSelector", +--~         [ 1] = "verticalFractionsSelector", +--~         [ 2] = "diagonalFractionsSelector", +--~     }, +--~     [12] = { +--~         name = "appleReserved2Type", +--~     }, +--~     [13] = { +--~         name = "overlappingCharactersType", +--~         [ 0] = "preventOverlapOnSelector", +--~         [ 1] = "preventOverlapOffSelector", +--~     }, +--~     [14] = { +--~         name = "typographicExtrasType", +--~          [0 ] = "hyphensToEmDashOnSelector", +--~          [1 ] = "hyphensToEmDashOffSelector", +--~          [2 ] = "hyphenToEnDashOnSelector", +--~          [3 ] = "hyphenToEnDashOffSelector", +--~          [4 ] = "unslashedZeroOnSelector", +--~          [5 ] = "unslashedZeroOffSelector", +--~          [6 ] = "formInterrobangOnSelector", +--~          [7 ] = "formInterrobangOffSelector", +--~          [8 ] = "smartQuotesOnSelector", +--~          [9 ] = "smartQuotesOffSelector", +--~          [10] = "periodsToEllipsisOnSelector", +--~          [11] = "periodsToEllipsisOffSelector", +--~     }, +--~     [15] = { +--~         name = "mathematicalExtrasType", +--~          [ 0] = "hyphenToMinusOnSelector", +--~          [ 1] = "hyphenToMinusOffSelector", +--~          [ 2] = "asteriskToMultiplyOnSelector", +--~          [ 3] = "asteriskToMultiplyOffSelector", +--~          [ 4] = "slashToDivideOnSelector", +--~          [ 5] = "slashToDivideOffSelector", +--~          [ 6] = "inequalityLigaturesOnSelector", +--~          [ 7] = "inequalityLigaturesOffSelector", +--~          [ 8] = "exponentsOnSelector", +--~          [ 9] = "exponentsOffSelector", +--~     }, +--~     [16] = { +--~         name = "ornamentSetsType", +--~         [ 0] = "noOrnamentsSelector", +--~         [ 1] = "dingbatsSelector   ", +--~         [ 2] = "piCharactersSelector", +--~         [ 3] = "fleuronsSelector   ", +--~         [ 4] = "decorativeBordersSelector", +--~         [ 5] = "internationalSymbolsSelector", +--~         [ 6] = "mathSymbolsSelector", +--~     }, +--~     [17] = { +--~         name = "characterAlternativesType", +--~         [ 0] = "noAlternatesSelector", +--~     }, +--~     [18] = { +--~         name = "designComplexityType", +--~         [ 0] = "designLevel1Selector", +--~         [ 1] = "designLevel2Selector", +--~         [ 2] = "designLevel3Selector", +--~         [ 3] = "designLevel4Selector", +--~         [ 4] = "designLevel5Selector", +--~     }, +--~     [19] = { +--~         name = "styleOptionsType", +--~         [ 0] = "noStyleOptionsSelector", +--~         [ 1] = "displayTextSelector", +--~         [ 2] = "engravedTextSelector", +--~         [ 3] = "illuminatedCapsSelector", +--~         [ 4] = "titlingCapsSelector", +--~         [ 5] = "tallCapsSelector   ", +--~     }, +--~     [20] = { +--~         name = "characterShapeType", +--~         [0 ] = "traditionalCharactersSelector", +--~         [1 ] = "simplifiedCharactersSelector", +--~         [2 ] = "jis1978CharactersSelector", +--~         [3 ] = "jis1983CharactersSelector", +--~         [4 ] = "jis1990CharactersSelector", +--~         [5 ] = "traditionalAltOneSelector", +--~         [6 ] = "traditionalAltTwoSelector", +--~         [7 ] = "traditionalAltThreeSelector", +--~         [8 ] = "traditionalAltFourSelector", +--~         [9 ] = "traditionalAltFiveSelector", +--~         [10] = "expertCharactersSelector", +--~     }, +--~     [21] = { +--~         name = "numberCaseType", +--~         [ 0] = "lowerCaseNumbersSelector", +--~         [ 1] = "upperCaseNumbersSelector", +--~     }, +--~     [22] = { +--~         name = "textSpacingType", +--~         [ 0] = "proportionalTextSelector", +--~         [ 1] = "monospacedTextSelector", +--~         [ 2] = "halfWidthTextSelector", +--~         [ 3] = "normallySpacedTextSelector", +--~     }, +--~     [23] = { +--~         name = "transliterationType", +--~         [ 0] = "noTransliterationSelector", +--~         [ 1] = "hanjaToHangulSelector", +--~         [ 2] = "hiraganaToKatakanaSelector", +--~         [ 3] = "katakanaToHiraganaSelector", +--~         [ 4] = "kanaToRomanizationSelector", +--~         [ 5] = "romanizationToHiraganaSelector", +--~         [ 6] = "romanizationToKatakanaSelector", +--~         [ 7] = "hanjaToHangulAltOneSelector", +--~         [ 8] = "hanjaToHangulAltTwoSelector", +--~         [ 9] = "hanjaToHangulAltThreeSelector", +--~     }, +--~     [24] = { +--~         name = "annotationType", +--~         [ 0] = "noAnnotationSelector", +--~         [ 1] = "boxAnnotationSelector", +--~         [ 2] = "roundedBoxAnnotationSelector", +--~         [ 3] = "circleAnnotationSelector", +--~         [ 4] = "invertedCircleAnnotationSelector", +--~         [ 5] = "parenthesisAnnotationSelector", +--~         [ 6] = "periodAnnotationSelector", +--~         [ 7] = "romanNumeralAnnotationSelector", +--~         [ 8] = "diamondAnnotationSelector", +--~     }, +--~     [25] = { +--~         name = "kanaSpacingType", +--~         [ 0] = "fullWidthKanaSelector", +--~         [ 1] = "proportionalKanaSelector", +--~     }, +--~     [26] = { +--~         name = "ideographicSpacingType", +--~         [ 0] = "fullWidthIdeographsSelector", +--~         [ 1] = "proportionalIdeographsSelector", +--~     }, +--~     [103] = { +--~         name = "cjkRomanSpacingType", +--~         [ 0] = "halfWidthCJKRomanSelector", +--~         [ 1] = "proportionalCJKRomanSelector", +--~         [ 2] = "defaultCJKRomanSelector", +--~         [ 3] = "fullWidthCJKRomanSelector", +--~     }, +--~ } diff --git a/otfl-font-tfm.lua b/otfl-font-tfm.lua index ab8a4db..9210fee 100644 --- a/otfl-font-tfm.lua +++ b/otfl-font-tfm.lua @@ -101,10 +101,8 @@ function tfm.read_from_tfm(specification)              end              tfm.enhance(tfmdata,specification)          end -    else -        if trace_defining then -            logs.report("define font","loading tfm with name %s fails",specification.name) -        end +    elseif trace_defining then +        logs.report("define font","loading tfm with name %s fails",specification.name)      end      return tfmdata  end @@ -226,6 +224,10 @@ end  local charactercache = { } +-- The scaler is only used for otf and afm and virtual fonts. If +-- a virtual font has italic correction make sur eto set the +-- has_italic flag. Some more flags will be added in the future. +  function tfm.do_scale(tfmtable, scaledpoints)      tfm.prepare_base_kerns(tfmtable) -- optimalization      if scaledpoints < 0 then @@ -246,6 +248,7 @@ function tfm.do_scale(tfmtable, scaledpoints)      local hasmath = tfmtable.math_parameters ~= nil or tfmtable.MathConstants ~= nil      local nodemode = tfmtable.mode == "node"      local hasquality = tfmtable.auto_expand or tfmtable.auto_protrude +    local hasitalic = tfmtable.has_italic      --      t.parameters = { }      t.characters = { } @@ -372,9 +375,11 @@ function tfm.do_scale(tfmtable, scaledpoints)              end          end          -- todo: hasitalic -        local vi = description.italic or v.italic -        if vi then -            chr.italic = vi*delta +        if hasitalic then +            local vi = description.italic or v.italic +            if vi and vi ~= 0 then +                chr.italic = vi*delta +            end          end          -- to be tested          if hasmath then @@ -531,10 +536,14 @@ function tfm.do_scale(tfmtable, scaledpoints)      if not tp[22] then tp[22] =   0     end  -- mathaxisheight      if t.MathConstants then t.MathConstants.AccentBaseHeight = nil end -- safeguard      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  --~ collectgarbage("collect") +--~ t.fontname = t.fontname or t.fullname +--~ t.name = t.name or t.fontname +--~ print(t.fullname,table.serialize(characters[string.byte('W')].kerns))      return t, delta  end diff --git a/otfl-font-xtx.lua b/otfl-font-xtx.lua index 5672068..63e421f 100644 --- a/otfl-font-xtx.lua +++ b/otfl-font-xtx.lua @@ -61,17 +61,18 @@ local list = { }  fonts.define.specify.colonized_default_lookup = "file" -local function issome() list.lookup = fonts.define.specify.colonized_default_lookup end -local function isfile() list.lookup = 'file' end -local function isname() list.lookup = 'name' end -local function thename(s) list.name = s end -local function iscrap(s) list.crap = string.lower(s) end -local function istrue(s) list[s] = 'yes' end -local function isfalse(s) list[s] = 'no' end -local function iskey(k,v) list[k] = v  end +local function issome ()    list.lookup = fonts.define.specify.colonized_default_lookup end +local function isfile ()    list.lookup = 'file' end +local function isname ()    list.lookup = 'name' end +local function thename(s)   list.name   = s end +local function issub  (v)   list.sub    = v end +local function iscrap (s)   list.crap   = string.lower(s) end +local function istrue (s)   list[s]     = 'yes' end +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  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) @@ -80,9 +81,10 @@ local truevalue  = lpeg.P("+") * spaces * (sometext/istrue)  local falsevalue = lpeg.P("-") * spaces * (sometext/isfalse)  local keyvalue   = (lpeg.C(sometext) * spaces * lpeg.P("=") * spaces * lpeg.C(sometext))/iskey  local somevalue  = sometext/istrue +local subvalue   = lpeg.P("(") * (lpeg.C(lpeg.P(1-lpeg.S("()"))^1)/issub) * lpeg.P(")") -- for Kim  local option     = spaces * (keyvalue + falsevalue + truevalue + somevalue) * spaces  local options    = lpeg.P(":") * spaces * (lpeg.P(";")^0  * option)^0 -local pattern    = (filename + fontname) * crapspec^0 * options^0 +local pattern    = (filename + fontname) * subvalue^0 * crapspec^0 * options^0  function fonts.define.specify.colonized(specification) -- xetex mode      list = { } @@ -102,6 +104,10 @@ function fonts.define.specify.colonized(specification) -- xetex mode          specification.lookup = list.lookup          list.lookup = nil      end +    if list.sub then +        specification.sub = list.sub +        list.sub = nil +    end      specification.features.normal = list      return specification  end diff --git a/otfl-luat-dum.lua b/otfl-luat-dum.lua index 4d7d9c5..f2ff505 100644 --- a/otfl-luat-dum.lua +++ b/otfl-luat-dum.lua @@ -20,6 +20,7 @@ trackers = {  }  storage = {      register      = dummyfunction, +    shared        = { },  }  logs = {      report        = dummyfunction, @@ -41,12 +42,14 @@ resolvers = resolvers or { } -- no fancy file helpers used  local remapper = {      otf = "opentype fonts",      ttf = "truetype fonts", -    ttc = "truetype fonts" +    ttc = "truetype fonts", +    cid = "other text files", -- will become "cid files"  }  function resolvers.find_file(name,kind)      name = string.gsub(name,"\\","\/") -    return kpse.find_file(name,(kind ~= "" and kind) or "tex") +    kind = string.lower(kind) +    return kpse.find_file(name,(kind and kind ~= "" and (remapper[kind] or kind)) or "tex")  end  function resolvers.findbinfile(name,kind) diff --git a/otfl-node-fnt.lua b/otfl-node-fnt.lua index 52b5a24..3ad9060 100644 --- a/otfl-node-fnt.lua +++ b/otfl-node-fnt.lua @@ -33,6 +33,18 @@ local fontdata = fonts.ids  -- 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) @@ -54,7 +66,7 @@ function nodes.process_characters(head)                      if shared then                          local dynamics = shared.dynamics                          if dynamics then -                            local d = shared.set_dynamics(font,dynamics,attr) +                            local d = shared.set_dynamics(font,dynamics,attr) -- still valid?                              if d then                                  used[attr] = d                                  a = a + 1 @@ -95,7 +107,7 @@ function nodes.process_characters(head)              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) +                    local h, d = processors[i](head,font,0) -- false)                      head, done = h or head, done or d                  end              end @@ -107,7 +119,7 @@ function nodes.process_characters(head)              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) +                    local h, d = processors[i](head,font,0) -- false)                      head, done = h or head, done or d                  end              end diff --git a/otfl-node-ini.lua b/otfl-node-ini.lua index aeeb689..8185e30 100644 --- a/otfl-node-ini.lua +++ b/otfl-node-ini.lua @@ -49,13 +49,15 @@ are only used when no attribute is set at the \TEX\ end which normally  happens in <l n='context'/>.</p>  --ldx]]-- -local last = 127 +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, { }  | 
